Friday, August 26, 2011

WsUtil Compiler tool

WsUtil Compiler tool

The Windows Windows Web Services compiler tool, WsUtil.exe, supports the service model and serialization of data types. It processes WSDL, XML schema and policy documents, and generates C headers and source files. This tool is similar to WSDL compiler tool for managed code but is aimed at native code instead.
To support the service model, WsUtil.exe generates headers to be used for both client and service. It generates C proxy file for the client side, and C stub files for the service side, as needed.
To support serialization, the compiler generates headers for element descriptions for global element definitions, and all the type definition information in the proxy files that is consumed by the serialization engine.
For command line options for processing WSDL files, XML Schema files, and web service policy files, see the following topics:

Security

When you use WsUtil, be aware of the following issues and observe the appropriate precautions:
  • Wsutil does not retrieve XML metadata over the network, and wsutil does not resolve import and/or include statements in the input metadata files. Wsutil opens and reads wsdl, xsd, and policy files. XML metadata is not tamper resistant. Ensure that you only use wsdl, xsd and policy files are acquired from trusted source and make sure to protect the files from tampering before and after using them. Carefully review the contents of the input files and validate that the contents of files are safe for use in the application. Wsutil.exe does not do any verification of authenticity of the metadata files.
  • Wsutil generates header and stub files, which are not tamper resistant. You need to set the correct level access rights on source files generated by wsutil.exe to prevent unauthoritized access to those files. Wsutil uses System.IO.StreamWriter to create the output files.
  • Users need to be aware that Wsutil can overwrite their local files, and they should be careful to specify safe file names and directories for output files using the /out switch.
  • Wsutil or wsutilhelper.dll loaded in wsutil.exe, may terminate unexpectedly or consume large amount of system resources when under attack or in processing a very large amount of input metadata. The tool is designed to be used during development time only This tool should be used as a development time tool only. It may not be safe for use in the middle tier to process policy information.
  • Wsutilhelper.dll helper DLL is loaded into managed wsutil.exe to process policy information. User should make sure no malicious binary with same filename exists in the binary path. Similarly, user should make sure in the build environment, the binary path is setup correctly that there is no malicious binary with same "wsutil.exe" name exists.
  • Wsutil generates SAL annotation for operations and structure fields when possible. User of wsutil generated files should follow the requirement specified through SAL annotation.

Service Model Layer Overview

he WWSAPI Service Model API models the communication between a client and a service as method calls, rather than as data messages. In contrast to the channel layer, which supports more traditional message exchanges between client and service, the Service Model automatically manages communication by means of a service proxy on the client and a service host on the service. This means that the client calls generated functions and the server implements callbacks.
For example, consider a calculator service which performs addition and subtraction on two numbers. Addition and subtraction are operations naturally represented as method calls.
Dd430451.ServiceModelIntro(en-us,VS.85).png The service model represents the communication between client and the service as declared method calls, and so conceals the communication details of the underlying channel layer from the application, making the service easier to implement.

Specifying a Service

A service must be specified in terms of its message exchange patterns as well as its network data representation. For services, this specification is usually provided as WSDL and XML schema documents.
The WSDL document is an XML document which contains the channel binding and the message exchange patterns of the service, whereas the XML schema document is an XML document that defines the data representation of the individual messages.
For the calculator service and its addition and subtraction operations, the WSDL document might look like the following example:
<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" 
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://Example.org" 
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" 
xmlns:wsap="http://schemas.xmlsoap.org/ws/2004/08/addressing/policy" xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
xmlns:msc="http://schemas.microsoft.com/ws/2005/12/wsdl/contract" xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" 
xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:wsa10="http://www.w3.org/2005/08/addressing" 
xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex" targetNamespace="http://Example.org" 
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
 <wsdl:portType name="ICalculator">
  <wsdl:operation name="Add">
   <wsdl:input wsaw:Action="http://Example.org/ICalculator/Add" 
   message="tns:ICalculator_Add_InputMessage" />
   <wsdl:output wsaw:Action="http://Example.org/ICalculator/AddResponse" 
   message="tns:ICalculator_Add_OutputMessage" />
  </wsdl:operation>
 </wsdl:portType>
</wsdl:definitions>


Likewise, its XML schema can be defined as follows:
<xs:schema xmlns:tns="http://Example.org" elementFormDefault="qualified" 
targetNamespace="http://Example.org" xmlns:xs="http://www.w3.org/2001/XMLSchema">
 <xs:element name="Add">
  <xs:complexType>
   <xs:sequence>
    <xs:element minOccurs="0" name="a" type="xs:int" />
    <xs:element minOccurs="0" name="b" type="xs:int" />
   </xs:sequence>
  </xs:complexType>
 </xs:element>
 <xs:element name="AddResponse">
  <xs:complexType>
   <xs:sequence>
    <xs:element minOccurs="0" name="result" type="xs:int" 
    />
   </xs:sequence>
  </xs:complexType>
 </xs:element>
</xs:schema> 


Converting Metadata to Code

The service model provides the WsUtil.exe as a tool to process these metadata documents, converting a WSDL file into a C header and source files.
Dd430451.DocToTool(en-us,VS.85).png The WsUtil.exe generates header and sources for service implementation as well as client-side service operations for the client .

Calling the Calculator Service From a Client

As with the service implementation, the client must include the generated header or headers.
#include "CalculatorProxyStub.h"
Now, The client application can create and open a service proxy to begin communication with the calculator service.
WS_ENDPOINT_ADDRESS address = {0};
WS_STRING uri= WS_STRING_VALUE(L"http://localhost/example");
address.uri = uri;

if (FAILED (hr = WsCreateServiceProxy(WS_CHANNEL_TYPE_REQUEST, WS_HTTP_CHANNEL_BINDING, NULL, NULL, 0, &serviceProxy, error)))
    goto Error;

if (FAILED (hr = WsOpenServiceProxy(serviceProxy, &address, NULL, error)))
    goto Error;

The application can call the Add operation on the calculator service with the following code:
if (FAILED (hr = DefaultBinding_ICalculator_Add(serviceProxy, heap, 1, 2, &result, NULL, 0, NULL, error)))
    goto Error;
Please refer to the code example at HttpCalculatorClientExample for full implementation of the calculator service.

Service Model Components

The interaction of the individual WWSAPI Service Model components within the Calculator example is as follows:
  • The client creates a service proxy and opens it.
  • The client calls the Add function of the service, and passes in the service proxy.
  • The message is serialized according to the serialization metadata in the header and source files generated by the metadata tool (WsUtil.exe).
  • The message is written to the channel and is transmitted over the network to the service.
  • On the server side, the service is hosted inside a service host, and has an endpoint listening for the ICalculator contract.
  • Using the Service Model metadata in the stub, the service deserializes the message from the client and dispatches it to the stub.
  • The server-side service calls the Add method, passing it the operation context. This operation context contains the reference to the incoming message.
Dd430451.ServiceModelLayout(en-us,VS.85).png Components
  • Service host: Hosts a service.
  • Service proxy: Defines how a client communicates with a service.
  • Context: Property bag for making state-specific information available to a service operation.
  • Contract: The interface definition of a service. For example, ICalculator represents a contract for the calculator service in our example code.
  • WsUtil.exe: The Service Model metadata tool for generating proxies and stubs.

Windows Web Services

