Link to home
Start Free TrialLog in
Avatar of Leo Eikelman
Leo Eikelman

asked on

SOAP calls to Java Web Service

I have a VB client that uses SOAP to call methods in the java web service.  The code for the VB client looks like this:

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Call a webservice's method
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Set objXML = CreateObject("MSXML2.DOMDocument")
    Set objSearchResult = CreateObject("MSXML2.XMLHTTP")
       
    strSearchKey = "<?xml version=""1.0"" encoding=""utf-8""?>" & _
                "<soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance""" & _
                " xmlns:xsd=""http://www.w3.org/2001/XMLSchema""" & _
                " xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"">" & _
                "<soap:Body>" & _
                "<getUserAttributes xmlns=""someuri"">"
 
    strSearchKey = strSearchKey & _
                  "<searchType1>" & "samAccountName" & "</searchType1>" & _
                  "<searchValues1>" & userName & "</searchValues1>" & _
                  "<filterOperator1>" & "1" & "</filterOperator1>" & _
                  "<searchType2>" & "" & "</searchType2>" & _
                  "<searchValues2>" & "" & "</searchValues2>" & _
                  "<filterOperator2>" & "1" & "</filterOperator2>" & _
                  "<attributeNames>" & "mail" & "</attributeNames>" & _
                  "<sortByAttribute>" & "" & "</sortByAttribute>" & _
                  "<sortOrder>" & "1" & "</sortOrder>" & _
                  "</getUserAttributes></soap:Body></soap:Envelope>"
 
    strHTTP = "someurl"
 
    strHeader = "/getUserAttributes"
 
    objSearchResult.Open "POST", strHTTP, False
    objSearchResult.setRequestHeader "SOAPAction", strHeader
    objSearchResult.setRequestHeader "Content-Type", "text/xml"
    objSearchResult.Send strSearchKey
   
    objXML.loadXML (objSearchResult.responseXML.xml)
 
    objXML.loadXML (objXML.selectSingleNode("/SOAP-ENV:Envelope/SOAP-ENV:Body/ns:getUserAttributesResponse/ns:getUserAttributesResult").Text)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


How can I recreate this in C++?  Is there some way of doing this without downloading other components (ex. MSSoap toolkit or EasySoap++)?

If anyone can direct me to some documentation or coding examples that would be a help.

Leo
Avatar of Infinity08
Infinity08
Flag of Belgium image

Create the same SOAP request (<soap:Envelope ... </soap:Envelope>), and use a HTTP library (libcurl eg.) to send it to the Java web service using the POST method. Wait for the reply, and process the reply ...

So, yes, you can easily do that ... although I did add the libcurl library for your ease of use. If you don't want to use an extra library, you can of course use sockets (eg. winsock for Windows), to open a connection to the web server, send a HTTP POST request with the SOAP request in the body over that connection, and parse the received reply.
Here's a nice winsock tutorial (look in the client section) :

http://johnnie.jerrata.com/winsocktutorial/

Here's libcurl :

http://curl.haxx.se/
btw, do you know how to program in C++ ?
Avatar of Leo Eikelman
Leo Eikelman

ASKER

Hey,

just got back from a meeting.

I have done a few C++ applications about 2 years ago, so I am just getting back into C++.

I will look into the links you provided when I get some time here and let you know if I have any questions.

Thanks,

Leo
hmmm... I'm not really sure how to use libcurl with SOAP calls.

the link for http://johnnie.jerrata.com/winsocktutorial/ didn't seem to have any references to SOAP calls at all.

Is there any code examples you can provide?


Leo
SOAP is a protocol that is used over HTTP. HTTP is the transfer protocol used to send the SOAP payload to the web server.

The SOAP payload is in your case :

   char *soap_req = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" \
                              "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" \
                              " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"" \
                              " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" \
                              "<soap:Body>" \
                              "<getUserAttributes xmlns=\"someuri\">" \
                              "<searchType1>samAccountName</searchType1>" \
                              "<searchValues1>userName</searchValues1>" \
                              "<filterOperator1>1</filterOperator1>" \
                              "<searchType2></searchType2>" \
                              "<searchValues2></searchValues2>" \
                              "<filterOperator2>1</filterOperator2>" \
                              "<attributeNames>mail</attributeNames>" \
                              "<sortByAttribute></sortByAttribute>" \
                              "<sortOrder>1</sortOrder>" \
                              "</getUserAttributes></soap:Body></soap:Envelope>";

