Web Service Development Guide : PART I Getting Started : Chapter 3 Creating a Web Service : The Generated Application Samples
The Generated Application Samples
By default, HydraExpress produces sample client and service implementations. For the operation sayHello located at portType GreetingPortType, its code generator produces:
a sample client implementation GreetingPortClient located in the directory HelloWorldExample\app\client. This implementation uses the generated proxy, GreetingBindingProxy located HelloWorldExample/codegen/client.
a sample service implementation GreetingPortTypeImp located in directory HelloWorldExample\app\server.
NOTE >> The files in the project\app directory are meant to be edited and used to implement your client and service. The files in the project\codegen directory provide background functionality and should not be edited.
To implement the client and server, you can implement the methods in these generated sample implementations, or create your own implementations. In most cases, modifying the sample implementation is the simplest approach.
For this example, we will use the provided implementations, which are located directly in the HelloWorld directory, as follows:
 
<installdir>
examples/
HelloWorld/
GreetingPortClient.cpp //provided client implementation
GreetingPortTypeImp.cpp //provided server implementation
The following sections explain how to use the client and server implementations.
The Client Proxy
Class GreetingBindingProxy is the generated client proxy for the HelloWorld service. It provides five methods for each operation specified in the WSDL file. One pair of methods implements synchronous behavior, and the remaining three methods implement asynchronous behavior.
Excerpt from the client proxy for the HelloWorld service, GreetingBindingProxy.h, located in the generated HelloWorldExample\include\HelloWorldExample directory:
 
std::string sayHello(const std::string& hellorequest_in); //1
std::string sayHello(rwsf::CallInfo& callInfo, const std::string& //2
hellorequest_in);
rwsf::AsyncHandle sayHelloStart(const std::string& hellorequest_in); //3
rwsf::AsyncHandle sayHelloStart(rwsf::CallInfo& info, //4
const std::string& hellorequest_in);
std::string sayHelloEnd(rwsf::AsyncHandle& handle); //5
//1 Declares the first of the two synchronous sayHello() methods. Takes a standard string as the hello request. Returns a string in response.
//2 Declares the second synchronous sayHello() method, which takes a standard string as the hello request, and a string as source data. This method also explicitly passes a rwsf::CallInfo object. Use this method if you need to add your own SOAP or transport headers to the message, or if you want to add some additional message handlers for the outgoing message.
//3 Defines the first of the two asynchronous sayHello() methods. These methods return a handle to an object that can be used to check on whether the operation has completed, and to retrieve the data if it has.
//4 Defines the second asynchronous sayHello() method. Differs from the first asynchronous method only in that it explicitly passes a rwsf::CallInfo object, which plays the same role as it does in the corresponding synchronous method.
//5 Declares the end method for an asynchronous process, which is used in retrieving the data.
To send a message to the Web service, we must construct an instance of the proxy and invoke either the synchronous or asynchronous method(s) that correspond to the WSDL operation. The method returns the values defined in the WSDL file for the response message.
Using the Client Proxy and the Client Implementation
We use the client proxy to implement the HelloWorld client application. The generated sample implementations by default use one of the proxy’s synchronous methods, as shown here:
 
void invoke_sayHello(GreetingBindingProxy& proxy)
This section discusses implementing the client for a synchronous operation. For information on asynchronous operations, see Chapter 13, “Asynchronous Messaging.”
The following code shows the provided client implementation file, <installdir>\examples\HelloWorld\GreetingPortClient.cpp. The client implementation is not a class, but rather a source file that includes the proxy header file and a main() function that invokes the proxy’s methods. The code below is reformatted slightly to fit on the page:
#include "HelloWorldExample/GreetingBindingProxy.h" //1
#include <iostream>
 
#include <rwsf/webservice/DefaultLogger.h>
#include <rwsf/webservice/HandlerManager.h>
#include <rwsf/webservice/MessageHandler.h>
#include <rwsf/webservice/transport/TransportManager.h>
 
void invoke_sayHello(GreetingBindingProxy& proxy) //2
{
std::string hellorequest_in("World!");
std::string return_ret;
rwsf::CallInfo callInfo;
 
try {
return_ret = proxy.sayHello(callInfo, hellorequest_in);
std::cout << "Server Response: " << return_ret << std::endl;
} catch(const rwsf::SoapFaultException& e) {
std::cout << "Fault Code: " << e.getFault().getFaultcode().asString()
<< std::endl;
std::cout << "Fault String: " << e.getFault().getFaultstring()
<< std::endl;
}
}
 
