Submitted on July 22, 2008 - 03:56.
| WSF/Jython | v1.0 alpha or higher |
| JDK | v1.5 |
| Jython | v2.2 |
The solution to the requirement of exposing a Python Web service in Axis2, lies within the pluggable deployer concept of Axis2 [1]. In order to expose services written in Python, we will be writing a custom deployer together with a Python message receiver. As you may already know, Python data types are dynamic as opposed to XML, in which data types are static. Therefore, within the deployer we need to map Python data types to XML schema data types. This process is known as data binding. Thereafter, with the help of data binding and method annotations, XML Schema is generated for the Python service. Next, the XML schema generated, together with meta-data pertaining to a AxisService, and given to the Axis2 engine. Axis2 engine will create the WSDL out of it and your Python service will be exposed to the world as a Web service. If you are interested in learning more on deployers, I suggest you take a look at the article on Axis2 deployment – Custom deployers.
The message receiver consumes SOAP messages and hands them over to applications. The message receiver is the last handler in the in-pipe. For more information on Message Receivers and Axis2 Architecture, please refer this documentation.
The figure above shows the architecture of this solution. The incoming SOAP message is received by the Transport Listener and it is passed through the handler chain. Then it is given to the Jython Message Receiver, which traverse through the AXIOM structure and retrieve the relevant information needed. This retrieved information is passed in to the python service. Then the python service gets executed and the resulting object is passed back in to the Jython Message Receiver. In the Jython Message Receiver an AXIOM structure is created out of the returned python object. Then the response is sent through the handler chain to the Transport Sender. The Transport Sender sends the response to the client.
JPython was the first implementation of Python programming language in java. Then the project was moved to SourceForge and renamed Jython. Jython is a programming hybrid. It exhibits the strengths of both its parents, namely Java and Python. Since Jython is written in 100% in java , scripts written using jython will run on top of any compliant Java Virtual Machine (JVM). Jython interpreter will support many shortcuts , which will make it easy to use existing java libraries as if they were your own python modules.
We are using Jython as the medium to communicate between Python and Java. As you can already see in the architecture diagram, Jython resides in between the Jython Message Receiver and the Python script.
At the deployment time the annotations of the python script are read. Then the mapping of the dynamic Python types to static Java types are done. This process is called data binding. After corresponding matching types are mapped, an XML schema is created out of the service. Following steps describe how the XML schema is generated out of the Python service.
The generated AxisService is given to axis2 engine. Then axis2 engine generates the WSDL out of it.
Lets try to write a simple Python script that has a operation named add. It takes two input variables and returns the addition of those two numbers.
def add(var1,var2): var3 = var1 + var2 return var3
Since we have to perform XML schema generation, we must annotate our Python script. An annotated Python method is given in the example below:
#@annotate("returns=int", "operationName=add", var1="integer", var2="integer")
def add(var1,var2):
var3 = var1 + var2
return var3
When annotating a Python script, you must annotate it as it is shown in the example above. In doing so, there is a simple set of instructions to follow:
#@annotate("returns=int", "operationName=add", var1="integer", var2="integer")
When using this deployer for deploying a Python script, you must follow the guidelines given below:
<deployer extension=".py" directory="scripts" class="org.wso2.wsf.jython.deployer.PythonDeployer"> </deployer>
Let's consider another situation where a method is defined within a class. The following example illustrates such a situation.
class MyClass:
#@annotate("returns=integer", "operationName=MyClass.multiply", var1="integer", var2="integer")
def multiply(var1,var2):
return var1*var2
Then the operationName attribute of the annotation should equate to class_name.method_name
#@annotate("returns=integer", "operationName=MyClass.multiply", var1="integer", var2="integer")
#@annotate("returns=int", "operationName=addTwo", var1="integer", var2="integer", var3=(a="string", b="integer"))
def addTwo(var1,var2,var3):
return var1+var2
Assume that you are having a variable or an object which contains multiple variables. You need to pass it into your Python method. Then it should be annotated as shown below:
#@annotate("returns=int", "operationName=addTwo", var1="integer", var2="integer", var3=(a="string", b="integer")) Based on the above tutorial on annotations, we can write a simple Python service given below, and expose it as a Web service with the help of the Python deployer.
#@annotate("returns=double", "operationName=f", a="double")
def f(a):
return a
#@annotate("returns=int", "operationName=add", var1="integer", var2="integer")
def add(var1,var2):
return var1+var2
#@annotate("returns=double", "operationName=deduct", var1="double", var2="double")
def deduct(var1,var2):
return var1-var2
#@annotate("returns=int", "operationName=addTwo", var1="integer", var2="integer", var3=(a="string", b="integer"))
def addTwo(var1,var2,var3):
return var1+var2
#@annotate("returns=int", "operationName=doComplexStuff", var1="integer", var2="(a="integer", b="integer")", var3="(a="string", b="integer")")
def doComplexStuff(var1,var2,var3):
return var1
class MyClass:
#@annotate("returns=integer", "operationName=MyClass.multiply", var1="integer", var2="integer")
def multiply(var1,var2):
return var1*var2
With the addition of the Python Deployer and the Python Message Receiver explained above, Axis2/Java is now able to expose a service written Python as a Web service. The underlying deployer will read the annotations and perform data-binding, schema generation. Schema generated will be passed on to the Axis2 engine, which will then perform the WSDL generation. Thereafter, a client is able to invoke the service using the WSDL generated.
This illustrates how a user with only knowledge in Python is be able to use the powerful Axis2/Java implementation, to expose Python Web services.
[1] - http://wso2.org/library/3708
[2] - http://ws.apache.org/axis2/1_4/Axis2ArchitectureGuide.html
[3] - http://www.jython.org/
Heshan Theekshana Suriyaarachchi, Undergraduate Intern, WSO2 Inc. heshan at wso2 dot com