Filling in the correct values of course !!

The HTTP protocol prescribes a command followed by a few headers, followed by a blank line, followed by the payload. So, in this case you'd get :

    char *http_headers = "POST /uri HTTP/1.1\r\n" \
                                    "Host: www.url.com\r\n" \
                                    "SOAPAction: http://www.url.com/soapaction\r\n" \
                                    "Content-Type: text/xml\r\n" \
                                    "Content-Length: 100\r\n" \
                                    "\r\n";

Of course using the correct URI, hostname, SOAP action and content length.
If you use libcurl, then you don't need to do this manually of course :)

For SOAP reference, check this page :

http://www.w3schools.com/soap/default.asp
@Infinity08

... I know how SOAP works.  I created the VB SOAP calls in the initial questions.

My question is what do I use in C++ to call the web service using this SOAP?

I have looked at examples of MS Soap Toolkit but can't seem to get it to work properly.

Leo
The two options I gave are :

1) do-it-yourself using socket programming ... ie. use the example code from the socket tutorial I gave earlier to
      a) make a connection with the web server
      b) send the HTTP request with SOAP body (ie. HTTP headers followed by SOAP body as i gave in my previous post)
      c) receive the reply
      d) close the connection
   the reply is the reply to the SOAP request (preceded by some HTTP headers) ... you'll have to parse that reply the way you want

2) use a HTTP library (like libcurl) to do all the lower level HTTP stuff for you, so you can focus on SOAP. Use the examples you can find on their site to guide you.

Of course there are also SOAP libraries around, but I was under the impression that you didn't want to use those (from your first post : "without downloading other components (ex. MSSoap toolkit or EasySoap++)"). If you change your mind, personally I find gsoap not bad :

http://gsoap2.sourceforge.net/

On this same site you'll find examples and other help in doing what you want ...
@infinity08

I have been trying to use MS SOAP Toolkit 2.0 to call my Java web service but I can't seem to get it right...

Do you know of any examples on using MS Soap toolkit 2.0?

Leo
ASKER CERTIFIED SOLUTION
Avatar of Infinity08
Infinity08
Flag of Belgium image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
unfortunately this is written in VB, but I'll look around microsoft's website.

Thanks,

Leo
>> unfortunately this is written in VB
I was indeed a bit too fast ... but I imagine that the C++ API is similar to the VB API.

This should be better for C++ :

http://www.codeguru.com/cpp/com-tech/complus/soap/article.php/c3945/

:)
Yeah I've tried that one but I still can't seem to get it to work.

Most of the articles I looked at deal with RPC web services because the line at the end is

Reader->RPCResult->text

Mine is a document style web service so I am not sure what code I should be using to call it.

Leo
SOAP is intended to do RPCs (remote procedure call), so I'm not sure what you're saying ? Did you just want to retrieve a document ? If so, just drop SOAP, and stick with HTTP !
I mean my web service WSDL file defines the each method as a document style.  I used SOAP to call these methods from VB so there should be no problem using SOAP.  What I mean by document style is this:  (This is from the WSDL file of the web service)

<<<<<<<<<<<<<<<SNIP>>>>>>>>>>>>>>>
....................
- <operation name="getApplicationInfo">
  <soap:operation soapAction="someNameSpace/getApplicationInfo" style="document" />
- <input>
  <soap:body use="literal" />
  </input>
- <output>
  <soap:body use="literal" />
  </output>
  </operation>
.........................
<<<<<<<<<<<<<<<SNIP>>>>>>>>>>>>>>>

Leo
That's just the description of the web service (WSDL = Web Service Definition Language).

You call the SOAP action someNameSpace/getApplicationInfo with some input and the result is some output.

How do you call the web service in the code ?
This is the entire code I am using:

#include <atlbase.h>
#include <iostream>

// Replace with the path of SOAP DLLs
// Exclude was added to remove the automatic exclusions
#import "MSXML.dll" named_guids, raw_interfaces_only
#import "C:\\Program Files\\Common Files\\MSSoap\\Binaries\\MSSOAP1.dll" named_guids, no_namespace, raw_interfaces_only exclude("IStream","ISequentialStream","_LARGE_INTEGER","_ULARGE_INTEGER","tagSTATSTG","_FILETIME")