One of the main reasons many developers flocked to the Microsoft .NET Framework, and Java to a lesser degree, was the fact that it made it much easier to write software for the Internet. Whether you were writing an HTTP client or server application, the .NET Framework had you covered with classes for making HTTP requests and processing XML easily. You could even generate SOAP clients from WSDL documents and implement SOAP servers with ASP.NET. As the standards around Web services matured, Microsoft developed the Windows Communications Foundation (WCF), also built on the .NET Framework, to make it easier to use the increasingly complex Web standards for handling different transports, such as TCP and UDP, and provide more versatile security options.
C++ developers, however, were left wondering whether it was even practical to use C++ to write Web applications. Microsoft had provided a couple of temporary solutions in the form of ATL classes and a COM-based toolkit, but in the end these couldn’t keep up with the progress that the managed SOAP stacks had made and thus were largely abandoned.
Despite the seemingly single-minded focus on the .NET Framework, developers at Microsoft haven’t forgotten about the C++ developer. In fact, many of them are still and will continue to be passionate C++ developers. As a result, solutions that help C++ developers are a key part of Microsoft’s strategy for the Windows platform. Of course, many of the APIs targeted at C++ developers also end up underpinning many of the managed frameworks.
Although there are too many to enumerate here, a few are worth mentioning. The Windows HTTP Services (WinHTTP) API provides a powerful and flexible solution for writing HTTP clients. You can read more about WinHTTP in my August 2008 column. The HTTP Server (HTTP.sys) API provides the foundations for building high-performance HTTP servers without relying on a full-fledged Web server like Internet Information Services (IIS). In fact, IIS itself is based on this same API. And of course the XmlLite API provides a small and fast XML parser for native code. You can read more about XmlLite in my April 2007 feature article.
Given all of this, it is still quite a daunting task to write a SOAP client or server. Although SOAP started off “simple” (that’s what the “S” stands for), it didn’t stay that way for long. WinHTTP, HTTP.sys and XmlLite may get you a long way by handling the HTTP transport and parsing the XML, but there is still a ton of code to write to handle the communications layer: things like formatting and interpreting SOAP headers, not to mention supporting other transports like TCP or UDP. Even if you could somehow manage all of this, you’re still left with parsing SOAP envelopes instead of being able to treat logical SOAP operations as function calls.
Well, these headaches are a thing of the past. With the introduction of the Windows Web Services (WWS) API, C++ developers no longer have to think of themselves as second-class citizens in the world of Web Services. WWS is designed from the ground up to be a completely native-code implementation of SOAP, including support for many of the WS-* protocols. WWS is, strictly speaking, exposed through a C API, making interoperability with other languages and runtimes very straightforward, but it is the C++ developer who will likely benefit the most. In fact, with a little help from C++, it can be a real joy to use—as you shall see in this article.

Architecture and Principles

WWS embodies everything that .NET Framework-based libraries are not. It is designed for native code. It is designed to introduce a minimal number of dependencies. It is designed to use as little memory as possible. And it is designed to be fast. Really fast. The team responsible for developing WWS runs performance tests on each new build, comparing it with WCF and RPC. RPC is used as a sort of baseline since nothing could be faster, but it does provide a reliable way of tracking speed regressions. It is, however, illuminating when you compare WCF and WWS. Figure 1 shows a comparison of the working set for a client using WCF and WWS respectively. That’s a pretty dramatic margin, but perhaps not that surprising when you think that the .NET Framework is involved. Figure 2, however, should be surprising if you, like many others, consider WCF to be state of the art. It shows the throughput in operations per second for a server using WCF and WWS respectively. WWS is more than twice as fast! Don’t get me wrong: There is nothing wrong with WCF or the .NET Framework, but when you need something small and fast, it’s hard to beat C++ and native code. But you know that already!

Figure 1 Comparing Client Working Set (Lower Is Better)
The WWS runtime is packaged in WebServices.dll, which is included with Windows 7 and Windows Server 2008 R2. It is also available as a system update for Windows XP and later. Functions exported from WebServices.dll represent the WWS API and you can gain access to them by linking to WebServices.lib and including the WebServices.h header file from the Windows SDK. So far, so good. But what does the API look like? Well, unlike COM-style APIs like that of XmlLite or Direct2D, this C API requires you to imagine a set of logical layers and objects that live behind the scenes and are just waiting to break out. Let’s first take a look at it in terms of layers. Figure 3 illustrates the layers of functionality exposed by the WWS API, with each layer building upon the one beneath it. Each layer is represented by a number of functions and structures and provides a set of abstractions. As you can guess, the application can make use of any of the layers, but for the most part you will want to stick with the service model that provides the simplest programming model and hides many of the details for you. The transports layer is just a reminder that underneath it all there will be some network protocol. WWS will use WinHTTP, HTTP.sys, or Winsock, depending on the selected transport and whether it is used to implement a client or server.

Figure 2 Comparing Server Throughput (Higher Is Better)

Figure 3 Layered API
As its name suggests, the service model layer entirely abstracts the SOAP message exchanges and models the logical Web service operations as function calls. It does not, however, stand alone but relies on the use of a command-line tool called Wsutil.exe from the Windows SDK. Given a WSDL file, this tool will generate a header file as well as a C source file with most of the code necessary to both connect to a Web service of the given description and to implement such a Web service, taking care to ensure the channel binding is properly configured and messages are properly formatted. This is by far the simplest approach and provides a programming model that is very much like what you would expect from traditional RPC.
The channel layer, on the other hand, exposes the messages sent and received on a particular transport, but still optionally shields you from having to actually format the messages yourself. The benefit here is that you are shielded from the particular transport and encoding that is used. The channel layer is where you control binding information and where you can secure your communication whether for authentication or privacy.
The XML layer exposes you to the formatting of messages and serialization of data. You have full access to the content of messages but are shielded from the particular encoding whether you’re communicating with text, binary or MTOM. You might be surprised to hear that WWS has its own XML parser. Why doesn’t it just use XmlLite? Although XmlLite is certainly lightweight and very fast, it isn’t quite a perfect match for a number of reasons. The most obvious reason is that WWS needs to support different encodings while XmlLite supports only text. SOAP messages are also typically encoded using UTF-8, while XmlLite exposes all properties with Unicode strings and this introduces unnecessary cost when copying values. WWS also has very strict memory consumption goals (there is actually an API for this, as we’ll see later on) that cannot be met with XmlLite. In the end, the WWS team was able to implement a custom parser specifically for SOAP that is considerably faster than XmlLite. Keep in mind that the WWS parser is not meant to replace XmlLite. As a general purpose XML parser, it is hard to beat, but the WWS XML layer provides developers with very specific features aimed at efficiently serializing data into and out of SOAP message using the subset of XML required by SOAP.
Apart from the functions and data structures that logically belong to these three layers, the WWS API provides a number of facilities that are common to all layers, including error handling, asynchronous completion, cancellation, memory management and more. Because I have limited space and want to help you get started quickly, I’m going to limit the rest of this article to the use of the service model for building a Web service client and server. In a future article, I’ll dig more deeply into the other parts of WWS.

Getting Started

