SOSS is an implementation of a SOAP server for OCaml.
It is designed to allow a service, developed in OCaml, to be made available as a SOAP service with minimal effort.
It's features include:
It is possible to write a series of service functions in pure OCaml without regard to SOAP and, from the interface file for the service automatically generate all that is required to reveal the service as a SOAP service through HTTP or TCP.
It is not, however, a completely general SOAP server. It's goal is as above, to define an OCaml service and reveal it as a SOAP service. As such it provides no support for more general SOAP features, such as SOAP with attachments.
Version 0.1.03 has been released.
Main changes since 0.1:
Documentation on this site is always more up to date than that in the current release.
There is a bug in the version 0.1 implementation of genInterface (not the
current release). genInterface will currently state that it requires
specification of OutputAppModule. To work around this bug,
please change the line
GenApp=true
in the default configuration file to
GenApp=false
I am very keen to make this a useful library for OCaml developers, so please,
if you have any questions or problems with the library, don't hesitate to
contact me:
stefanlampe at hotmail.com
SOSS requires a few things to be installed before it itself can be installed. SOSS has only been tested on linux.
Utilities it requires:
All utilities should be in the path
Libraries it requires:
All libraries should be locatable through the ocamlfind utility.
SOSS has been tested with these versions of the utilities and libraries:
If all of these are installed, cd to the root directory of the unpacked archive and run 'omake'
The soss library is in the lib directory
The interface generator, genInterface is in the bin directory
The example is in the bin/example directory
This installation procedure has not been thoroughly tested, if there are any issues, tell me (stefanlampe at hotmail.com), and I'll try to address them quickly.
An example is provided with the installation, a simple calculator service has been written to show the principles of the SOSS system.
Briefly, a service is simply an interface file for a module. In the interface are the types and functions that can be called remotely.
Once this module and interface has been created, a utility, genInterface, is used to create mapping code for the types and SOAP messages.
A short application module must be written. This does three things:
That's it! Compile and link and the SOAP server can be run.
The OCaml SOAP service is defined, as far as SOSS is concerned, with an interface file. This details the types and functions to be made available in the SOAP service. As such there are restrictions on the generality of the interface.
The first restriction is that types must be fully defined. There can be no types that take type parameters. References to types in other files cannot be made, the definition must be in the interface.
A list of the limitations on types is:
ignores parameterised types, exceptions, type aliases,
types accessing other modules, function types, class types, labelled
types, optional labelled types, object types, polymorphic types,
variant types (though concrete types are supported)
The second restriction is on the function declarations. Types must be
specified completely, and each type must be a type identifier. It is not
possible to have a function such as
val f : string list -> int option
This must be changed to
type stringList of string list
type intOpt of int option
val f : stringList -> intOpt
Labelled parameters are supported, but optional types are not.
Once the interface has been defined it is possible to generate automatically all the code required using the genInterface tool supplied in the install. (SOSS_INSTALL/bin/genInterface.opt)
The files generated by genInterface consist of:
It is not truly necessary to understand the representation that SOSS uses for XML data, but only to understand that conversion routines must be generated to translate between XML values and OCaml values. These routines are generated in the interface module.
The XML schema defines types for the XML values transferred in the use of the SOAP service. This file is also necessary for test the validity of the WSDL files.
These define the service in a WSDL file. 2.0 support can only be tentative as the specification is not yet finalised. It should be possible to generate client code in another language from the WSDL files produced.
In fact, the example does just this using Java and Axis to generate a lot of the client code.
There are a number of configuration options necessary to generate all the
files above. To specify these options, a configuration file is used. The
genInterface application can supply a default configuration file that
shows the available options and gives a brief explanation of them. To
obtain this, run the following command in the directory containing the
OCaml service interface file:
genInterface -gen_config
This will create a genInterface.conf file. Examine this file and set the options required. Note that it is not necessary to generate all the files that are possible to generate and that some options are not required for all files. The genInterface utility will alert you if an option has not been set which should have been set.
When genInterface is run, the source for the interface and application will be generated in the current working directory. It is now possible to build the service.
SOSS uses Ocamlduce to a large extent.
It is often possible to avoid compiling your service with OCamlduce, however.
The only case where this is not immediately possible is when the service generates SOAP faults. In this case the service must be compiled with OCamlduce, with reference to the soss library.
If it is necessary to compile with OCaml, it may be possible to move the error generation to a separate module. (i.e. create a module specifically for generating the SOAP faults from your service, that the rest of the service calls. Compile that module with OCamlduce. Then, it should be possible to compile the rest of the service with OCaml).
Whether or not the service is compiled with OCamlduce, it is always necessary to link with it.
It is assumed then that the build consists of a number of units:
The SOSS library doesn't rely on any other of these units, so it may be
placed first in the build. (It is possible the service modules do rely
on the SOSS library as it can generate SOSS faults). The service modules
don't depend on the interface or the application, so it can be placed
second in the build. The interface comes next, and finally, the application.
ocamlducec <soss lib> <service modules> <service interface>
<service app>
The SOAP server can now be run.
The SOSS SOAP server comprises a number of separate modules.
The first, the front end, is the server - HTTP or TCP. These are minimal servers that collect requests and return responses. When setting up the SOSS system, the module required can be specified.
Both these servers can accept multiple connections, and process multiple connections at one time. However, if multiple requests are received through the one connection, they are not processed concurrently, but sequentially. This is because there is no information in the SOAP messages to indicate that the response belongs to a particular request. So the first request in leads to the first response out.
SOAP over HTTP is a standard way to present a SOAP service. TCP is not so standard. It is not possible to indicate the end of a SOAP message without doing at least a minimum of parsing of the data being received. As such the TCP server relies on the SOAP message being terminated with a zero byte of data. It is important to remember this if building a client connecting to the service over TCP.
When a request is received, it is passed to the SOAP handler. There are two SOAP handlers available, a single-threaded handler and a multi-threaded handler. The single threaded handler processes all requests sequentially, in the one thread. This ensures that the service is never exposed to more than one thread of execution at a time. If the service is thread safe, however, it is possible to allow each request received to execute in its own thread by using the multi-threaded handler.
The only case where the service code may need to be aware of the SOSS library surrounding it is in the case of errors. Most SOAP errors are handled by the SOSS library and the generated interface code. However, it is possible to generate a SOAP error from within the service by raising a SoapFault. Please look at the API documentation for more information on these faults.
The function to use is SoapService.startService. This requires four parameters, an indication of the server type (tcp or http), the type of soap handler (single threaded or multi threaded) a 'registerService' function, and a port to run the server on.
The registerService function is part of the generated interface. If the
interface module is called 'IntfModule', the registerService function is
IntfModule.registerService
The function returns the service. This can be passed to
SoapService.stopService
to stop the server. It will try to stop politely, after current requests
have completed.