Mrz 16 2008

Creating generic SOAP Web Services

Published by at 9:50 PM under Java,web services



This blog is about how a generic soap web service can work. It is a productive concept which i have developed for a real world application. I tried to keep this basic concept as simple as possible.

In a future blog-entry, i will show a NetBeans example for this. Please be patient, it takes much time to create it.

Consider this scenario, you are creating a SOAP Web Service which has only one operation, it is called “processOperation()“. The Request for this operation needs 4 data type elements:

  • id : string (Customer Identification)
  • password : string (Password)
  • version : string (current Version of the Customer-Schema)
  • data : string (XML-Data or something else)


The Response has only 2 elements:

  • result : string (some result data)
  • error : string (an error message if something went wrong)



This is your WSDL and XML-Schema:


WSDL

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions xmlns:ns1="genericsoapwebservices.jdevelop.eu" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:ns="http://schemas.xmlsoap.org/soap/encoding/" name="GenericSOAPWebServices" targetNamespace="genericsoapwebservices.jdevelop.eu">
	<types>
		<xsd:schema>
			<xsd:import namespace="genericsoapwebservices.jdevelop.eu" schemaLocation="webservices.xsd"/>
		</xsd:schema>
	</types>
	<message name="processOperation">
		<part name="processOperation" element="ns1:processOperation"/>
	</message>
	<message name="processOperationResponse">
		<part name="processOperationResponse" element="ns1:processOperationResponse"/>
	</message>
	<portType name="GenericSOAPWebServices">
		<operation name="processOperation">
			<input message="ns1:processOperation"/>
			<output message="ns1:processOperationResponse"/>
		</operation>
	</portType>
	<binding name="GenericSOAPWebServicesPortBinding" type="ns1:GenericSOAPWebServices">
		<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
		<operation name="processOperation">
			<soap:operation soapAction="urn:http://blog.jdevelop.eu/services/processOperation"/>
			<input>
				<soap:body use="literal"/>
			</input>
			<output>
				<soap:body use="literal"/>
			</output>
		</operation>
	</binding>
	<service name="SOAPService">
		<port name="WebServices" binding="ns1:GenericSOAPWebServicesPortBinding">
			<soap:address location="http://blog.jdevelop.eu:80/services"/>
		</port>
	</service>
</definitions>


XML Schema

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema xmlns:ns1="http://blog.jdevelop.eu/genericsoapwebservices.xsd" xmlns:tns="genericsoapwebservices.jdevelop.eu" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="genericsoapwebservices.jdevelop.eu" version="1.0">
	<xs:element name="processOperation">
		<xs:complexType>
			<xs:sequence>
				<xs:element name="id" type="xs:string"/>
				<xs:element name="password" type="xs:string"/>
				<xs:element name="version" type="xs:string"/>
				<xs:element name="data" type="xs:string"/>
			</xs:sequence>
		</xs:complexType>
	</xs:element>
	<xs:element name="processOperationResponse">
		<xs:complexType>
			<xs:sequence>
				<xs:element name="result" type="xs:string"/>
				<xs:element name="errormessage" type="xs:string" minOccurs="0"/>
			</xs:sequence>
		</xs:complexType>
	</xs:element>
</xs:schema>



The use case is simple. A customer calls the Web Service Operation, send some data and receive an output. But now a second customer want to use your Web Service. The Problem – they already have a Web Service Client which is the standard implementation for every B2B connection in their extranet, and they don’t want to modify it to fit your needs.

They can include the required 4 data type elements in the Request, but this Request use their own XML-Schema. The data types are scattered around in the SOAP-Envelope.

For example, the elements “id“, “password” and “version” are in the SOAP-Header and the “data” is in the SOAP-Body. What a crap, our processOperation-Method cannot handle this!

Generic SOAP Web Service - simple overview


So you can now develop a special Web Service for this customer (and for each upcoming customer in the future) or you modify the current Web Service to handle this challenge.

The key for success is the modification of the SOAP-Message (described in this blog http://blog.jdevelop.eu/?p=67) with XSL Transformations (XSLT). Sounds nuts? Don’t worry, i will show you how this can work!

Take a look at this diagram:

Generic SOAP Web Services - activity diagram


At the beginning of this workflow, with the help of the ServerSOAPHandler, you must identify any incoming message, using XPath to determine which customer is the sender. In a database you have stored the infomations about the locations of the 4 data type elements in the SOAP-Envelope for every specific customer Request.

Look at this special Request:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soap="genericsoapwebservices.jdevelop.eu">
	<soapenv:Header>
		<username xmlns:soap="http://blog.jdevelop.eu/headerdata">blog</username>
		<password xmlns:soap="http://blog.jdevelop.eu/headerdata">jdevelop</password>
		<schemaVersion xmlns:soap="http://blog.jdevelop.eu/headerdata">1.1</schemaVersion>
	</soapenv:Header>
	<soapenv:Body>
		<soap:processOperation>
			<data>23</data>
		</soap:processOperation>
	</soapenv:Body>
</soapenv:Envelope>



According to your XML-Schema, the database must contain this XPath expressions to read and map the correct values:

  • id : /soapenv:Envelope/soapenv:Header/Username/text()
  • password : /soapenv:Envelope/soapenv:Header/Password/text()
  • version : /soapenv:Envelope/soapenv:Header/SchemaVersion/text()
  • data : /soapenv:Envelope/soapenv:Body/soap:processOperation/data/text()


Without this informations, your Web Service is not able to handle this Request!

If the Request is a “normal” one, which means that this customer is using your Web Service specification, the workflow can proceed to the processOperation-Method. If not, the next step is the “Technical mapping“. The System is using XSLT to transform the specific customer Request to your Web Service Schema, so that it can be used without problems from the processOperation-Method.

After processing the Operation, transforming the Response is similar to the above mentioned workflow.

With this approach you can configure every customer from your database. You don’t need to change one code of line. Just create/modify XPath- and XSLT files and add this information to your database.


All the exams more advanced than 70-640, like the 640-822 and 70-236 have high qualifying criteria’s, and that include 640-863 as well as 642-436.

Technorati Tags: , , , , ,

5 responses so far

5 Responses to “Creating generic SOAP Web Services”

  1. Anirban Majumdar sagt:

    Hi Siegfried

    Really helpful article.It you also be very helpful if you could provide a help in my scenario wherein I need to set a separate header in the SOAP request from the client-end with user-id and password and extract and validate the values at the service side using JAX-WS.
    Could you please guide me in the implementation process.

  2. Hello Anirban,
    sorry for the late answer, had to much to do.
    If you still need help, send me an email.

  3. Kasper sagt:

    Hi Siegfried

    Thank you very much for taking the time to write this article, which has been very helpfull to me.

    Best regards

  4. Gwaine sagt:

    This is brilliant!

    I was thinking of doing something similar (creating a one method web service with one data parameter) but it didn’t occur to me to add another “wrapper” webservice to provide different interfaces to the same underlying code.

    My core code will remain largely unchanged as the web services on top come and go over time.

    Thanks!
    Gwaine

  5. Paul sagt:

    This doesn’t make much sense to me.

    If you’re handling the service switching, request parsing, response construction yourself why do you need SOAP? Why not use HTTP directly?