To get started, I’ll use the minimal Web service definition from Figure 4. This WSDL document defines the types, messages, operations, endpoints and channel bindings of the service. The first thing to do is run it through Wsutil.exe as follows:
Wsutil.exe Calculator.wsdl
This will produce a header file called Calculator.wsdl.h and a C source file called Calculator.wsdl.c.
Figure 4 Web Service Definition
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
 xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
 xmlns:xsd="ttp://www.w3.org/2001/XMLSchema"
 xmlns:tns="http://calculator.example.org/"
 targetNamespace="http://calculator.example.org/">
    
 <wsdl:types>
   <xsd:schema elementFormDefault="qualified" 
    targetNamespace="http://calculator.example.org/">
    <xsd:element name="AddRequest">
     <xsd:complexType>
      <xsd:sequence>
       <xsd:element name="first" type="xsd:double" />
       <xsd:element name="second" type="xsd:double" />
      </xsd:sequence>
     </xsd:complexType>
    </xsd:element>
    <xsd:element name="AddResponse">
     <xsd:complexType>
      <xsd:sequence>
       <xsd:element name="result" type="xsd:double" />
      </xsd:sequence>
     </xsd:complexType>
    </xsd:element>
   </xsd:schema>
  </wsdl:types>

  <wsdl:message name="AddRequestMessage">
    <wsdl:part name="parameters" element="tns:AddRequest" />
  </wsdl:message>
  <wsdl:message name="AddResponseMessage">
    <wsdl:part name="parameters" element="tns:AddResponse" />
  </wsdl:message>

  <wsdl:portType name="CalculatorPort">
    <wsdl:operation name="Add">
      <wsdl:input message="tns:AddRequestMessage" />
      <wsdl:output message="tns:AddResponseMessage" />
    </wsdl:operation>
  </wsdl:portType>

  <wsdl:binding name="CalculatorBinding" type="tns:CalculatorPort">
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="Add">
      <soap:operation soapAction=
       "http://calculator.example.org/Add" style="document"/>
      <wsdl:input>
       <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
       <soap:body use="literal"/>
      </wsdl:output>
     </wsdl:operation>
   </wsdl:binding>

   <wsdl:service name="CalculatorService">
    <wsdl:port name="CalculatorPort" binding="tns:CalculatorBinding">
     <soap:address location="http://localhost:81/calculator"/>
    </wsdl:port>
   </wsdl:service>

</wsdl:definitions>
Before we take a look at what was generated, we need to get some groundwork done, regardless of whether you’re implementing the client or the server. The first thing you’ll need is a way to express error information. The WWS API exposes rich error information both for its own functions as well as SOAP faults via an error object. Being a C API, this object is represented by an opaque handle and a set of functions. In this case, WS_ERROR* represents a handle to an error object and WsCreateError is the function that creates it. The object is freed by calling the WsFreeError function. The error object can store a number of strings with different levels of information about an error. To retrieve these, you need to first determine how many strings are present. This is done by calling the WsGetErrorProperty function, giving it the handle to the error object and specifying the WS_ERROR_PROPERTY_STRING_COUNT constant. Armed with this information, you call the WsGetErrorString function, giving it the handle to the error object as well as the zero-based index of the string to retrieve. You can also use the API functions to populate your own error objects. Naturally, a little C++ will go a long way to making this simpler and more reliable. Figure 5 provides a simple error object wrapper. You can easily enumerate the strings in an error object, as shown in Figure 6.
Figure 5 Error Object Wrapper
class WsError
{
    WS_ERROR* m_h;
public:
    WsError() m_h(0)
    {}
    ~WsError()
    {
        if (0 != m_h)
    }
    HRESULT Create(const WS_ERROR_PROPERTY* properties,
                      ULONG propertyCount)
    {
        return WsCreateError(properties, propertyCount, &m_h);
    }
    HRESULT GetProperty(WS_ERROR_PROPERTY_ID id, void* buffer,
                            ULONG bufferSize)
    {
        return WsGetErrorProperty(m_h, id, buffer, bufferSize);
    }
    template <typename T>
    HRESULT GetProperty(WS_ERROR_PROPERTY_ID id, out T* buffer)
    {
        return GetProperty(id, buffer, sizeof(T));
    }
    HRESULT GetString(ULONG index, WS_STRING* string)
    {
        return WsGetErrorString(m_h, index, string);
    }
    operator WS_ERROR*() const
    {
        return m_h;
    }
};
Figure 6 Enumerate the Strings in an Error Object
WsError error;
HR(error.Create(0, 0));
// Something goes wrong . . .
ULONG stringCount = 0;
HR(error.GetProperty(WS_ERROR_PROPERTY_STRING_COUNT,&stringCount));

for (ULONG i = 0; i < stringCount; ++i)
{
    WS_STRING string;
    HR(error.GetString(i, &string));
    wprintf(L"Error %d: %.*s\n", i, string.length, string.chars);
}
The next thing we’ll need is a heap object. The heap object provides precise control over memory allocation when producing or consuming messages and when needing to allocate various other API structures. It also simplifies the programming model since there is no need for you to know precisely how much memory is required for any particular function to succeed. Many older functions in the Windows SDK will, for example, either require you to guess how much storage is required or to first call a function in a particular way to determine how much memory you should allocate for the function to succeed. The use of the WWS heap object removes all this extra coding and provides a nice way to control the memory usage of the API. This also comes in handy from a security perspective where you may want to specify expected limits on how much the API may allocate. WS_HEAP* represents a handle to a heap object and WsCreateHeap is the function that creates it. The object is freed by calling the WsFreeHeap function. Once it’s created, you can allocate memory from the heap using the WsAlloc function, but for this article we’ll just pass the handle to the heap object to other API functions for them to use as necessary.
Figure 7 provides a simple heap object wrapper. Given this, you can create a heap object limited to 250 bytes as follows:
WsHeap heap;

HR(heap.Create(250, // max size
               0, // trim size
               0, // properties
               0, // property count
               error));
Notice how I’m passing the error object to the heap object’s Create method. Should anything go wrong while creating the heap object, I’ll be able to interrogate the error object to find out the cause.
Figure 7 Heap Object Wrapper
class WsHeap
{
    WS_HEAP* m_h;
public:
    WsHeap() : m_h(0)
    {}
    ~WsHeap()
    {
        if (0 != m_h) WsFreeHeap(m_h);
    }
    HRESULT Create(SIZE_T maxSize, SIZE_T trimSize,
            const WS_HEAP_PROPERTY* properties,
            ULONG propertyCount,
            in_opt WS_ERROR* error)
    {
            return WsCreateHeap(maxSize, trimSize, properties, propertyCount,
                                    &m_h, error);
    }
    operator WS_HEAP*() const
    {
        return m_h;
    }
};

The Client

The client-side of the service model centers on the service proxy object. The generated source code includes a function called CalculatorBinding_CreateServiceProxy. The name is derived from that of the endpoint or binding name defined in the WSDL document. This function creates a service proxy object and returns a WS_SERVICE_PROXY* representing an opaque handle to that object. The object is freed by calling the WsFreeServiceProxy function. Once created, your application can open the service endpoint using the WsOpenServiceProxy function and then make calls via the service proxy to the Web service. What exactly WsOpenServiceProxy does is dependent on the transport being used. You must also take care to close the service proxy prior to freeing the object using the WsCloseServiceProxy function. Naturally, all of this housekeeping can be nicely wrapped up in a simple class provided in Figure 8. Given this, you can create and open the service proxy, as shown in Figure 9.
Figure 8 Service Proxy Wrapper
class WsServiceProxy
{
    WS_SERVICE_PROXY* m_h;
public:
    WsServiceProxy() : m_h(0)
    {}
    ~WsServiceProxy()
    {
        if (0 != m_h)
        {
            Close(0, 0); // error
            WsFreeServiceProxy(m_h);
        }
    }
    HRESULT Open(const WS_ENDPOINT_ADDRESS* address, 
            const WS_ASYNC_CONTEXT* asyncContext, 
            WS_ERROR* error)
    {
        return WsOpenServiceProxy(m_h, address, asyncContext, error);
    }
    HRESULT Close(const WS_ASYNC_CONTEXT* asyncContext, 
            WS_ERROR* error)
    {
        return WsCloseServiceProxy(m_h, asyncContext, error);
    }
    WS_SERVICE_PROXY** operator&()
    {
        return &m_h;
    }
    operator WS_SERVICE_PROXY*() const
    {
        return m_h;
    }
};
Figure 9 Create and Open Service Proxy
WsServiceProxy serviceProxy;

