Building Your Own SOAP Client and Reporting Tool
Building Your Own SOAP Client and Reporting Tool
Sep. 26, 2003 12:00 AM
If your company is like most, it is likely that your suppliers, vendors, distributors, and partners have exposed dozens of Web services for your use.
What do you do if you want to try several Web services before deciding whether to integrate them with your IT environment, and you don't have the time to write a client for each? And what is the best way to handle verbose results that make it difficult to extract the information that is meaningful to your company?
Although some companies let you download free tools to invoke Web services, they generally don't give you much understanding of how a request is generated and usually won't go beyond showing you a raw response. You may want to roll up your sleeves and explore the many standards and APIs such as SAAJ and XSLT that are available to see how you can invoke Web services and generate useful reports. During this process you can begin building a framework for integrating Web services into your environment.
In this article we'll describe how to develop a generic tool that allows you to select the WSDL file of any Web service, provide the required input when prompted, run the Web service to view the result, and construct a report containing only the data of interest to you. Our generic tool, which we will call WSClient for the purposes of this discussion, uses industry standards and readily available Java APIs such as WSDL4J, SAAJ, Castor, JDOM, and XSLT.
When we select an operation, our tool will create a dummy XML message that conforms to the operation schema. We can then fill in the input values and click the Execute button to run the Web service. WSClient will then send a SOAP message to invoke the Web service and display the response, which will be a valid result or a SOAP fault describing a failure.
Let's look at how we'll load the WSDL file, create sample XML input, invoke the Web service through SOAP, and generate a report from the response.
WSDL Parsing and Analysis
WSDL describes Web services by providing the details of the communication requirements necessary for a client to invoke the Web service. Specifically, WSDL is an XML model that describes the messages that need to be exchanged between a client and a service provider. Additionally, WSDL describes how and where a Web service is invoked.
A WSDL document uses the elements shown in Table 1 for defining a Web service.
Each element will be used to supply the information we need to invoke a Web service. WSClient will use IBM's Web Services Description Language for Java Toolkit (WSDL4J) to programmatically analyze the structure of the WSDL and identify the operations available for consumption. WSDL4J is the open source reference implementation of the Java APIs for WSDL (JWSDL) being developed under the Java Community Process.
Our demonstration Web service is named "XigniteQuotes" and is available to the public from Xignite, Inc. The XigniteQuotes Web service returns a full month of historical quotes for any U.S. Equity. (You can view the WSDL for this Web service at www.xignite.com/xquotes.asmx?WSDL.) WSClient will be able to read this service description to get the details required to consume this Web service.
Finding the Services and Operations
The Definition interface defines the methods we need to begin analyzing the WSDL definition and makes it possible to programmatically discover the defined services, their operations, the data types, and the service's endpoint URI.
Now that we have an in-memory definition of the WSDL document, we ask for the services that are defined. The Definition interface's getServices() method returns a collection of Service instances that our tool will iterate. Each Service instance will contain a group of related ports, and each port is represented as an instance of the Port interface. From the Port instance we can discover the binding referred to by the defined port. A binding is represented as an instance of the Binding interface, which gives us information on the binding operations that are represented as instances of the BindingOperation interface (see Listing 1).
Finding the Parts
The defined operation is represented as an instance of the Operation interface that is obtained by calling the BindingOperation's getOperation() method. The message structures of the operation's input and output are accessible as Message objects. Message definitions are obtained by calling the getMessage() method defined on the Input and Output interfaces.
The Message interface defines a method named getParts() to retrieve the SOAP parts that have been defined for this message. A message part is represented as an instance of the Part interface. The Part interface defines methods for retrieving a part's name, element name, and data type name (see Listing 2).
We can use this information to get the associated schema for each message part. This allows us to construct the request message to be sent to the Web service and to process the response generated by the invocation.
Creating Sample XML Input
In our sample WSDL document our <types> element contains the schema shown in Listing 3.
For each complex message part, we will refer to this schema to build an XML message that will be passed as part of the SOAP message sent during the Web service invocation. If we expect that the response part will be of a complex type we can refer to the type defined in the schema to process the response message.
The WSClient's ComponentBuilder class defines a method named buildMessageText() that takes as its input a WSDL4J Message instance. From the Message object we can obtain the list of parts that define the message. The parts are iterated and sample input text is built for the message parts. For each part processed we check to see if there is a complex type defined for it in our Castor Schema Object Model.
For each message part, we generate an initial XML instance that can be used to invoke the Web service. For example, our demonstration Web service takes as the request message the element named "GetQuotesHistorical". Using the element defined in the schema above an appropriate input message would be:
This generated message is then saved to our OperationInfo instance and is then used as the initial message to be sent when we invoke the service (see Listing 4).
The sequence of consuming a Web service from our SAAJ client will be:
We create the connection by calling the SOAPConnectionFactory's newInstance() method. We then create a new SOAPMessage instance using SAAJ's MessageFactory class. The SOAPMessage instance created by the SAAJ factory comes initialized with a pre-defined SOAPPart that contains a SOAPEnvelope (see Listing 5).
In addition, the SOAPEnvelope comes prebuilt with an empty SOAPHeader and SOAPBody. The SOAPHeader is optional. Our example doesn't pass a SOAPHeader, so we will remove it from the envelope when building the request.
Invoking the Web Service
Once we've added the request content to the SOAPBody we can invoke the service. The final steps are to create the SOAPAction header and a URLEndpoint that points to the service's target URL. We give the Connection instance our populated SOAPMessage and the URLEndpoint and invoke the Connection's call() method. The call() method returns the XML response as a SOAPMessage (see Listing 7).
Making Sense Out of the Response
It is important to note that users do not have to write this script themselves. Using a generic XSLT script, the tool automatically generates the script for this particular Web service from the WSDL file. This generic script knows how to traverse a WSDL file and extract the structure of the response message. It is aware of the XML Schema elements such as ComplexType, Sequence, All, Group, minOccurs, maxOccurs, etc. Using this information it infers when to display items as text fields and when to create tables.
The reporting process can be summarized as follows:
The generic script processes the entire response and presents it in an HTML format, which may turn out to be very verbose. Because of this the tool displays the schema of the response, so users can visually select the elements of interest. This will generate a smaller XSLT script that will extract only the pertinent information from the response and present it as a report.
The generic script can be extended using richer XSLT semantics and formatting objects. This will enable us to transform the response into any format, including HTML, PDF, Word, or another XML document (see Figure 1).
WSClient is a useful mechanism for trying Web services. As we have seen you can use it to invoke any Web service and generate easy-to-read reports based on the response.
Our tool also can be used as a first step towards integrating Web services. Users can create a named scenario by specifying a WSDL file, the input XML (which is configurable), and an optional XSLT script. Through an API, the tool can be programmatically instructed to run the scenario identified by its name and return the result. This localizes the complexity of dealing with Web services in the tool and encapsulates the complexity from the invoking program. If used properly, this tool can help you make the transition from tentative evaluation of Web services to their complete adoption.
Reader Feedback: Page 1 of 1
SOA World Latest Stories
Subscribe to the World's Most Powerful Newsletters
Subscribe to Our Rss Feeds & Get Your SYS-CON News Live!
SYS-CON Featured Whitepapers
Most Read This Week