Topic - HowTo Build a SOAP Web-Service on NetKernel
Topic - HowTo Build a SOAP Web-Service on NetKernel Topic - HowTo Build a SOAP Web-Service on NetKernel
from forum How To
 forum index   my profile   search 
 new topic  post reply 
moderators: pjr tab RandyKahle
HowTo Build a SOAP Web-Service on NetKernel
Joined: 7-February-2005
Posts: 397
Location: UK
Posted: 6-July-2006 12:22

HowTo Build a SOAP Service

This howto explains the steps to follow to build a SOAP web-service on NetKernel.

Specification

The service will be exposed at a URL endpoint of:

http:/localhost:8080/howto/soap/service

The service will have one port that echos back the SOAP message it recieves. The port will have the SOAP action URI:

urn:org:ten60:howto:soap:service:echo

Recipe

  1. Create a module and configure the mapping section like this:

    <mapping>
    <this>
    <match>ffcpl:/etc.*</match>
    <match>ffcpl:/resources/.*</match>
    </this>
    <import>
    <uri>urn:org:ten60:netkernel:mod:ws</uri>
    </import>
    <import>
    <uri>urn:org:ten60:netkernel:ext:dpml</uri>
    </import>
    <super />
    </mapping>

    The <this> section makes sure that resources in the /etc and /resources directories may be found in the module's address space. The imports hook-in the folloing libraries:

    urn:org:ten60:netkernel:mod:ws - provides the soap mapper and message processing tools
    urn:org:ten60:netkernel:ext:dpml - provides the DPML runtime for scripting the echo service.
  2. Import your module into the Front-End fulcrum so that it is exposed to the HTTP transport running on port 8080.
  3. Edit your module definition to export a public interface:

    <export>
    <uri>
    <match>service:(wsSOAPServer|wsdlGenerator|wsDocumentation).*?/howto/soap/service.*</match>
    </uri>
    </export>

    This rule will capture all pre-processed SOAP service requests coming from the HTTPBridge in the fulcrum module that match our service endpoint /howto/soap/service.

    The HTTPBridge will automatically treat any URL request with a path containing /soap/ as being a SOAP service request using the HTTP protocol binding. In this 'soap' mode the HTTPBridge automatically extracts the soap message from the body of the HTTP request together with the endpoint and action HTTP headers. The HTTPBridge collects all this information and presents it as a uniform active URI. For our service the Bridge will pre-process the HTTP request and issue an internal active URI request:

    service:SOAPServer
    +endpoint@http://localhost:8080/howto/soap/service
    +action@urn:org:ten60:howto:soap:service:echo
    +message@[somemessage]


    [Don't worry about the other service request types, wsdlGenerator and wsDocumentation - we'll show how these can be wired up to provide WSDL and human readable service descriptions below.]

  4. Now add this rewrite rule to your module definition.

    <rewrite>
    <rule>
    <match>service:((wsSOAPServer|wsdlGenerator|wsDocumentation).*)</match>
    <to>active:$1+config@ffcpl:/etc/SOAPServiceMap.xml</to>
    </rule>
    </rewrite>

    This rule will turn the service:wsSOAPServer request into an active:wsSOAPServer request and in the process attaches a config argument that tells active:wsSOAPServer where the SOAP service map is located. active:sSOAPServer is a specialist mapper service, its job is to route the external SOAPy requests to an internal active URI request for a service implementation.

  5. Create the SOAP service map at /etc/SOAPServiceMap.xml

    <SOAPServiceMap>
    <service>
    <name>HowTo SOAP Service</name>
    <endpoint>/howto/soap/service</endpoint>
    </service>
    <port>
    <name>Echo</name>
    <type>doc</type>
    <endpoint>/howto/soap/service</endpoint>
    <action>urn:org:ten60:howto:soap:service:echo</action>
    <int>active:dpml+operand@ffcpl:/resources/echo.idoc</int>
    </port>
    </SOAPServiceMap>

    Here the service tag contains a named endpoint matching our public endpoint URL. The port tag contains all the information needed by the wsSOAPServer to locate the internal service implementation of the echo service. So the port name is Echo, its type is 'doc' - meaning we expect document/literal soap messages (not RPC), the endpoint and action tags match our service endpoint and action specification. Finally the int tag provides the URI call to the internal implementation for the service - in this case it is a call to the DPML runtime to run /resources/echo.idoc. The wsSOAPServer will issue a request for the int URI with the addition of an argument called message containing the incoming SOAP message. Within the implementing script the message can be processed with the usual "this:param:message" syntax.

    The service map has one service tag per endpoint. Each endpoint may have any number of ports and each port must have a unique action.

  6. Implement the echo service at /resources/echo.idoc by copying and pasting this script:

    <idoc>
    <seq>
    <instr>
    <type>copy</type>
    <operand>this:param:message</operand>
    <target>this:response</target>
    </instr>
    </seq>
    </idoc>

    This script echos the message it receives back as its response. You could of course use any of NetKernels supported languages to implement this service. Just change the int service implementation URI appropriately.

  7. The service is finished. Now write a test soap client. Copy the following script into the workbench module at a location /howto/testClient.idoc

    <idoc>
    <seq>
    <instr>
    <type>wsSOAPClient</type>
    <endpoint>http://localhost:8080/howto/soap/service</endpoint>
    <action>urn:org:ten60:howto:soap:service:echo</action>
    <message>
    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Body>
    <p:message xmlns:p="urn:org:ten60:howto">Hello World</p:message>
    </soapenv:Body>
    </soapenv:Envelope>
    </message>
    <target>this:response</target>
    </instr>
    </seq>
    </idoc>

    This script uses the wsSOAPClient accessor to call the soap echo service. You can run this script at http://localhost:8080/workbench/howto/testClient.idoc