HR(CalculatorBinding_CreateServiceProxy(0, // template value
                                        0, // properties
                                        0, // property count
                                        &serviceProxy,
                                        error));

WS_ENDPOINT_ADDRESS address =
{
    {
        static_cast<ULONG>(wcslen(url)),
        const_cast<PWSTR>(url)
    }
};

HR(serviceProxy.Open(&address,
                     0, // async context
                     error));
The WS_ENDPOINT_ADDRESS structure is used to address the messages being sent. You will typically use this structure when programming at the channel layer. In this case, we populate only the URL portion and the service proxy takes care of the rest.
At this point, we can use another generated function namely CalculatorBinding_Add, which unsurprisingly represents the Web service’s Add operation. It really doesn’t get much easier than this:
const double first = 1.23;
const double second = 2.34;
double result = 0.0;

HR(CalculatorBinding_Add(serviceProxy,
                         first,
                         second,
                         &result,
                         heap,
                         0, // properties
                         0, // property count
                         0, // async context
                         error));

ASSERT(3.57 == result);
Once you are done interacting with the Web service you just need to close the service proxy’s communication channel:
HR(serviceProxy.Close(0, // async context
                      error));

The Server

While the client-side programming model centers on the service proxy, the server instead creates and manages a service host, which provides the necessary runtime to listen on the various endpoints based on the provided channel information. Again, because we’re using the service model, most of the details are abstracted away, and we’re left only to create the service endpoint and host. WWS will do the rest.
The first step is to create the service endpoint. The service model takes care of this in the form of another generated function, namely CalculatorBinding_CreateServiceEndpoint, as Figure 10 shows. Creating the endpoint requires specifying the address on which the endpoint is going to listen. This is provided by the WS_STRING structure, which is a length-prefixed Unicode string and is not required to be null terminated. Because the endpoint is responsible for fulfilling requests, you need to provide a table of function pointers mapping to the operations exposed by the service. The generated CalculatorBindingFunctionTable structure is used for this purpose. Finally, the endpoint itself is represented by the WS_SERVICE_ENDPOINT structure and is allocated in the provided heap.
Figure 10 CalculatorBinding_CreateServiceEndpoint
class WsServiceHost
{
    WS_SERVICE_HOST* m_h;
public:
  WsServiceHost() : m_h(0)
  {}
  ~WsServiceHost()
  {
    if (0 != m_h)
    {
        Close(0, 0); 
        WsFreeServiceHost(m_h);
    }
  }
  HRESULT Create(const WS_SERVICE_ENDPOINT** endpoints, 
          const USHORT endpointCount, 
          const WS_SERVICE_PROPERTY* properties, 
          ULONG propertyCount, WS_ERROR* error)
  {
     return WsCreateServiceHost(endpoints, endpointCount, properties,
                      propertyCount, &m_h, error);
  }
  HRESULT Open(const WS_ASYNC_CONTEXT* asyncContext, WS_ERROR* error)
  {
    return WsOpenServiceHost(m_h, asyncContext, error);
  }
  HRESULT Close(const WS_ASYNC_CONTEXT* asyncContext, WS_ERROR* error)
  {
    return WsCloseServiceHost(m_h, asyncContext, error);
  }
  operator WS_SERVICE_HOST*() const
  {
    return m_h;
  }
};

WsServiceProxy serviceProxy;
const WS_STRING address =
{
    static_cast<ULONG>(wcslen(url)),
    const_cast<PWSTR>(url)
};

CalculatorBindingFunctionTable functions =
{
    AddCallback
};

WS_SERVICE_ENDPOINT* endpoint = 0;

HR(CalculatorBinding_CreateServiceEndpoint(0, // template value
                                           &address,
                                           &functions,
                                           0, // authz callback
                                           0, // properties
                                           0, // property count
                                           heap,
                                           &endpoint,
                                           error));
The next step is to create the service host. WS_SERVICE_HOST* represents a handle to a service host object and WsCreateServiceHost is the function that creates it. The object is freed by calling the WsFreeServiceHost function. The WsCreateServiceHost function creates the service host object given a list of endpoints. At this point, you can start the listeners on all the endpoints using the WsOpenServiceHost function. Stop the communication using the WsCloseServiceHost function. As with the service proxy, be sure to close the service host prior to freeing it. Again, all of this housekeeping can be nicely wrapped up in a simple class provided in Figure 11. Given this, you can start the Web service as follows:
const WS_SERVICE_ENDPOINT* endpoints[] = { endpoint };

WsServiceHost serviceHost;

HR(serviceHost.Create(endpoints,
                      _countof(endpoints),
                      0, // properties
                      0, // property count
                      error));

HR(serviceHost.Open(0, // async context
                    error));
In this case, there is only a single endpoint but you can see how easy it would be to add additional endpoints to the service host. When it is time to stop the service, you just need to close the service host’s communication channels.
HR(serviceHost.Close(0, // async context
                     error));
Actually implementing the Web service operation is about the easiest part:
HRESULT CALLBACK AddCallback(__in const WS_OPERATION_CONTEXT*, 
                 __in double first, 
                 __in double second, 
                 __out double* result, 
                 __in_opt const WS_ASYNC_CONTEXT* /*asyncContext*/,
                 __in_opt WS_ERROR* /*error*/)
{
    *result = first + second;
    return S_OK;
}
The signature for the AddCallback function is also provided by the generated source code, should you have any doubts about how to specify it.
And that’s all I have space for this month, but you should now have a good idea of the features and benefits that the Windows Web Services API has to offer. As you can see, C++ developers finally have a modern SOAP stack right out of the box. It offers the best possible performance and memory usage and is a pleasure to use with a little help from C++.
Figure 11 Service Host Wrapper
class WsServiceHost
{
    WS_SERVICE_HOST* m_h;
public:
    WsServiceHost() : m_h(0)
    {}
    ~WsServiceHost()
    {
        if (0 != m_h)
        {
            Close(0, 0);
            WsFreeServiceHost(m_h);
        }
    }
    HRESULT Create(const WS_SERVICE_ENDPOINT** endpoints,
            const USHORT endpointCount,
            const WS_SERVICE_PROPERTY* properties,
            ULONG propertyCount, WS_ERROR* error)
    {
        return WsCreateServiceHost(endpoints, endpointCount, properties,
                                            propertyCount, &m_h, error);
    }
    HRESULT Open(const WS_ASYNC_CONTEXT* asyncContext, WS_ERROR* error)
    {
        return WsOpenServiceHost(m_h, asyncContext, error);
    }
    HRESULT Close(const WS_ASYNC_CONTEXT* asyncContext, WS_ERROR* error)
    {
        return WsCloseServiceHost(m_h, asyncContext, error);
    }
    operator WS_SERVICE_HOST*() const
    {
        return m_h;
    }
};
Who’s Using It?
Various teams at Microsoft have already started adopting the Windows Web Services (WWS) API within their own products or technologies. In many cases, this replaces custom-built SOAP stacks and some even chose to replace commercial implementations like Windows Communication Foundation (WCF) with WWS. Here are just a few examples.
The Microsoft Web Services on Devices (WSD) API enables developers to write clients and servers based on the Devices Profile for Web Services (DPWS). In Windows 7, the WSD API has started using WWS for the creation and canonicalization of XML in SOAP messages that the WSD runtime sends out. The WSD team plans to expand their use of WWS as they add new features and refactor existing code.
Windows CardSpace is Microsoft’s implementation of an identity system based on Web service standards. Originally implemented with WCF, it is being rewritten using native code and WWS to meet very strict business requirements on the size of the downloadable installer and the runtime working set.
The Microsoft Forefront Threat Management Gateway (TMG) is a security platform providing firewall and caching features to secure and improve the performance of networks. Its URL filtering feature uses WWS to connect to the Microsoft Reputation Service to categorize URLs.
Finally, the Windows Public Key Infrastructure (PKI) client provides automatic lifecycle management of certificates with auto enrollment as well as user and application driven certificate enrollment. Windows 7 introduces a new set of Web services that allow for certificate enrollment to be completed without the 
traditional limitations of LDAP and DCOM. The PKI client makes use of WWS for all operations, including a new Certificate Enrollment Policy (MS-XCEP) protocol and a WS-Trust extension for certificate enrollment (MS-WSTEP). The WWS client communicates with a new set of Active Directory Certificate Services in Windows Server 2008 R2 that are implemented with WCF, as well as with Web services provided by public certificate issuers.

