While many of the more advanced features of the emerging Web services architecture are still being built into many of the platforms, support for SOAP and WSDL in most vendors' Web services toolkits is widespread and makes binding to and using Web services straightforward. In this section, we investigate how a typical application server and can be used to deploy our simple banking example, and how it can be later consumed by a client application. The overall architecture can be seen in Figure 3-37. Figure 3-37. Cross-platform banking Web service example.The architecture for this sample is typical of Web services applications that routinely combine a variety of platforms. In Figure 3-37, we use Microsoft's .Net and Internet Information Server to host the service implementation, but we use the Java platform and the Apache AXIS Web service toolkit to consume this service and drive the application. Service Implementation and DeploymentThe implementation of our banking service is a straightforward C# class, and is shown in Figure 3-38. Figure 3-38. A simple bank Web service implementation.using System; using System.Collections; using System.ComponentModel; using System.Data; using System.Web; using System.Web.Services; [WebService(Namespace="http://bank.example.org")] public class BankService : System.Web.Services.WebService { [WebMethod] public string openAccount(string title, string surname, string firstname, string postcode, string telephone) { BankEndSystem bes = new BackEndSystem(); string accountNumber = bes.processApplication(title, surname, firstname, postcode, telephone); return accountNumber; } } Most of the work for this service is done by some back-end banking system, to which our service delegates the workload. Our service implementation just acts as a kind of gateway between the Web service network to which it exposes our back-end business logic, and the back-end systems themselves to which it delegates work it receives from Web services clients. This pattern is commonplace when exposing existing systems via Web services, and makes good architectural sense since the existing system does not have to be altered just to add in Web service support.
When deployed into our Web services platform (in this example, Microsoft's IIS with ASP.Net), the associated WSDL description of the service is generated by inspection of the implementation's interface and made available to the Web. The resultant WSDL[10] is shown in Figure 3-39.
It is important to bear in mind, that although the WSDL shown in Figure 3-39 is intricate and lengthy for a simple service, the effort required to build it is practically zero because of tool support. The only issue that this should raise in the developer's mind is that their chosen platform and tools should handle this kind of work on their behalf. WSDL should only be handcrafted where there a specific need to do something intricate and unusual that tool support would not facilitate. Binding to and Invoking Web ServicesOnce the service has been deployed and its endpoint known by consumers, clients can bind to it by using their client-side Web services toolkits to create proxies. A proxy is a piece of code that sits between the client application and the network and deals with all of the business of serializing and deserializing variables from the client's program into a form suitable for network transmission and back again. The client application, therefore, never has to be aware of any network activity and is simpler to build. Figure 3-39. Bank service auto-generated WSDL description.<?xml version="1.0" encoding="utf-8"?> <definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:bank="http://bank.example.org" targetNamespace="http://bank.example.org" xmlns="http://schemas.xmlsoap.org/wsdl/"> <types> <xs:schema elementFormDefault="qualified" targetNamespace="http://bank.example.org"> <xs:element name="openAccount"> <xs:complexType> <xs:sequence> <xs:element minOccurs="0" maxOccurs="1" name="title" type="xs:string"/> <xs:element minOccurs="0" maxOccurs="1" name="surname" type="xs:string"/> <xs:element minOccurs="0" maxOccurs="1" name="firstname" type="xs:string"/> <xs:element minOccurs="0" maxOccurs="1" name="postcode" type="xs:string"/> <xs:element minOccurs="0" maxOccurs="1" name="telephone" type="xs:string"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="openAccountResponse"> <xs:complexType> <xs:sequence> <xs:element minOccurs="0" maxOccurs="1" name="openAccountResult" type="xs:string"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="string" nillable="true" type="xs:string"/> </xs:schema> </types> <message name="openAccountSoapIn"> <part name="parameters" element="bank:openAccount"/> </message> <message name="openAccountSoapOut"> <part name="parameters" element="bank:openAccountResponse"/> </message> <portType name="BankServiceSoap"> <operation name="openAccount"> <input message="bank:openAccountSoapIn"/> <output message="bank:openAccountSoapOut"/> </operation> </portType> <binding name="BankServiceSoap" type="bank:BankServiceSoap"> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/> <operation name="openAccount"> <soap:operation soapAction="http://bank.example.org/openAccount" style="document"/> <input> <soap:body use="literal"/> </input> <output> <soap:body use="literal"/> </output> </operation> </binding> <service name="BankService"> <port name="BankServiceSoap" binding="bank:BankServiceSoap"> <soap:address location="http://localhost/dnws/BankService.asmx"/> </port> </service> </definitions> In our example, the serialization and deserialization is to SOAP from Java and back again, and is handled by a proxy generated by the Apache AXIS WSDL2Java tool. This tool parses WSDL at a given location and generates a proxy class which allows client code to communicate with that service. For example, the proxy code generated by this tool when it consumed our bank example service is shown in Figure 3-40. Figure 3-40. Apache AXIS auto-generated proxy for the bank Web service./** * This file was auto-generated from WSDL * by the Apache Axis WSDL2Java emitter. */ package org.example.bank; import java.lang.String; public class BankServiceSoapStub extends org.apache.axis.client.Stub implements org.example.bank.BankServiceSoap { // Data members removed for brevity public BankServiceSoapStub() throws org.apache.axis.AxisFault { this(null); } // Other constructors removed for brevity private org.apache.axis.client.Call createCall() throws java.rmi.RemoteException { // Implementation removed for brevity return _call; } catch (java.lang.Throwable t) { throw new org.apache.axis.AxisFault("Failure trying" + " to get the Call object", t); } } public String openAccount(String title, String surname, String firstname, String postcode, String telephone) throws java.rmi.RemoteException { // Implementation removed for brevity } } The proxy class shown in Figure 3-40 allows the client of the Web service to call its functionality with a call as simple as the likes of: bankAccountService.openAccount("Mr", "Aneurin", "Bevan", "ABC 123", "0207 123 4567") without having to worry about the fact that on the wire, the proxy has sent a SOAP message that looks like that shown in Figure 3-41 below: Figure 3-41. Proxy generated SOAP message.<?xml version="1.0" encoding="utf-8" ?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap:Body> <openAccount xmlns="http://bank.example.org"> <title>Mr</title> <surname>Bevan</surname> <firstname>Aneurin</firstname> <postcode>ABC 123</postcode> <telephone>0207 123 4567</telephone> </openAccount> </soap:Body> </soap:Envelope> At the receiving end, the bank service's SOAP server will retrieve this SOAP from the network and turn it into something meaningful (in our case C# objects) before passing it to the service implementation. The service implementation grinds away at its task, producing some result in its own proprietary format before passing it back to the underlying Web services platform to serialize its results into the appropriate network format (i.e., a SOAP message) and return it to the caller. At this point the service invocation has finished and the resources used during the execution of that service can be freed. Where's the Hard Work?For simple interactions, there isn't any hard work for the developer to do because SOAP toolkits are sufficiently advanced enough to automate this. For example, we didn't have to worry about the style of SOAP encoding or how the marshalling occurred in any of our bank account examples, even though we crossed networks, servers, and even languages and platforms. Though it may seem from these examples that Web services is an automation utopia, it is not. While it is true that for the majority of cases, simple interactions can be automated (though auto-generation of WSDL from service implementation code and auto-generation of proxies from WSDL descriptions), this is about as far as toolkits have advanced. Given that this book extends beyond this third chapter, it is safe to assume that we're going to have to roll up our shirt sleeves at some point and patch the gaps that the current set of Web services toolkits inevitably leaves. It is in these subsequent chapters where we will find the hard work! |