void Add()
{
ISoapSerializerPtr Serializer;
ISoapReaderPtr Reader;
ISoapConnectorPtr Connector;
IStream *inputstream;
IStream *outputstream;

_bstr_t endpoint = L"EndPointURL";
_bstr_t action = L"SoapAction";
_variant_t vEndPoint = "http://someurl/somejws.jws/WSDL";
_variant_t vAction = "getApplicationInfo";

_bstr_t method = L"getApplicationInfo";
_bstr_t command = L"getApplicationInfo";
_bstr_t m = L"m";
_bstr_t a = L"strAppName";
_bstr_t val1 = L"*";

USES_CONVERSION;

try
{
// Create the Connector
Connector.CreateInstance(__uuidof(HttpConnector));

// Connect to the web service
Connector->put_Property(endpoint,vEndPoint);
Connector->put_Property(action,vAction);

// Begin the message to the server
Connector->BeginMessage();

// Create the SoapSerializer
Serializer.CreateInstance(__uuidof(SoapSerializer));

// Connect the serializer to the input stream of the connector
Connector->get_InputStream(&inputstream);
_variant_t stream = inputstream;
Serializer->Init(stream);

// Build the XML message manually
Serializer->startEnvelope(NULL,NULL,NULL);
Serializer->startBody(NULL);
Serializer->startElement(method,command,NULL,m);
Serializer->startElement(a,NULL,NULL,NULL);
Serializer->writeString(val1);
Serializer->endElement();
Serializer->endElement();
Serializer->endBody();
Serializer->endEnvelope();

// Send the message to the web service
Connector->EndMessage();

// Create the SoapReader
Reader.CreateInstance(__uuidof(SoapReader));

// Connect the reader to the output stream of the connector
Connector->get_OutputStream(&outputstream);
_variant_t outstream = outputstream;
VARIANT_BOOL bres;
Reader->Load(outstream, _bstr_t(L""), &bres);

// Get the results from the server and print it
MSXML::IXMLDOMElementPtr element;
Reader->get_RPCResult((IXMLDOMElement **)&element);
BSTR buff;
element->get_text(&buff);
std::cout << W2A(buff) << std::endl;

}
catch(...)
{
std::cout << "Something wrong happened !" << std::endl<< std::endl;
}
}

int main()
{
CoInitialize(NULL);
Add();
CoUninitialize();

return 0;
}



I wasn't exactly sure what the 'm' in this line

Serializer->startElement(method,command,NULL,m);

was supposed to be for so I just left it as what it was when I got the code example of the internet.

When I run this code I get the "Something wrong happened !" printed out and I am not sure how to debug to see what actually happened that caused an error.

Thanks,

Leo
First of all, you can narrow it down by using smaller try-catch blocks, as well as by printing out intermediary results. Try to find where exactly the error occurs this way, and what happens. Then you can fix the problem ... debugging often takes longer than the actual writing of the code :)
I get an error on this line:

>>element->get_text(&buff);


Any idea why this might be happening?


Leo
After this :

    Reader->get_RPCResult((IXMLDOMElement **)&element);

check that element now contains a valid MSXML::IXMLDOMElementPtr (ie. isn't null). If get_RPCResult() didn't complete successfully (couldn't receive from the web service), then it might be that nothing was filled in

    BSTR buff;
    element->get_text(&buff);

What's the prototype of the get_text() method ? Is it something like :

    get_text(BSTR * b)

??
ok I checked my program and I noticed I was usign the wrong URL.  now the program does not crash but I am receiving an error from WebLogic.  

This line:

std::cout << W2A(buff) << std::endl;

prints out

fc:JWSError

I am not sure how to actually get the value of the error...


Do you see any syntax problems with my code?

Leo
the signature for get_text is:

HRESULT get_text(BSTR *text)


Leo
That's an error on the (Java) web server side.

I don't know the MS Soap toolkit as I said before, so I can't tell you if there's a way to get more info on the error (there probably is).

You could also check the server logs (if there are any) to see where the problem lies.

Third option is to use a packet sniffer (like ethereal) to see what the message was ...