Managed vs. Unmanaged Development

Benefits of Managed Code

Managed code refers to code written for managed programming languages, such as .NET and Java. These languages provide a generalized way to handle the details of memory management and garbage collection, at the cost of a small amount of overhead. This trade-off frees you from error-prone tasks, and allows you to write more compact, readable, and error-free programs.
Historically, game developers used unmanaged code. At first, there were no managed languages. When these languages appeared, the extra cost of the managed layer was too high for games, many of which require extremely high performance, particularly in terms of graphics processing.
Today, game developers use managed code more often, because even on Windows Mobile devices, the hardware performs a great deal of the graphics processing, so the graphics code is less often the performance bottleneck. Managed code development using the .NET Mobile Framework on the Windows Mobile platform has become very popular, particularly for casual game development in which graphics performance is less important than stability.
Managed code that runs on Windows Mobile requires the Windows Mobile Class Library and the .NET Mobile Framework. Windows Mobile 6 now includes the .NET Compact Framework version 2 SP2 in ROM, in all devices.
For more information on developing for Windows Mobile using managed code, see the following topics:
For 3D graphics programming for Windows Mobile, use the Managed Direct3D Mobile library, which is part of the .NET Compact Framework 2.0.
For information on Managed Direct3D Mobile, see:
If you use an unmanaged language, such as C++, you must write extra code to manage memory and security, and clean up objects after they have served their purpose. The housekeeping details are complicated, and don't relate to the intended function of the program, so developers often neglect these tasks, ignore them, or lose track of them. As a result, unmanaged code is often more costly and time consuming to test, and it requires greater programmer training and discipline.
However, developers often prefer unmanaged code because it executes faster, allows more flexibility in the use of pointers, and gives direct control of hardware. Because of that preference, most of the documentation in this SDK targets unmanaged code.
You might choose to use an unmanaged language for Windows Mobile games for either of the following reasons:
  • Maximum speed of execution. The managed layer adds around 10% overhead to the program.
  • Maximum flexibility. Some features of some APIs are unavailable through the managed library. Using unmanaged APIs from a managed code program is possible but more difficult, and introduces its own performance issues.
  • You can create a marketable game using either approach. The main criteria for the decision are your experience and comfort level with the languages, and the performance that the application code requires. For example, managed code probably delivers the performance required for a card game, but unmanaged code is probably a better choice for a 3-D flying game.

Thursday, August 25, 2011

Web Services in C++

http://www.codeproject.com/KB/webservices/SoapClient_CPP.aspx

http://msdn.microsoft.com/en-us/library/2k53kft2%28v=vs.80%29.aspx

http://users.skynet.be/pascalbotte/rcx-ws-doc/gsoap.htm




Tuesday, August 23, 2011

Developing JAX-WS Web Service Clients

Developing JAX-WS Web Service Clients

In this tutorial, you use the web service facilities provided by NetBeans IDE to analyze a Spell Checker web service, after which you build a web client that interacts with the service. The client uses a servlet class and a JSP page. The user passes information to the servlet from the JSP page.
Contents
Content on this page applies to NetBeans IDE 6.7-7.0
To follow this tutorial, you need the following software and resources.
Software or Resource Version Required
NetBeans IDE Java EE download bundle
Java Development Kit (JDK) version 6 or version 5
Warning: NetBeans IDE 6.9 requires JDK 6
Java EE-compliant web or application server Tomcat web server 6.0
GlassFish Server Open Source Edition
Oracle WebLogic Server
If you are using JDK 6, you need JDK 6 Update 7 or later.
Both Tomcat and the GlassFish server can be installed with the Web and Java EE distribution of NetBeans IDE. Alternatively, you can visit the the GlassFish server downloads page or the Apache Tomcat downloads page.
This is what your client will look like, with all data received from the web service:
Spell Checker report By the end of this tutorial, you discover that your only contribution to the application consists of providing the text to be checked, invoking an operation on the web service, and rendering the result. The IDE generates all the code needed for contacting the web service and sending the text. The spell checker web service takes care of the rest, it identifies the misspelled words and provides a list of suggested alternatives.
The spell checker web service used in this tutorial is provided by the CDYNE Corporation. CDYNE develops, markets and supports a comprehensive suite of data enhancement, data quality and data analysis web services and business intelligence integration. The spell checker web service is one of the web services provided by CDYNE. Note that the strength of an application based on one or more web services depends on the availability and reliability of the web services. However, CDYNE's FAQ points out that it has a "100% availability objective" and that in the event of "natural disaster, act of terror, or other catastrophe, web service traffic is transferred to our secondary data center". NetBeans thanks CDYNE for enabling this tutorial to be written and for supporting its development.

Consuming the Spell Checker Web Service

To use a web service over a network, which is called "consuming" a web service, you need to create a web service client. For the creation of web service clients, NetBeans IDE provides a client creation facility, which is the Web Service Client wizard that generates code for looking up a web service. It also provides facilities for developing the created web service client, a work area consisting of nodes in the Projects window. These facilities are part of the standard NetBeans IDE installation, they're available straight out of the box and no plug-ins are needed.

Creating the Client

In this section, you use a wizard to generate Java objects from the web service's WSDL file.
  1. Choose File > New Project (Ctrl-Shift-N). Under Categories, choose Java Web. Under Projects, choose Web Application. Click Next. Name the project SpellCheckService and make sure that you specify an appropriate server as your target server. (Refer to the "Getting Started" section for details.) Leave all other options at default and click Finish.
  2. In the Projects window, right-click the SpellCheckService project node and choose New > Other. In the New File wizard choose Web Services > Web Service Client. In the Web Service Client wizard, specify the URL to the web service: http://wsf.cdyne.com/SpellChecker/check.asmx?wsdl
    If you are behind a firewall, you might need to specify a proxy server—otherwise the WSDL file cannot be downloaded. To specify the proxy server, click Set Proxy in the wizard. The IDE's Options window opens, where you can set the proxy universally for the IDE.
  3. Leave the package name blank. By default the client class package name is taken from the WSDL. In this case is com.cdyne.ws.
  4. Select JAX version JAX-WS (Some older services require JAX-RPC clients). Click Finish.
  5. In the Projects window, within the Web Service References node, you see the following:
    Projects window showing web service references
