Introduction
WSDL file describes webservices. Java classes are often generated from WSDL. For this purpose, we could use command line tools (e. g. wsdl2Java or wsimport) or using maven plugin.
From the other side, we have Apache Karaf which is OSGI container. Karaf has installed by default many deployers for creating OSGi bundles from files, e. g. Blueprint deployer, Spring deployer or War deployer.
It is easy to generate java classes from WSDL file and also to create custom deployer for Karaf, so why do not join these two features?
Installation of WSDL deployer
Source code of my WSDL deployer is provided here. You can download and build it:
mvn clean install
We also need Karaf. I will use the newest version 4.0.5. It could be download from Karaf website. When you download and unpack it, you can run it:
$ cd PUT_PATH_TO_KARAF_DIR_HERE $ ./bin/karaf __ __ ____ / //_/____ __________ _/ __/ / ,< / __ `/ ___/ __ `/ /_ / /| |/ /_/ / / / /_/ / __/ /_/ |_|\__,_/_/ \__,_/_/ Apache Karaf (4.0.5) Hit '<tab>' for a list of available commands and '[cmd] --help' for help on a specific command. Hit '<ctrl-d>' or type 'system:shutdown' or 'logout' to shutdown Karaf. karaf@root()>
and install commons-io and wsdl-delpoyer bundles:
karaf@root()> install -s mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.commons-io/1.4_3 Bundle ID: 52 karaf@root()> install -s mvn:com.github.alien11689.karaf/wsdl-deployer/1.0.0-SNAPSHOT Bundle ID: 53
Install WSDL from Karaf shell
I will test deployer using WSDL file named exampleService-2.0.0.wsdl
(provided WSDL is similar to this, but has another namespace in types schama for testing purpose):
<?xml version="1.0"?> <wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://Example.org" xmlns:sns="http://Example.org/schema" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsap="http://schemas.xmlsoap.org/ws/2004/08/addressing/policy" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msc="http://schemas.microsoft.com/ws/2005/12/wsdl/contract" xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:wsa10="http://www.w3.org/2005/08/addressing" xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex" targetNamespace="http://Example.org" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"> <wsdl:types> <xsd:schema targetNamespace="http://Example.org/schema" elementFormDefault="qualified" > <xsd:element name="Add"> <xsd:complexType> <xsd:sequence> <xsd:element minOccurs="0" name="a" type="xsd:int" /> <xsd:element minOccurs="0" name="b" type="xsd:int" /> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="AddResponse"> <xsd:complexType> <xsd:sequence> <xsd:element minOccurs="0" name="result" type="xsd:int" /> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="Subtract"> <xsd:complexType> <xsd:sequence> <xsd:element minOccurs="0" name="a" type="xsd:int" /> <xsd:element minOccurs="0" name="b" type="xsd:int" /> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="SubtractResponse"> <xsd:complexType> <xsd:sequence> <xsd:element minOccurs="0" name="result" type="xsd:int" /> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:schema> </wsdl:types> <wsdl:message name="ICalculator_Add_InputMessage"> <wsdl:part name="parameters" element="sns:Add" /> </wsdl:message> <wsdl:message name="ICalculator_Add_OutputMessage"> <wsdl:part name="parameters" element="sns:AddResponse" /> </wsdl:message> <wsdl:message name="ICalculator_Subtract_InputMessage"> <wsdl:part name="parameters" element="sns:Subtract" /> </wsdl:message> <wsdl:message name="ICalculator_Subtract_OutputMessage"> <wsdl:part name="parameters" element="sns:SubtractResponse" /> </wsdl:message> <wsdl:portType name="ICalculator"> <wsdl:operation name="Add"> <wsdl:input wsaw:Action="http://Example.org/ICalculator/Add" message="tns:ICalculator_Add_InputMessage" /> <wsdl:output wsaw:Action="http://Example.org/ICalculator/AddResponse" message="tns:ICalculator_Add_OutputMessage" /> </wsdl:operation> <wsdl:operation name="Subtract"> <wsdl:input wsaw:Action="http://Example.org/ICalculator/Subtract" message="tns:ICalculator_Subtract_InputMessage" /> <wsdl:output wsaw:Action="http://Example.org/ICalculator/SubtractResponse" message="tns:ICalculator_Subtract_OutputMessage" /> </wsdl:operation> </wsdl:portType> <wsdl:binding name="DefaultBinding_ICalculator" type="tns:ICalculator"> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" /> <wsdl:operation name="Add"> <soap:operation soapAction="http://Example.org/ICalculator/Add" style="document" /> <wsdl:input> <soap:body use="literal" /> </wsdl:input> <wsdl:output> <soap:body use="literal" /> </wsdl:output> </wsdl:operation> <wsdl:operation name="Subtract"> <soap:operation soapAction="http://Example.org/ICalculator/Subtract" style="document" /> <wsdl:input> <soap:body use="literal" /> </wsdl:input> <wsdl:output> <soap:body use="literal" /> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="CalculatorService"> <wsdl:port name="ICalculator" binding="tns:DefaultBinding_ICalculator"> <soap:address location="http://localhost/ICalculator" /> </wsdl:port> </wsdl:service> </wsdl:definitions>
We could install it via command:
karaf@root()> install -s wsdl:file:PUT_PATH_TO_WSDL_HERE/exampleService-2.0.0.wsdl\$package=org.github.alien11689.example&s1=http://Example.org/schema&t1=org.github.alien11689.example.schema Bundle ID: 54
File must have format ${bundleSymbolicName}-${version}.wsdl
.
Provided options are:
package
- allows to change package of generated interface- pair
s1
andt1
- maps schema in WSDL to package (WSDL deployer is in draft verion nowadays provides options to map only one schema).
Karaf has installed this file:
karaf@root()> headers 54 Bundle 54 --------- Manifest-Version = 2 Bundle-ManifestVersion = 2 Bundle-SymbolicName = exampleService-2.0.0.wsdl Bundle-Version = 2.0.0 Export-Package = org.github.alien11689.example.schema;version=2.0.0, org.github.alien11689.example;version=2.0.0 Import-Package = javax.jws, javax.jws.soap, javax.xml.bind.annotation, javax.xml.namespace, javax.xml.ws
Install WSDL by putting it into Karaf drop folder
You can also install WSDL file by copying it to deploy
directory:
cp PUT_PATH_TO_WSDL_HERE/exampleService-2.0.0.wsdl PUT_PATH_TO_KARAF_DIR_HERE/deploy/deployedExampleService-2.0.0.wsdl
It is much more simple to do, but do not allow for customization (e. g. namespace to package mapping). It creates bundle:
karaf@root()> list | grep deployedExampleService 55 | Active | 80 | 2.0.0 | deployedExampleService-2.0.0.wsdl karaf@root()> headers 55 Bundle 55 --------- Manifest-Version = 2 Bundle-ManifestVersion = 2 Bundle-SymbolicName = deployedExampleService-2.0.0.wsdl Bundle-Version = 2.0.0 Export-Package = org.example;version=2.0.0, org.example.schema;version=2.0.0 Import-Package = javax.jws, javax.jws.soap, javax.xml.bind.annotation, javax.xml.namespace, javax.xml.ws
How does it work?
Deployer uses wsimport
command to create in temporary directory and compile generated java classes. Compiled class are packed with MANIFEST.MF
into service.jar
and such jar is really installed in OSGi container. For example, my temporary directory is /tmp/4ff81631-3c08-487a-b731-1f95c568026f
:
$ tree /tmp/4ff81631-3c08-487a-b731-1f95c568026f /tmp/4ff81631-3c08-487a-b731-1f95c568026f ├── Jaxb-binding.xml ├── Jaxws-binding.xml ├── service.wsdl ├── src │ └── org │ └── github │ └── alien11689 │ └── example │ ├── CalculatorService.java │ ├── ICalculator.java │ └── schema │ ├── Add.java │ ├── AddResponse.java │ ├── ObjectFactory.java │ ├── package-info.java │ ├── Subtract.java │ └── SubtractResponse.java └── target ├── org │ └── github │ └── alien11689 │ └── example │ ├── CalculatorService.class │ ├── ICalculator.class │ └── schema │ ├── Add.class │ ├── AddResponse.class │ ├── ObjectFactory.class │ ├── package-info.class │ ├── Subtract.class │ └── SubtractResponse.class └── service.jar
And my service.jar
contains:
$ jar tf /tmp/4ff81631-3c08-487a-b731-1f95c568026f/target/service.jar META-INF/ META-INF/MANIFEST.MF org/ org/github/ org/github/alien11689/ org/github/alien11689/example/ org/github/alien11689/example/schema/ org/github/alien11689/example/schema/Add.class org/github/alien11689/example/schema/ObjectFactory.class org/github/alien11689/example/schema/Subtract.class org/github/alien11689/example/schema/SubtractResponse.class org/github/alien11689/example/schema/package-info.class org/github/alien11689/example/schema/AddResponse.class org/github/alien11689/example/ICalculator.class org/github/alien11689/example/CalculatorService.class
Conclusion
WSDL generation and Karaf deployers could be easily joined and simplified creation of OSGi bundles without explicite creation of jar. Provided WSDL deployer is just draft, but could be very useful when we have many WSDLs and do not want to create separate artifacts for them.
Source code of WSDL deployer is provided here.