Further Options
The previous example describes the general procedure for implementing a service. This section discusses some of the issues you may need to consider to create a production quality server.
Multithreading
The Agent creates threads as necessary to handle incoming requests, and multiple threads may enter a servlet at the same time. Objects supplied as parameters to the overridden virtual methods are guaranteed to be active in only a single thread. However, if the servlet maintains state, it must take appropriate precautions to ensure thread safety. See “Recovering Session State,” in the HydraExpress Servlet Development Guide for details.
A Note on Allocating Objects in Multithreaded Applications
Because services created with HydraExpress run in multiple threads, it is recommended that you allocate objects on the heap rather than the stack, a general “best practice” for multithreaded applications. This prevents problems with thread stack size.
Service Security
To run a secure service, the client must communicate with the service through an HTTPS transport. Any HydraExpress client can use the HTTPS transport supplied with HydraExpress.
To test a secure client against a Web service running in the Agent, just include in the WSDL or client implementation the path to the default port used for security, 8443, such as:
https://localhost:8443/dayofweek/DayofWeek/
For an example of creating a secure service, see
Chapter 4, “Extending Your Web Service.” NOTE >> Using the HTTPS protocol results in a dependence on the OpenSSL third-party library.
Error Reporting and WSDL-Defined Faults
HydraExpress handles server and client exceptions through
rwsf::Exception or one of its derived classes, and SOAP faults through an instance of
rwsf::SoapFaultException or one of its generated derivations if a fault is specified in the WSDL file.
A WSDL file can define faults to be caught in the server and returned to the client. One or more faults may be defined for each operation defined in the WSDL. HydraExpress creates a class for each unique fault message type defined. Several faults can use the same message format, so messages are the critical definition needed by HydraExpress to create a mechanism for returning faults to the client.
If faults are defined in the WSDL, the server-side implementation code can detect problems and report them back to the client by throwing one of the defined fault messages.
NOTE >> This discussion reflects a traditional request-response operation. For a solicit-response operation, faults would be handled on the client and returned to the server.
For a discussion on exceptions for both the client and server, as well as WSDL-defined faults, see “WSDL-Defined Faults,” in the HydraExpress User Guide.
Implementing a Standalone Server
HydraExpress allows you to implement your service as a standalone server, independent from the Agent. To take advantage of this feature, use the -standalone option when generating code in order to generate a sample standalone server.
Server-Side Logging
HydraExpress supports both client-side and server-side logging. Logging is not implemented in the sample server application by default (although it is implemented on the client side).
HydraExpress provides two types of loggers: its primary Agent global logger, and a Web services-specific logger.
For server-side code, use the Agent logger, which is best for logging events from services, connectors, transports, and handlers. This book does not include a detailed discussion on using the Agent logger; rather, please see “Using the Default Logger in a Service,” in the HydraExpress User Guide.
The Web services logger may provide some use while debugging, as it logs some Fatal and Error level messages. See
“Server-side Logging through the Web Services Logger” for more information.
Session Management
The server-side code generated by HydraExpress provides support for session management in Web services. For information on session management in the HydraExpress-generated classes, see
Chapter 18, “Sessions and State.”Using a Different Implementation Name
The name of the sample server implementation generated by HydraExpress is based on the port name defined in the WSDL, with the addition of Imp, as in <portType>Imp. The simplest way to implement the Web service is to use the sample implementation directly, without changing the name of the implementation class or the files.
However, there may be circumstances in which you want to change the name of the class that implements the service.
As an example, let’s suppose you wanted to change the name of the service implementation for the DayofWeek example from DayOfWeekPortTypeImp to MyDayofWeekImp. These are the changes you would need to make:
• Rename the implementation files
DayOfWeekPortTypeImp.h => MyDayofWeekImp.h
DayOfWeekPortTypeImp.cpp => MyDayofWeekImp.cpp
• In the renamed file MyDayofWeekImp.cpp:
— Change the include for the header:
#include MyDayofWeekImp.h
— Change the macro that registers the implementation:
RWSF_DEFINE_MESSAGE_HANDLER(MyDayofWeekImp)
— Change the method definition:
MyDayOfWeekImp::getDayOfWeek(...)
• In the renamed file MyDayofWeekImp.h, you would need to:
— Change the guard at the top of the file:
#ifndef MyDayOfWeekImp_h_
#define MyDayOfWeekImp_h_
— Change the class declaration:
class MyDayOfWeekImp : public DayOfWeekPortTypeBase
• In the makefile, search on the string DayOfWeekPortTypeImp and change it to MyDayOfWeekImp.
This would also be true of the debug makefile makefile_debug and of occurrences of DayOfWeekPortTypeImp in the MSVC project files.
• In the named object configuration file objects.xml, change the naming-class element from DayOfWeekPortService.createDayOfWeekPortTypeImp to DayOfWeekPortService.createMyDayOfWeekImp.
Similar changes would need to be made if your application used notification classes and you wished to change the notification implementation.
In addition, if your application contained generated datatype classes (located in your code generation directory’s codegen\data and include\data directories, you would need to:
• change both the header and implementation file names to the new name
• change any related includes in the renamed file MyDayofWeekImp.cpp
Wrapped Style Operations
HydraExpress recognizes the wrapped document style. This feature allows you to generate an “unwrapped” interface for the proxy and server. Here are the WSDL requirements:
• The input message definition must have a single part.
• The part must be an element. The part name does not matter.
• The element must have the same name as the related operation.
• The element's complex type must have only a name attribute.
• The operation must use a "document" style binding (i.e. not "rpc").
If you generate code using the -wrapped option, and your WSDL meets the above requirements, HydraExpress will “unwrap” the top level element, and treat each of the element’s parts as arguments to the operation.
Both input and output elements are unwrapped, effectively removing the “wrapper” or top-level element from the generated interface.
Developing a WSDL to Support the Wrapped Style
Here is how this style looks in WSDL:
<wsdl:types>
<schema ...>
<element name="prevDay" type="sns:prevDay"/> //1
<complexType name="prevDay">
<sequence>
<element name="Unit" type="xsd:string"/>
<element name="identifier" type="xsd:int"/>
</sequence>
</complexType>
</schema>
</wsdl:types>
...
<wsdl:message name="getBusinessDayRequest">
<wsdl:part name="input" element="sns:prevDay" /> //2
</wsdl:message>
...
<wsdl:portType name="BusinessDayPortType">
<wsdl:operation name="prevDay"> //3
<wsdl:input message="tns:getBusinessDayRequest" />
<wsdl:output message="tns:getBusinessDayResponse" />
</wsdl:operation>
</wsdl:portType>
...
<wsdl:binding name="BusinessDayPortType">
<soap:binding style="document" //4
transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="prevDay">
<wsdl:input message="tns:getBusinessDayRequest" />
<wsdl:output message="tns:getBusinessDayResponse" />
</wsdl:operation>
</wsdl:binding>
Generating Code with the -wrapped Option
You can generate code using the -wrapped option, as follows:
prompt>rwsfgen -wrapped -projectname Wrapped MyWSDL.wsdl
Looking at the Generated Code
The resulting generated service operation method for the prevDay operation would not include the complex type sns::PreviousDay at all, instead using its elements Unit and identifier as parameters:
void BusinessDayPortTypeImp::prevDay(
rwsf::CallInfo& callInfo, const std::string& Unit_in,
int identifier_in)
{ ... }
By comparison, the same WSDL without the -wrapped option results in a generated service operation method that takes an input parameter of type sns::PreviousDay, as follows:
void BusinessDayPortTypeImp::prevDay(rwsf::CallInfo& callInfo,
sns::PrevDay input_in);
Some WSDLs cannot be used with the -wrapped option. If this is the case, the HydraExpress Agent will return an error:
WARNING: WSDL file: C:\RogueWave\HydraExpress\examples\webservices\DayOfWeek\DayO
fWeek.wsdl is NOT eligible for wrapped style.
Turning off Text Escaping to Improve Performance
If you are certain that the data you are sending will not contain any special characters that must be escaped, you may get better performance in your applications by setting the property
RWSF:doEscape to
false in the service’s handler configuration file. (For more customizations to configuration files, see
“Customizing the Service Configuration Files” ).
This property controls whether or not the skeleton escapes content when writing responses. The default is true.
To reset this property on the server side, set the
RWSF:doEscape property to
false in the server-side configuration file
<servicecontextname>_handlers.xml. (For more information on this handlers file, see
“Service Chains Configuration File: handlers.xml” .)
By default the RWSF:doEscape property is "true".
To turn off text escaping, add the RWSF:doEscape property to <servicecontextname>__handlers.xml and set it to “false”. For instance, given the DayofWeek example:
<configuration>
<service name="DayOfWeekPortService">
<request-handlers>
<handler name="http://localhost:8090/dayofweek/DayOfWeekSkeleton">
<property name="RWSF:doEscape" value="false" />
</handler>
</request-handlers>
...
</service>
</configuration>
Accessing the Request URL
The service implementation may access the URL for requests that arrive via HTTP or HTTPS from the
rwsf::CallInfo object.
To access the property RWSF:requestURL:
rwsf::Attribute attr = callInfo.get("RWSF:RequestURL");
std::string temp;
attr >> temp;
std::string requestURL(temp);
Customizing the Service Configuration Files
Among the generated files are a series of XML-based configuration files. Using the configuration files allows you to build a high degree of flexibility into your application. HydraExpress generates these configuration files automatically based on default values in the WSDL, so you don’t have to deal with them unless you wish to customize your application.
The ability to use configuration files to link a transport with a service, or a service with a binding, effectively decouples these objects in your application. This allows you to change how your service works without changing your binding, or to use a new service with the same binding, or to change any number of other elements in your application without having to regenerate code or recompile.
The primary configuration files on the server side are
• the transports configuration file: transports.xml
• the servlet configuration file: servicecontextname_web.xml
• the service chains configuration file: servicecontextname_handlers.xml
• the named objects configuration file: servicecontextname_objects.xml
Transport Configuration File: transports.xml
The transports.xml file includes all available transports for your service. This file is not generated, but rather copied from the template files in the <installdir>\conf\webservice directory each time the code generator is invoked. Use this file to configure additional transports that you have included in your application, or to customize existing transports.
Servlet Configuration File: web.xml
The <servicecontextname>_web.xml file includes servlet configuration information. This includes
• a definition of the servlet
• the name of the configuration file that defines the particular service (or services) that the servlet uses
• other optional parameters
When you deploy your service, HydraExpress copies all config files, including this <servicecontextname>_web.xml file to the appropriate context directory in your <installdir>\apps\servlets directory.
For more information on this file and defining servlets, see
“About the Servlet Used by the Service.”Following is the contents of dayofweek_web.xml.
<web-apps>
<servlet>
<servlet-name>DayOfWeekPortService</servlet-name> 1
<servlet-class>rwsf_webservice_servlet.createWebServiceServlet
</servlet-class>
<init-param>
<param-name>configFile</param-name> 2
<param-value>handlers.xml</param-value>
</init-param>
<init-param>
<param-name>serviceName</param-name> 3
<param-value>DayOfWeekPortService</param-value>
</init-param>
<init-param>
<param-name>wsdlFileName</param-name> 4
<param-value>DayOfWeek.wsdl</param-value>
</init-param>
<servlet-mapping> 5
<servlet-name>DayOfWeekPortService</servlet-name>
<url-pattern>/DayOfWeek/*</url-pattern>
</servlet-mapping>
</servlet>
...
</web-apps>
The excerpt here shows the default configuration elements contained in the generated <servicecontextname>_web.xml file. Other optional configuration elements may be added to define session timeout values and to configure error pages.
For more information on setting a timeout value for your session, see
“Configuring Session Timeouts.” For more information, on error pages, see
“Configure Error Pages,” in the HydraExpress Servlet Development Guide.
Service Chains Configuration File: handlers.xml
The configuration file
<servicecontextname>_handlers.xml is generated as part of the server side components. It chains together the handlers for this service and contains initialization parameters. For more information on handlers, see
Chapter 14, “SOAP Message Handlers.” Following is an excerpt from dayofweek_handlers.xml:
<configuration>
<service name='DayOfWeekPortService'> 1
<request-handlers> 2
<handler name='http://localhost:8090/dayofweek/DayOfWeekSkeleton'/>
</request-handlers>
<transport-handlers/>
<service-endpoint name='http://localhost:8090/dayofweek/DayOfWeek'/> 3
<response-handlers/>
<fault-handlers/>
</service>
</configuration>
NOTE >> The element transport-handlers should not be confused with the transport itself. An optional transport handler might add message encryption, compression, or special encoding. A transport handler manipulates the request before passing it to the request handlers, the response after any response handlers, and just before it is sent by the transport.
Named Objects Configuration File: objects.xml
A named object is a unit of compiled code with a name that allows it to be found and used by any service within a given service context. The configuration file for defining named objects is <servicecontextname>_objects.xml.
HydraExpress uses this mechanism for service execution. You can also use it to load and use objects that extend your services in a limitless variety of ways. The code can be a small, self-contained bit of functionality, or it might be an entry point to a large back end application, or anything in between.
For more information on named objects, see
Chapter 16, “Named Objects.”