The Projects window shows that a web service called 'check' has made a number of 'CheckTextBody' and 'CheckTextBodyV2' operations available to your application. These operations check a string for spelling errors and returns data to be processed by the client. The V2 version of the service does not require authentication. You will use the checkSoap.CheckTextBodyV2 operation throughout this tutorial.
Within the Generated Sources node, you see the client stubs that were generated by the JAX-WS Web Service Client wizard.
Files view showing package structure of Build node Expand the WEB-INF node and the wsdl subnode. You find a local copy of the WSDL file, named check.asmx.wsdl.
Projects window showing local WSDL copy and mapping file in WEB-INF The URL of the WSDL that you used to create the client is mapped to the local copy of the WSDL in jax-ws-catalog.xml. Mapping to a local copy has several advantages. The remote copy of the WSDL does not have to be available for the client to run. The client is faster, because it does not need to parse a remote WSDL file. Lastly, portability is easier. For more details, see the DZone article Portability and Performance Improvements in JAX-WS Clients Created with NetBeans IDE 6.7.
The generated jax-ws-catalog mapping file

Developing the Client

There are many ways to implement a web service client. The web service's WSDL file restricts the type of information that you can send to the web service, and it restricts the type of information you receive in return. However, the WSDL file lays no restrictions on how you pass the information it needs, nor on what the user interface consists of. The client implementation you build below consists of a JSP page which allows the user to enter text to be checked and a servlet which passes the text to the web service and then produces a report containing the result.

Coding the JSP Page

Our JSP page will consist of a text area, where the user will enter text, and a button for sending the text to the web service.
  1. In the Projects window, expand the Web Pages node of the SpellCheckService project and double-click index.jsp so that it opens in the Source Editor.
  2. Copy the following code and paste it over the <body> tags in index.jsp:
    <body>
      <form name="Test" method="post" action="SpellCheckServlet">
         <p>Enter the text you want to check:</p>
         <p>
         <p><textarea rows="7" name="TextArea1" cols="40" ID="Textarea1"></textarea></p>
         <p>
         <input type="submit" value="Spell Check" name="spellcheckbutton">
      </form>
    </body>
    The previously listed code specifies that when the submit button is clicked, the content of the textarea is posted to a servlet called SpellCheckServlet.

Creating and Coding the Servlet

In this section you create a servlet that will interact with the web service. However, the code that performs the interaction will be provided by the IDE. As a result, you only need to deal with the business logic, that is, the preparation of the text to be sent and the processing of the result.
  1. Right-click the SpellCheckService project node in the Projects window, choose New > Other and then choose Web > Servlet. Click Next. The New Servlet wizard opens.
  2. Name the servlet SpellCheckServlet and type clientservlet in the Package drop-down.
    New Servlet wizard showing name and package of servlet
  3. Click Next. The Configure Servlet Deployment panel opens. Note that the URL mapping for this servlet is /SpellCheckServlet. Accept the defaults and click Finish. The servlet opens in the Source Editor.
    Display in browser
  4. Put your cursor inside the Source Editor, inside the processRequest method body, and add some new lines right at the top of the method.
  5. Right-click in the space that you created in the previous step, and choose Insert Code > Call Web Service Operation. Click the checkSoap.CheckTextBodyV2 operation in the "Select Operation to Invoke" dialog box,as shown below:
    Projects window showing web service references Click OK.
    Note: You can also drag and drop the operation node directly from the Projects window into the editor, instead of calling up the dialog shown above.
    At the end of the SpellCheckServlet class, you see a private method for calling the SpellCheckerV2 service and returning a com.cdyne.ws.DocumentSummary object .
    private DocumentSummary checkTextBodyV2(java.lang.String bodyText) {
        com.cdyne.ws.CheckSoap port = service.getCheckSoap();
        return port.checkTextBodyV2(bodyText);
    }
    This method is all you need to invoke the operation on the web service. In addition, the following lines of code are declared at the top of the class:
    @WebServiceRef(wsdlLocation = "http://wsf.cdyne.com/SpellChecker/check.asmx?WSDL")
    private Check service;
  6. Replace the try block of the processRequest() method with the code that follows. The in-line comments throughout the code below explain the purpose of each line.
    try {
        //Get the TextArea from the JSP page
        String TextArea1 = request.getParameter("TextArea1");
    
    
        //Initialize WS operation arguments
        java.lang.String bodyText = TextArea1;
    
        //Process result
        com.cdyne.ws.DocumentSummary doc = checkTextBodyV2(bodyText);
        String allcontent = doc.getBody();
    
        //From the retrieved document summary,
        //identify the number of wrongly spelled words:
        int no_of_mistakes = doc.getMisspelledWordCount();
    
        //From the retrieved document summary,
        //identify the array of wrongly spelled words:
        List allwrongwords = doc.getMisspelledWord();
    
        out.println("<html>");
        out.println("<head>");
    
        //Display the report's name as a title in the browser's titlebar:
        out.println("<title>Spell Checker Report</title>");
        out.println("</head>");
        out.println("<body>");
    
        //Display the report's name as a header within the body of the report:
        out.println("<h2><font color='red'>Spell Checker Report</font></h2>");
    
        //Display all the content (correct as well as incorrectly spelled) between quotation marks:
        out.println("<hr><b>Your text:</b> \"" + allcontent + "\"" + "<p>");
    
        //For every array of wrong words (one array per wrong word),
        //identify the wrong word, the number of suggestions, and
        //the array of suggestions. Then display the wrong word and the number of suggestions and
        //then, for the array of suggestions belonging to the current wrong word, display each
        //suggestion:
        for (int i = 0; i < allwrongwords.size(); i++) {
            String onewrongword = ((Words) allwrongwords.get(i)).getWord();
            int onewordsuggestioncount = ((Words) allwrongwords.get(i)).getSuggestionCount();
            List allsuggestions = ((Words) allwrongwords.get(i)).getSuggestions();
            out.println("<hr><p><b>Wrong word:</b><font color='red'> " + onewrongword + "</font>");
            out.println("<p><b>" + onewordsuggestioncount + " suggestions:</b><br>");
            for (int k = 0; k < allsuggestions.size(); k++) {
                String onesuggestion = (String) allsuggestions.get(k);
                out.println(onesuggestion);
            }
        }
    
        //Display a line after each array of wrong words:
        out.println("<hr>");
    
        //Summarize by providing the number of errors and display them:
        out.println("<font color='red'><b>Summary:</b> " + no_of_mistakes + " mistakes (");
        for (int i = 0; i < allwrongwords.size(); i++) {
            String onewrongword = ((Words) allwrongwords.get(i)).getWord();
            out.println(onewrongword);
        }
    
        out.println(").");
        out.println("</font>");
        out.println("</body>");
        out.println("</html>");
    
    } catch (Exception ex) {
        out.println("exception" + ex);
    } finally {
        out.close();
    }    
    
  7. You see a number of error bars and warning icons, indicating classes that are not found. To fix imports after pasting the code, either press Ctrl-Shift-I, or right-click anywhere, which opens a context menu, and select Fix Imports. (You have a choice of List classes to import. Accept the default java.util.List.) The full list of imported classes follows:
    import com.cdyne.ws.Check;
    import com.cdyne.ws.Words;
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.util.List;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.xml.ws.WebServiceRef;
    Note: If you see warnings that the com.cdyne.* classes cannot be found, do not be alarmed. This problem is resolved when you build the project, when the IDE parses the WSDL files and finds the classes.
    Note that error handling has not been dealt with in the previously listed code. See Applying What You Have Learned for details.

Deploying the Client

The IDE uses an Ant build script to build and run your application. The IDE generates the build script based on the options you entered when creating the project. You can fine tune these options in the project's Project Properties dialog box (right-click the project node in the Projects window and choose Properties).
  1. Right-click the project node and choose Run. After a while, the application deploys and displays the JSP page that you coded in the previous section.
  2. Enter some text, making sure that some of it is incorrectly spelled:
    JSP page with text to check
  3. Click Spell Check and see the result:
    Spell Checker report showing errors 
  4.  

