Web Service Development Guide : PART III Working with Message Patterns : Chapter 10 Implementing Solicit-Response and Notification Services : Implementing the Service
Implementing the Service
The implementation of this service takes place in three files:
WeatherSummaryExample\app\server\WeatherSummaryImp.cpp: A server-side class containing implementations of the subscribe(), unsubscribe(), and weatherUpdate() service operation methods. The weatherUpdate() operation includes a call to the weatherNotification() operation method in the server-side notification proxy. The subscribe() operation calls the notification proxy as well to initiate the server-side solicit-response operation verifySubscription().
WeatherSummaryExample\app\client\WeatherSummaryClient.cpp: A client-side main() function that contains the calls to the subscribe(), weatherUpdate(), and unsubscribe() service operation methods in the client proxy.
WeatherSummaryExample\app\client\WeatherSummaryNotificationImp.h and WeatherSummaryNotificationImp.cpp: Contain the client-side implementation of the weatherNotification() service operation method, and the client-side response to the verifySubscription() server request.
The WeatherSummary example ships with implemented versions of these files, located in the main example directory <installdir>\examples\webservices\WeatherSummary, along with the WeatherSummary.wsdl. The discussions that follow are based on these provided implementations.
The Request-Response Operation
The code below is an excerpt from WeatherSummaryImp.cpp. It shows the message handler registration macro and the endpoint implementation for the request-response operation method subscribe().
 
RWSF_DEFINE_MESSAGE_HANDLER(WeatherSummaryImp)
 
void
WeatherSummaryImp::subscribe(rwsf::CallInfo& callInfo,
const std::string& host_in, const std::string& port_in,
const std::string& transportName_in,
bool& status_out, std::string& message_out) //1
{
std::string location = createLocation(transportName_in,
host_in, port_in); //2
 
WeatherSummaryNotificationProxy notifProxy =
WeatherSummaryNotificationProxy::make(location); //3
bool result = notifProxy.verifySubscription(); //4
 
if (result) { //5
subscriptions_.insert(subscriptions_.end(), location);
message_out = "OK";
}
else {
message_out = "Unable to verify callback server.";
}
status_out = result;
}
//1 The call to the subscribe() operation method. The CallInfo object contains data related to message handling and configuration properties. The next three parameters are passed from the client request, and the final two are to hold data sent in the response.
//2 Creates a location based on the input parameters. The createLocation() method is also defined in this file.
//3 Obtains an instance of the notification proxy, which is the client-like proxy that allows the server to initiate requests.
//4 Calls the verifySubscription() solicit-response operation method, which verifies that the location created above is real and reachable.
//5 The remaining lines of code use the result of the verifySubscription() call to set the status and message return data.
This file also defines the unsubscribe() operation method, which is very similar to above except for the logic that determines the response data. See the WeatherSummaryImp.cpp file in the example if you are interested in the specifics.
The Solicit-Response and Notification Operations
One extra class is generated on the server side to support the solicit-response and notification patterns. The class WeatherSummaryNotificationProxy is a generated proxy used to send a message to the client.
The Notification Proxy
The class WeatherSummaryNotificationProxy is very similar to the generated proxy on the client side, containing both asynchronous and synchronous service operation methods that are used by the server (see “Implementing the Call to the Notification Endpoint” and “The Solicit-Response Operation Call”.
Here is a brief excerpt of the proxy’s API:
 
class WeatherSummaryNotificationProxy : public rwsf::Client {
public:
static WeatherSummaryNotificationProxy make(const std::string&
location = "http://localhost:8090/weather/WeatherSummary"); //1
static WeatherSummaryNotificationProxy
make(const rwsf::Transport& transport); //2
...
 
void weatherNotification(const wsx::WeatherSummary& weatherData_in); //3
void weatherNotification(rwsf::CallInfo& callInfo,
const wsx::WeatherSummary& weatherData_in);
rwsf::AsyncHandle weatherNotificationStart(
const wsx::WeatherSummary& weatherData_in);
rwsf::AsyncHandle weatherNotificationStart(rwsf::CallInfo& info,
const wsx::WeatherSummary& weatherData_in);
void weatherNotificationEnd(rwsf::AsyncHandle& handle);
 
bool verifySubscription();
bool verifySubscription(rwsf::CallInfo& callInfo);
rwsf::AsyncHandle verifySubscriptionStart();
rwsf::AsyncHandle verifySubscriptionStart(rwsf::CallInfo& info);
bool verifySubscriptionEnd(rwsf::AsyncHandle& handle);
...
}
//1 Static make() method for obtaining a proxy instance based on a location. This was used in the server implementation described above:
WeatherSummaryNotificationProxy notifProxy =
WeatherSummaryNotificationProxy::make(location);
//2 Static make method that takes an rwsf::Transport object.
//3 Synchronous and asynchronous versions of the two operation methods initiated on the server. The asynchronous methods allow the client to continue execution after making one of these calls, without having to wait on the transport-level reply inherent in synchronous transports such as HTTP and HTTPS
Implementing the Call to the Notification Endpoint
Let’s first look at an excerpt from WeatherSummaryImp.cpp showing the implementation for the one-way operation method weatherUpdate(). This implementation does not really do anything with the weather update, but uses the message’s arrival as the event that triggers a call to the notification operation method weatherNotification() in the specially-generated class WeatherSummaryNotificationProxy. In a more complete implementation, the data would probably be persisted in some way, but here the only point is to demonstrate how to implement a notification.
 
void WeatherSummaryImp::weatherUpdate(rwsf::CallInfo& callInfo,
const wsx::WeatherSummary& weatherData_in) //1
{
std::list<std::string>::iterator iter = subscriptions_.begin(); //2
for (; iter != subscriptions_.end(); ++iter) {
WeatherSummaryNotificationProxy notifProxy =
WeatherSummaryNotificationProxy::make(*iter); //3
notifProxy.weatherNotification(weatherData_in); //4
}
}
//1 Represents the end point implementation for the weatherUpdate() one-way message from the client. Since the request is one-way, no necessary response is expected. But in this case, this message serves as the trigger for a notification message back to the client.
//2 Creates an iterator for cycling through the locations registered with the server to receive notifications when a weather update is received. In our simple example, the only location registered is the same client that sent the weather update.
//3 For each registered client, obtains a notification proxy.
//4 Sends a notification to the client based on the input data from weatherUpdate().
The Solicit-Response Operation Call
The call to the solicit-response endpoint is covered above in “The Request-Response Operation” because it occurs in the middle of the Request-Response implementation. It also depends on the notification proxy.