Useful patterns and tools

This howto shows how to connect an external SOAP service to an internal NetKernel implementation. The typical pattern for the internal implementation is to extract a message body part. Process it. Construct a new SOAP message. Set some body value and issue the message as the service's response.

The mod-ws module provides many utility tools for slicing and dicing SOAP messages without the pain of dealing with the XML directly. See for example wsSOAPGetBody for an 'extract by example' tool to get at a SOAP body part.

Documenting the Service

If you make a browser request for http://localhost:8080/howto/soap/service?DOC - you will see an auto-generated service description. When you call the endpoint with a ?DOC query parameter the HTTPBridge knows that this is a request for documentation and so it issues a request for service:wsDocumentation+[....]. Earlier we created a rewrite rule that mappted service:wsDocumentation to the active:wsDocumentation engine. With no arguments, this accessor simply styles the SOAP service map to a human readable HTML form.

You can serve human readable documentation for each port by adding a doc tag to the port specification. Like int, this should provide the internal URI request to a script or service that provides an HTML document describing the port. Note this *must* be an active URI since, just like the wsSOAPServer, the wsDocumentation server issues the internal request for the URI but adds the action and endpoint arguments.

If you have a strong stomach you can add a WSDL description by adding a 'wsdl' tag to the main service description tag. This should point to the internal URI of the WSDL document. A request for http://localhost:8080/howto/soap/service?WSDL will serve this WSDL service description for the endpoint. WSDL has the unique distinction amongst standards as being a service metadata format that is invariably neither human nor machine readable - well done. Call me old fashioned but I think that a well written human readable HTML engineering specification can't be beaten.

Manualy configuring the HTTPBridge to use SOAP mode

You might prefer to control the public URL endpoint interface more specifically than relying on the default /soap/ match we used above. Here's how:

  • On the public interface of your module export ffcpl:/etc/HTTPBridgeConfig.xml
  • In your module create a file /etc/HTTPBridgeConfig.xml with the following contents

    <HTTPBridgeConfig>
    <!--SOAP Service Zone-->
    <zone>
    <match>.*/mymodule/path1/path2/myservice.*</match>
    <soap />
    </zone>
    </HTTPBridgeConfig>

    Any URL request that matches this zone will be processed using the SOAP HTTP protocol binding rules - you'll have to take care of the endpoint matching and mapping in your module to work with the new soap service path.

Joined: 7-February-2006
Posts: 55
Posted: 9-July-2006 12:59
Can you please post all the files for this example? I think they would make a great example of how easy simple web services are on NK.

Carlos
Joined: 7-February-2005
Posts: 397
Location: UK
Posted: 9-July-2006 13:19
Hi Carlos. Of course!  I'll package them up and post a link in this thread.

Also you've reminded me I should point out that this tutorial assumes the use of the latest mod-ws library v1.1.0 which we posted as an update earlier this week.  More information available here:

http://www.1060.org/forum/topic/149/1
Source Code
Joined: 7-February-2005
Posts: 397
Location: UK
Posted: 9-July-2006 13:58
I've posted a working module that implements this howto:

http://www.1060.org/resources/howto/soap-service/howto-soap-1.0.0.jar

Add this module to your etc/deployedModules.xml and import into your front-end fulcrum as described in the howto.  Also included in the resources/ directory in the module is a howto-test-client.idoc that calls the echo service - copy this to your workbench module.
missing input/output definitions (?)
Joined: 22-September-2006
Posts: 1
Posted: 22-September-2006 12:31
When I used snippits of the code on this page to create my HelloWorld soap interface (mui importante!), it seemed the soapservicemap needs <messageIn/> and <messageOut/> tags in order for the ?WSDL to /not/ die a horrible death.
Is this a bug or a feature?

btw. very interesting stuff, this NK.
input/output definitions
Joined: 7-February-2005
Posts: 397
Location: UK
Posted: 29-September-2006 12:46
Hi Jos,

Welcome to the forum and sorry for the delay in replying - we have been snowed under with the Architects Weekend and subsequent commitments.

You are correct that to auto-generate the WSDL you need to supply the messageIn / messageOut fields.  We need to be more polite if they are missing!  The WSDL generator is an attempt to provide a helping hand to give a framework for a WSDL service description. It works on the idea of providing an intitial loose coupled service interface.   If you need to tighten up the interface constraint then take the generated WSDL description and tighten up the embedded XSD for the message formats.  You can then register this as the version to be served for the service description by adding a WSDL tag with the URI to your enhanced version.

Hope this helps.  Please keep posting questions.

Cheers,

Peter
 new topic  post reply  To find out about new replies to this post as they occur
please subscribe to one of these feeds:
AtomRSS moderate 
© 2003-2006, 1060 Research Limited. 1060 registered trademark, NetKernel trademark of 1060 Research Limited.