Asynchronous Web Service Clients

By default, JAX-WS clients created by the NetBeans IDE are synchronous. Synchronous clients invoke a request on a service and then suspend their processing while they wait for a response. However, in some cases you want the client to continue with some other processing rather than wait for the response. For example, in some cases it may take a significant amount of time for the service to process the request. Web service clients that continue processing without waiting for the service response are called "asynchronous".
Asynchronous clients initiate a request to a service and then resume their processing without waiting for a response. The service handles the client request and returns a response at some later point, at which time the client retrieves the response and proceeds with its processing.
Asynchronous clients consume web services either through the "polling" approach or the "callback" approach. In the "polling" approach, you invoke a web service method and repeatedly ask for the result. Polling is a blocking operation because it blocks the calling thread, which is why you do not want to use it in a GUI application. In the "callback" approach you pass a callback handler during the web service method invocation. The handler's handleResponse() method is called when the result is available. This approach is suitable to GUI applications because you do not have to wait for the response. For example, you make a call from a GUI event handler and return control immediately, keeping the user interface responsive. The drawback of the polling approach is that, even though the response is consumed after it is caught, you have to poll for it to find out that it has been caught.
In NetBeans IDE, you add support for asynchronous clients to a web service client application by ticking a box in the Edit Web Service Attributes GUI of the web service references. All other aspects of developing the client are the same as for synchronous clients, except for the presence of methods to poll the web service or pass a callback handler and await the result.
The rest of this section details how to create a Swing graphical interface and embed an asynchronous JAX-WS client inside it.

Creating the Swing Form

In this section you design the Swing application. If you prefer not to design the Swing GUI yourself, you can download a predesigned JFrame and go to the section on Creating the Asynchronous Client.
The Swing client gets text you type in, sends it to the service, and returns the number of mistakes and a list of all the wrong words. The client also shows you each wrong word and the suggestions to replace it, one wrong word at a time.
Predesigned Swing client To create the Swing client:
  1. Create a new Java Application project. Name it AsynchSpellCheckClient. Do NOT create a Main class for the project.
  2. In the Projects view, right-click the AsynchSpellCheckClient project node and select New > JFrame Form...
  3. Name the form MainForm and place it in the package org.me.forms.
  4. After you create the JFrame, open the project properties. In the Run category, set MainForm as the Main class.
    Project Properties showing MainForm selected as Main class
  5. In the Editor, open the Design view of MainForm.java. From the Palette, drag and drop three Scroll Panes into MainForm. Position and size the scroll panes. They will hold the text fields for the text you type in to check, all the wrong words, and the suggestions for one wrong word.
  6. Drag and drop five Text Fields into MainForm. Drop three of them into the three scroll panes. Modify them as follows:
    Text Fields
    Variable NameIn Scroll Pane?Editable?
    tfYourTextYY
    tfNumberMistakesNN
    tfWrongWordsYN
    tfWrongWord1NN
    tfSuggestions1YN
  7. Drag and drop a Progress Bar into MainForm. Name the variable pbProgress.
  8. Drag and drop two Buttons into MainForm. Name the first button btCheck and change its text to Check Text or Check Spelling. Name the second button btNextWrongWord, change its text to Next Wrong Word, and disable it.
  9. Drag and drop some Labels into MainForm, to give a title to your application and to describe the text fields.
Arrange the appearance of the JFrame to your liking and save it. Next you add web service client functionality.

Enabling Asynchronous Clients

Add the web service references, as described in Creating the Client. Then edit the web service attributes to enable asynchronous clients.
  1. In the Projects window, right-click the AsynchSpellCheckClient project node and choose New > Other. In the New File wizard choose Web Services > Web Service Client. In the Web Service Client wizard, specify the URL to the web service: http://wsf.cdyne.com/SpellChecker/check.asmx?wsdl. Accept all the defaults and click Finish. This is the same procedure from Step 2 onwards described in Creating the Client.
  2. Expand the Web Service References node and right-click the check service. The context menu opens.
    The context menu for the Check service node in Web Service References, with the cursor poised over Edit Web Service Attributes
  3. From the context menu, select Edit Web Service Attributes. The Web Service Attributes dialog opens.
  4. Select the WSDL Customization tab.
  5. Expand the Port Type Operations node. Expand the first CheckTextBodyV2 node and select Enable Asynchronous Client.
    The Web Service Attribute dialog showing the option to enable asynchronous clients for a Port Type Operation
  6. Click OK. The dialog closes and a warning appears that changing the web service attributes will refresh the client node.
    Warning that generated classes and WSDL will refresh, affecting applications that use the generated classes
  7. Click OK. The warning closes and your client node refreshes. If you expand the check node in Web Service References, you see that you now have Polling and Callback versions of the CheckTextBody operation.
    Asynchronous client operations in Projects window
Asynchronous web service clients for the SpellCheck service are now enabled for your application.

Adding the Asynchronous Client Code

