Developing and Running the Example
Service Description
The client created in this example uses the WSDL provided in the file DayOfWeek.wsdl located in the examples\webservices\DayOfWeek directory of your HydraExpress distribution. The WSDL file defines a single operation, GetDayofWeek, located at a port named DayOfWeekPortType. Since this example focuses on the various options available to a client rather than designing an implementation, the service is deliberately simple. The operation receives a message containing an XML Schema date part. The operation returns a message containing a string that holds the day of the week on the date provided.
Invoking the Generator
Make sure that you have set up your environment as described in Chapter 2, “Setup,” in the HydraExpress User Guide.
Open a command prompt and change to the examples\webservices\DayOfWeek directory under the RWSF_HOME directory, as shown below:
Windows | cd %RWSF_HOME%\examples\webservices\DayOfWeek |
UNIX/Linux | cd $RWSF_HOME/examples/webservices/DayOfWeek |
In addition to the DayofWeek WSDL and the provided implementation files, this directory contains a HydraExpress project file,
example-project.xml. This file provides custom configuration information to the generator. (For more information on the HydraExpress project file, see
Chapter 21, “The Project File and Directory Structure.”If you open this file, you’ll note that it identifies a value for the project-name attribute and a files element that references the DayofWeek.wsdl, so there is no need to include these items on the command line if this file is provided to the generator.
Run rwsfgen with example-project.xml as the sole argument, as follows:
prompt> rwsfgen example-project.xml
The above invocation is exactly the same as the following:
prompt> rwsfgen -projectname DayOfWeekExample -whitespace DayofWeek.wsdl
NOTE >> The two required options above are -projectname and the name of the file to parse. The project name is required, and may be entered directly into a HydraExpress project file or on the command line. Note that the name may not include spaces, as HydraExpress supports only file paths without spaces.
Since this chapter is primarily interested in creating a client to access the service, we could also choose to generate only a client, using an additional argument -noserver as follows:
prompt> rwsfgen -noserver example-project.xml
Since we will be using this example to also discuss server-side options in
Chapter 8 , we’ll build both a client and server.
For full information on the various code generation options, see
“Generator Options.”Generated Files
HydraExpress generates server and client-side code, sample applications, configuration files, makefiles, MSVC project files, and documentation into a directory DayOfWeekExample, using the options included in the example-project.xml file. (HydraExpress supports only file paths without spaces, so when naming your project, do not include spaces, since HydraExpress uses the project name as a basis for the name of the code generation directory.)
The project files are generated into several subdirectories, according to HydraExpress’ standard code generation directory hierarchy. For more information on the directory structure, see
“The Generated Project Directory.” NOTE >> Files that are overwrite-protected are generated with a “
.sample” extension if a file exists in the code generation directory of the same name. See
“Overwrite Protection.”
Table 4 – Files generated for DayofWeek example
Directory | Files | Description |
DayOfWeekExample/ | DayOfWeekExample.xml | The project file, named according to the project name, defining all project elements (options, configurations, schemas, WSDLs, etc.). See “The Project File” . |
| makefile makefile_debug | Project-level makefiles. Calls all makefiles in subdirectories. Overwrite-protected. |
| makefile.include | Include makefile. Contains all makefile compiler and linker options. Edits to this file cascade down to all makefiles. Overwrite-protected. |
| DayOfWeekExample.sln | MSVC solution file. Generated for Windows platforms. |
| deployDebug.bat deployRelease.bat | Convenience debug and release deployment batch files generated for use with MSVC projects. |
app/ | makefile makefile_debug | Makefiles. Builds contents of app/ directory. Overwrite-protected. |
/client | DayOfWeekPortClient.cpp | Sample client implementation using the client proxy. Overwrite-protected. |
| makefile makefile_debug | Makefiles. Builds contents of app/client directory. Overwrite-protected. |
| DayOfWeekPortClient.vcproj | MSVC project file generated for Windows platforms. |
/server | DayOfWeekPortTypeImp.cpp DayOfWeekPortTypeImp.h | Sample service implementation and header files. Overwrite-protected. |
| makefile makefile_debug | Makefiles. Builds contents of app/server directory. Overwrite-protected. |
| DayOfWeekPortServiceSample.vcproj | MSVC project file generated for Windows platforms. |
codegen/ | makefile makefile_debug | Makefiles. Builds contents of codegen/ directory. Overwrite-protected. |
/client | DayofWeekBindingProxy.cpp | Implementation file for the generated client proxy class. Defines the methods for the operations defined in the WSDL file. |
| makefile makefile_debug | Makefiles. Builds contents of codegen/client directory. Overwrite-protected. |
| DayOfWeekBindingClientLibrary.vcproj | MSVC project file generated for Windows platforms. |
/server | DayOfWeekBindingSkeleton.cpp DayOfWeekPortTypeBase.cpp | Implementation files for the class that handles messaging and the base class for the server-side implementation. |
| makefile makefile_debug | Makefiles. Builds contents of codegen/server directory. Overwrite-protected. |
| DayOfWeekPortService.vcproj | MSVC project file generated for Windows platforms. |
conf/ | transports.xml client-transports.xml | Configuration files for: 1. Server and client transports |
| dayofweek_handlers.xml | 2. Server-side handlers to support handler chaining and configuration |
| client-handlers.xml | 3. Client-side handlers containing default client logger |
| dayofweek_objects.xml | 4. All named objects required by this service. These are registered and created when the Agent is started. |
| dayofweek_web.xml | 5. Service Descriptor XML file for the service |
| makefile makefile_debug | Deployment makefiles. Overwrite-protected. |
docs/ | index.html | The generated documentation. Use index.html as the entry point to all docs contained in the docs subdirectories. |
include/ | | Header files, as follows: |
/DayOfWeekExample | Subdirectory by project name |
| DayOfWeekBindingProxy.h | 1. Client proxy class |
| DayOfWeekBindingSkeleton.h | 2. Class that handles messaging |
| DayOfWeekPortTypeBase.h | 3. Base class for the server-side implementation |
Note that the directories bin and lib are empty at code generation, but will include the .exe and .dll files, or the .lib or .so files after the project build, depending on your platform.
Using the Client Proxy
The proxy provides a set of five methods for each operation specified in the WSDL description. One pair of methods implements synchronous behavior; the remaining three methods implement asynchronous behavior. To send a message to the Web service, construct an instance of the proxy and invoke either the synchronous or asynchronous method(s) that correspond to the operation. The method returns the values defined in the WSDL file for the response message. (
Appendix A describes type mappings for these values.)
The generated sample client implementation uses one of the synchronous methods for all operations, but you can easily change the implementation to create an asynchronous client. The asynchronous
<operation-name>Start() method launches a thread for the operation so that the client can continue other processes while waiting for the server to respond. For more information on the client’s asynchronous features, see
“The Asynchronous Client API.”The generated header file for the client proxy contains the signatures for the generated service operation methods. The names of the methods that implement the operations in the WSDL file match the WSDL’s operation names, with the first letter of the name converted to lower case. Parameter names match the part names in the WSDL file, with an underscore and the direction of the part appended to the name. For example, a part named
tickerSymbol which is only used for input will have the name
tickerSymbol_in, while an
inout part named
targetStruct will have the name
targetStruct_inout. For details on naming conventions, see
Appendix A .
Looking at the Code
The sample below shows the public interface for the client proxy, DayOfWeekBindingProxy.h located in the DayofWeekExample\include\DayofWeekExample directory.
The sample is reformatted slightly to fit on the page, and omits include statements, comments, and private members:
class DayOfWeekBindingProxyImp;
class DAYOFWEEKBINDINGCLIENTLIBRARY_DECLSPEC
DayOfWeekBindingProxy : public rwsf::Client //1
{
public:
static DayOfWeekBindingProxy make(const std::string& location = //2
"http://localhost:8090/dayofweek/DayOfWeek");
static DayOfWeekBindingProxy make(const rwsf::Transport& transport); //3
static DayOfWeekBindingProxy make(DayOfWeekBindingProxyImp *impl); //4
DayOfWeekBindingProxy(); //5
DayOfWeekBindingProxy(const DayOfWeekBindingProxy& proxy);
~DayOfWeekBindingProxy();
DayOfWeekBindingProxy& operator=(const DayOfWeekBindingProxy& proxy); //6
void setTransportProperty(const std::string& property, //7
const std::string& value);
std::string getDayOfWeek(const std::string& date_in); //8
std::string getDayOfWeek(rwsf::CallInfo& callInfo,
const std::string& date_in);
rwsf::AsyncHandle getDayOfWeekStart(const std::string& date_in); //9
rwsf::AsyncHandle getDayOfWeekStart(rwsf::CallInfo& info,
const std::string& date_in);
std::string getDayOfWeekEnd(rwsf::AsyncHandle& handle); //10
Using the Client Proxy
Use the proxy to implement your client application. HydraExpress creates a sample implementation you may use as a framework. This section discusses how to implement the proxy for a synchronous operation. For information on the asynchronous operation, see
“The Asynchronous Client API.”First, we’ll look at the generated class, and then we’ll see how we can easily edit it to implement the getDayofWeek method.
The generated sample implementation below shows the DayOfWeekPortClient.cpp file created by the rwsfgen program and located in the DayOfWeekExample\app\client directory. The sample is not a class, but a source file that includes the proxy header file and a main() function that invokes the proxy’s methods.
#include "DayOfWeekExample/DayOfWeekBindingProxy.h" //1
#include <iostream>
#include <include/webservice/DefaultLogger.h>
#include <include/webservice/HandlerManager.h>
#include <include/webservice/MessageHandler.h>
#include <include/webservice/transport/TransportManager.h>
void invoke_DayOfWeek(DayOfWeekBindingProxy& proxy) //2
{
std::string date_in;
std::string dayOfWeek_ret;
rwsf::CallInfo callInfo;
try {
dayOfWeek_ret = proxy.getDayOfWeek(callInfo, date_in);
} 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[])
{
std::string location; //3
if (argc < 2) {
location = "http://localhost:8090/dayofweek/DayOfWeek";
}
else if (argv[1][0]=='-' && argv[1][1]=='a') {
location = "http://localhost:8013/dayofweek/DayOfWeek";
}
else if (argv[1][0]=='-' && argv[1][1]=='l') {
location = "http://localhost:8090/dayofweek/DayOfWeek";
}
else {
location = argv[1];
}
try {
// initialize config files //4
rwsf::NamingContext::loadGlobal("../conf/client-objects.xml");
rwsf::HandlerManager::loadConfiguration("../conf/client-handlers.xml" );
rwsf::TransportManager::initialize("../conf/client-transports.xml" );
DayOfWeekBindingProxy proxy =
DayOfWeekBindingProxy::make(location); //5
if(!proxy.isValid()) {
std::cerr << "Unable to create proxy. " << "\nExiting" <<
std::endl;
return 1;
}
invoke_getDayOfWeek(proxy); //6
} catch (const rwsf::Exception& x) { //7
std::cerr << "rwsf::Exception thrown: "
<< x.what() << std::endl;
return 1;
} catch(const std::exception& x) {
std::cerr << "std::exception thrown:" << std::endl
<< x.what() << std::endl;
return 1;
} catch(...) {
std::cerr << "Unknown exception thrown" << std::endl;
return 1;
}
return 0;
}
To create a working client, simply implement the invoke_getDayOfWeek method, replacing the generated code with your own.
In this case we will use the implemented client application DayOfWeekPortClient.cpp provided in the directory <installdir>\examples\webservices\DayofWeek.
The code below shows how the shipped file implements the service operation method invoke_getDayofWeek().
void invoke_getDayOfWeek(DayOfWeekBindingProxy& proxy)
{
std::string date_in;
std::cout << "Enter date: " << std::flush;
std::cin >> date_in;
rwsf::DateTime dt(date_in, rwsf::DateTime::setDate);
if (!dt.isValid()) { std::cout << "Error: Invalid date" << std::endl;
return;
}
else {
rwsf::DateTime today(rwsf::DateTime::setCurrentTime);
std::string toBe;
std::string dayOfWeek_ret;
if (date_in < today) {
toBe = " was a ";
} else if (date_in == today) {
toBe = " is a ";
} else {
toBe = " will be a ";
}
rwsf::CallInfo info;
try {
dayOfWeek_ret = proxy.getDayOfWeek(info, date_in);
std::cout << date_in << toBe << dayOfWeek_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;
}
}
}
...
Class
rwsf::DateTime correctly parses many common date formats. The client uses this class to simplify the process of converting input from the console into the ISO8601 format that the schema requires.
Compiling and Deploying the Client
At this point the client is implemented and ready to compile. The service now needs to be implemented; then both can be built and the service can be deployed to the HydraExpress Agent.
Chapter 8 discusses how to implement the service, and
“Compiling the Service” discusses building the client and service, and deploying the service.