void logError(std::string error, std::string detail) {
rwsf::HandlerManager::invokeLogger(error + ": " + detail,
rwsf::CallInfo::Error);
}
 
using rwsf::DefaultLogger;
RWSF_DEFINE_STATIC_MESSAGE_HANDLER("RWSFClientLogger", DefaultLogger)
 
int main(int argc, char* argv[])
{
// Instantiate GreetingBindingProxy.
// If you need to override the URL given in the WSDL file for
// the service, modify the constructor argument or pass in on
// the command line
 
std::string location; //3
 
if (argc < 2) {
location = "http://localhost:8090/helloworld/HelloWorld";
}
else if (argv[1][0]=='-' && argv[1][1]=='a') {
location = "http://localhost:8013/helloworld/HelloWorld";
}
else if (argv[1][0]=='-' && argv[1][1]=='l') {
location = "http://localhost:8090/helloworld/HelloWorld";
}
else {
location = argv[1];
}
 
try {
// initialize config files
try {
// default path from the bin directory
rwsf::NamingContext::loadGlobal("../conf/client-objects.xml");
rwsf::HandlerManager::loadConfiguration("../conf/client-handlers.xml");
rwsf::TransportManager::initialize("../conf/client-transports.xml"); //4
}
catch(...) {
// default path from the app/client vcproj file
rwsf::NamingContext::loadGlobal("../../conf/client-objects.xml");
rwsf::HandlerManager::loadConfiguration("../../conf/client-handlers.xml");
rwsf::TransportManager::initialize("../../conf/client-transports.xml");
}
 
GreetingBindingProxy proxy = GreetingBindingProxy::make(location); //5
 
if(!proxy.isValid()) {
std::cerr << "Unable to create proxy. " << "\nExiting" << std::endl;
return 1;
}
 
invoke_sayHello(proxy); //6
 
}
catch (const rwsf::Exception& x) { //7
logError("rwsf::Exception thrown", x.what());
std::cerr << "rwsf::Exception thrown: "
<< x.what() << std::endl;
return 1;
}
catch(const std::exception& x) {
logError("std::exception thrown", x.what());
std::cerr << "std::exception thrown:" << std::endl
<< x.what() << std::endl;
return 1;
}
catch(...) {
logError("Unknown exception thrown", "");
std::cerr << "Unknown exception thrown" << std::endl;
return 1;
}
return 0;
}
//1 Include necessary header files.
//2 Function that invokes the sayHello() operation. The function takes a reference to a GreetingBindingProxy, creates a standard string “World!” and an empty standard string instance, and calls the sayHello operation on the proxy.
The client implements one sample invocation method that takes an explicit rwsf::CallInfo parameter. The program provides a try block around the code that calls methods on the proxy. The proxy indicates errors by throwing a rwsf::SoapFaultException derived from rwsf::SoapFault, and the server writes a log message by default. Note that the generator makes no attempt to provide valid input for the operation.
//3 The main() function first determines the location for the service through a combination of information from the WSDL and possible command line options and arguments.
If no command line argument is used when invoking the client, the default is the location specified in the WSDL.
//4 Registers the service handlers and transports that are available for this message.
//5 Obtains a client proxy and ensures that it is valid.
//6 Calls the invoke_sayHello() method on the proxy.
//7 Catch blocks for exceptions that might be thrown by this call. The exceptions shown should always be caught. If you generate code with the ‑SourcePro option, which uses Rogue Wave SourcePro C++ datatypes, then you should also catch exceptions derived from RWxmsg.
The sayHello operation requires a string as input (“World!”) and returns a message containing an string with the value “Hello World!”
The next step is to develop the service implementation. Then we’ll compile and run the application.
The Service Implementation
The GreetingPortType service operations are implemented by the service implementation class GreetingPortTypeImp.
To implement the server, you may either implement the methods of this class or derive your own class from GreetingPortTypeBase. In this example, we will use the provided implementation GreetingPortTypeImp located at <installdir>\examples\HelloWorld.
 
#include <rwsf/webservice/Fault.h> //1
#include <rwsf/core/NamedObject.h>
 
#include "GreetingPortTypeImp.h"
 
RWSF_DEFINE_MESSAGE_HANDLER(GreetingPortTypeImp) //2
 
std::string
GreetingPortTypeImp::sayHello(rwsf::CallInfo& callInfo,
const std::string& hellorequest_in)
{
return std::string("Hello " + hellorequest_in); //3
}
//1 Include headers.
//2 This macro registers your service, requiring only the default name for the implementation class as an argument.
//3 Implements the service operation method sayHello() by returning a string “Hello.”
The section “Compiling and Running the Application” explains how to compile and run the example program.