Now that you have asynchronous web service operations, add an asynchronous operation to MainForm.java.
To add asynchronous client code:
  1. In MainForm, change to the Source view and add the following method just before the final closing bracket.
    public void callAsyncCallback(String text){
                     
    }
  2. In the Projects window, expand the AsynchSpellCheckService's Web Service References node and locate the checkSoap.CheckTextBodyV2 [Asynch Callback]operation.
  3. Drag the CheckTextBodyV2 [Asynch Callback] operation into the empty callAsyncCallback method body. The IDE generates the following try block. Compare this generated code to the code generated for the synchronous client.
    try { // Call Web Service Operation(async. callback)
          com.cdyne.ws.Check service = new com.cdyne.ws.Check();
          com.cdyne.ws.CheckSoap port = service.getCheckSoap();
          // TODO initialize WS operation arguments here
          java.lang.String bodyText = "";
          javax.xml.ws.AsyncHandler<com.cdyne.ws.CheckTextBodyV2Response> asyncHandler = 
                  new javax.xml.ws.AsyncHandler<com.cdyne.ws.CheckTextBodyV2Response>() {
                public void handleResponse(javax.xml.ws.Response<com.cdyne.ws.CheckTextBodyV2Response> response) {
                      try {
                            // TODO process asynchronous response here
                            System.out.println("Result = "+ response.get());
                      } catch(Exception ex) {
                            // TODO handle exception
                      }
                }
          };
          java.util.concurrent.Future<? extends java.lang.Object> result = port.checkTextBodyV2Async(bodyText, asyncHandler);
          while(!result.isDone()) {
                // do something
                Thread.sleep(100);
          }
          } catch (Exception ex) {
          // TODO handle custom exceptions here
    }
    In this code, along with the web service invocation, you see that the response from the SpellCheck service is handled through an AsynchHandler object. Meanwhile, a Future object checks to see if a result has been returned and sleeps the thread until the result is complete.
  4. Switch back to the Design view. Double-click the Check Spelling button. The IDE automatically adds an ActionListener to the button and switches you to the Source view, with the cursor in the empty btCheckActionPerformed method.
  5. Add the following code to the btCheckActionPerformed method body. This code gets the text that you type into the tfYourText field, has the progress bar display a "waiting for server" message, disables the btCheck button, and calls the asynchronous callback method.
    private void btCheckActionPerformed(java.awt.event.ActionEvent evt) {                                        
        String text = tfYourText.getText();
        pbProgress.setIndeterminate(true);
        pbProgress.setString("waiting for server");
        btCheck.setEnabled(false);
        callAsyncCallback(text);
    }
  6. At the beginning of the MainForm class, instantiate a private ActionListener field named nextWord. This ActionListener is for the Next Wrong Word button that advances one wrong word in the list of wrong words and displays the word and suggestions for correcting it. You create the private field here so you can unregister the ActionListener if it already has been defined. Otherwise, every time you check new text, you would add an additional listener and end up with multiple listeners calling actionPerformed() multiple times. The application would not behave correctly.
    public class MainForm extends javax.swing.JFrame {
        
        private ActionListener nextWord;
        ...
  7. Replace the entire callAsyncCallback method with the following code. Note that the outermost try block is removed. It is unnecessary because more specific try blocks are added inside the method. Other changes to the code are explained in code comments.
    public void callAsyncCallback(String text) {
    
            
        com.cdyne.ws.Check service = new com.cdyne.ws.Check();
        com.cdyne.ws.CheckSoap port = service.getCheckSoap();
        // initialize WS operation arguments here
        java.lang.String bodyText = text;
    
        javax.xml.ws.AsyncHandler<com.cdyne.ws.CheckTextBodyV2Response> asyncHandler = new javax.xml.ws.AsyncHandler<com.cdyne.ws.CheckTextBodyV2Response>() {
    
            public void handleResponse(final javax.xml.ws.Response<com.cdyne.ws.CheckTextBodyV2Response> response) {
                SwingUtilities.invokeLater(new Runnable() {
    
                    public void run() {
    
                        try {
                            // Create a DocumentSummary object containing the response.
                            // Note that getDocumentSummary() is called from the Response object
                            // unlike the synchronous client, where it is called directly from
                            // com.cdyne.ws.CheckTextBody
    
                            com.cdyne.ws.DocumentSummary doc = response.get().getDocumentSummary();
    
    
                            //From the retrieved DocumentSummary,
                            //identify and display the number of wrongly spelled words:
    
                            final int no_of_mistakes = doc.getMisspelledWordCount();
                            String number_of_mistakes = Integer.toString(no_of_mistakes);
                            tfNumberMistakes.setText(number_of_mistakes);
    
    
                            // Check to see if there are any mistakes
                            if (no_of_mistakes > 0) {
    
                                //From the retrieved document summary,
                                //identify the array of wrongly spelled words, if any:
    
                                final List<com.cdyne.ws.Words> allwrongwords = doc.getMisspelledWord();
    
    
                                //Get the first wrong word
                                String firstwrongword = allwrongwords.get(0).getWord();
    
                                //Build a string of all wrong words separated by commas, then display this in tfWrongWords
    
                                StringBuilder wrongwordsbuilder = new StringBuilder(firstwrongword);
    
                                for (int i = 1; i < allwrongwords.size(); i++) {
                                    String onewrongword = allwrongwords.get(i).getWord();
                                    wrongwordsbuilder.append(", ");
                                    wrongwordsbuilder.append(onewrongword);
                                }
                                String wrongwords = wrongwordsbuilder.toString();
                                tfWrongWords.setText(wrongwords);
    
                                //Display the first wrong word
                                tfWrongWord1.setText(firstwrongword);
    
    
                                //See how many suggestions there are for the wrong word
                                int onewordsuggestioncount = allwrongwords.get(0).getSuggestionCount();
    
    
                                //Check to see if there are any suggestions.
                                if (onewordsuggestioncount > 0) {
    
                                    //Make a list of all suggestions for correcting the first wrong word, and build them into a String.
                                    //Display the string of concactenated suggestions in the tfSuggestions1 text field
    
    
                                    List<String> allsuggestions = ((com.cdyne.ws.Words) allwrongwords.get(0)).getSuggestions();
    
                                    String firstsuggestion = allsuggestions.get(0);
                                    StringBuilder suggestionbuilder = new StringBuilder(firstsuggestion);
                                    for (int i = 1; i < onewordsuggestioncount; i++) {
                                        String onesuggestion = allsuggestions.get(i);
                                        suggestionbuilder.append(", ");
                                        suggestionbuilder.append(onesuggestion);
                                    }
                                    String onewordsuggestions = suggestionbuilder.toString();
                                    tfSuggestions1.setText(onewordsuggestions);
    
                                } else {
                                    // No suggestions for this mistake
                                    tfSuggestions1.setText("No suggestions");
                                }
                                btNextWrongWord.setEnabled(true);
    
                                // See if the ActionListener for getting the next wrong word and suggestions
                                // has already been defined. Unregister it if it has, so only one action listener
                                // will be registered at one time.
    
                                if (nextWord != null) {
                                    btNextWrongWord.removeActionListener(nextWord);
                                }
    
                                // Define the ActionListener (already instantiated as a private field)
                                nextWord = new ActionListener() {
    
                                    //Initialize a variable to track the index of the allwrongwords list
    
                                    int wordnumber = 1;
    
                                    public void actionPerformed(ActionEvent e) {
                                        if (wordnumber < no_of_mistakes) {
    
                                            // get wrong word in index position wordnumber in allwrongwords
                                            String onewrongword = allwrongwords.get(wordnumber).getWord();
    
                                            //next part is same as code for first wrong word
    
                                            tfWrongWord1.setText(onewrongword);
                                            int onewordsuggestioncount = allwrongwords.get(wordnumber).getSuggestionCount();
                                            if (onewordsuggestioncount > 0) {
                                                List<String> allsuggestions = allwrongwords.get(wordnumber).getSuggestions();
                                                String firstsuggestion = allsuggestions.get(0);
                                                StringBuilder suggestionbuilder = new StringBuilder(firstsuggestion);
                                                for (int j = 1; j < onewordsuggestioncount; j++) {
                                                    String onesuggestion = allsuggestions.get(j);
                                                    suggestionbuilder.append(", ");
                                                    suggestionbuilder.append(onesuggestion);
                                                }
                                                String onewordsuggestions = suggestionbuilder.toString();
                                                tfSuggestions1.setText(onewordsuggestions);
                                            } else {
                                                tfSuggestions1.setText("No suggestions");
                                            }
    
                                            // increase i by 1
                                            wordnumber++;
    
                                        } else {
                                            // No more wrong words! Disable next word button
                                            // Enable Check button
                                            btNextWrongWord.setEnabled(false);
                                            btCheck.setEnabled(true);
                                        }
                                    }
                                };
    
                                // Register the ActionListener
                                btNextWrongWord.addActionListener(nextWord);
    
                            } else {
                                // The text has no mistakes
                                // Enable Check button
                                tfWrongWords.setText("No wrong words");
                                tfSuggestions1.setText("No suggestions");
                                tfWrongWord1.setText("--");
                                btCheck.setEnabled(true);
    
                            }
                        } catch (Exception ex) {
                            ex.printStackTrace();
                        }
    
                        // Clear the progress bar
                        pbProgress.setIndeterminate(false);
                        pbProgress.setString("");
                    }
                });
    
            }
        };
    
        java.util.concurrent.Future result = port.checkTextBodyV2Async(bodyText, asyncHandler);
        while (!result.isDone()) {
            try {
    
    
                //Display a message that the application is waiting for a response from the server
                tfWrongWords.setText("Waiting...");
                Thread.sleep(100);
            } catch (InterruptedException ex) {
                Logger.getLogger(MainForm.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
  8. Press Ctrl-Shift-I and fix imports. This adds the following import statements:
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.util.List;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    import javax.swing.SwingUtilities;
You can now build and run the application! Unfortunately, you are unlikely to see what happens during a long delay in getting a response from the server, because the service is quite fast.