Tuesday, August 25, 2009

Web services in Java using Apache Axis2

Dear Reader,

WebService is basically an application which allows communication between two software components. 
It means both the software components(client and server here) should understand a common language format, then 
only they can talk to each other. 

So, the basic Web services platform is XML + HTTP. All the standard Web Services works using following components:
    a. SOAP (Simple Object Access Protocol)
    b. UDDI (Universal Description, Discovery and Integration)
    c. WSDL (Web Services Description Language)

We are discussing here the point c. WSDL is nothing but an XML File only. So if you want to talk to a web service, 
that service must be in the form of *.wsdl. Each service has some operations. Operations are actual methods which 
are available for communication (in Java terminology: Service is a program, Operations are methods).

NOTE: In WebServices your request and response both will be of XML type and hence it must comply with SCHEMA or DTD.

Now let us see the working example from scratch. I am explaining how to create a web service and how to invoke it in 
a very simple manner in Windows OS. This is done using Apache Axis2 server.

You need:
1) Axis2 server, download it from below link and extract it in "C:\" drive. I have renamed the folder as "axis2-1.5-bin".
http://apache.ziply.com//axis/axis2/java/core/1.5.6/axis2-1.5.6-bin.zip

2) Go to "C:\axis2-1.5-bin\bin" directory. Then type "axis2server.bat", you will see:-
C:\axis2-1.5\bin>axis2server.bat
    Using JAVA_HOME C:\Program Files\Java\jdk1.5.0_13
    Using AXIS2_HOME C:\axis2-1.5
    [INFO] [SimpleAxisServer] Starting
    [INFO] [SimpleAxisServer] Using the Axis2 RepositoryC:\axis2-1.5\repository
    [SimpleAxisServer] Using the Axis2 RepositoryC:\axis2-1.5\repository
    [SimpleAxisServer] Using the Axis2 Configuration FileC:\axis2-1.5\conf\axis2.xml
    [INFO] Clustering has been disabled
    [INFO] Deploying module: addressing-1.5 - file:/C:/axis2-1.5/repository/modules/addressing-1.5.mar
    [INFO] Deploying module: metadataExchange-1.5 - file:/C:/axis2-1.5/repository/modules/mex-1.5.mar
    [INFO] Deploying module: mtompolicy-1.5 - file:/C:/axis2-1.5/repository/modules/mtompolicy-1.5.mar
    [INFO] Deploying module: ping-1.5 - file:/C:/axis2-1.5/repository/modules/ping-1.5.mar
    [INFO] Deploying module: script-1.5 - file:/C:/axis2-1.5/repository/modules/scripting-1.5.mar
    [INFO] Deploying module: soapmonitor-1.5 - file:/C:/axis2-1.5/repository/modules/soapmonitor-1.5.mar
    [INFO] Deploying module: metadataExchange-1.5 - file:/C:/axis2-1.5/lib/mex-1.5.jar
    [INFO] Deploying Web service: ArithmeticService.aar - file:/C:/axis2-1.5/repository/services/ArithmeticService.aar
    [INFO] Deploying Web service: AsynchronousService.aar - file:/C:/axis2-1.5/repository/services/AsynchronousService.aar
    [INFO] Deploying Web service: version.aar - file:/C:/axis2-1.5/repository/services/version.aar
    [INFO] Deploying Web service: WeatherService.aar - file:/C:/axis2-1.5/repository/services/WeatherService.aar
    [INFO] Listening on port 8080
    [INFO] [SimpleAxisServer] Started
    [SimpleAxisServer] Started
//This shows your server is started, now you have to create application and deploy.

3) Now open one more command prompt, go to "C:\axis2-1.5\repository\services" directory. 
This services directory is having list of all web services deployed as *.aar files. These *.aar files are actully
like JAR/WAR/EAR files which Apache Axis treats as "Apache Archive". Axis2 supports hot deployment, means
create *.aar file and paste to this directory, If server is already running, your web service will be deployed.

4) Now let us write a Java program. Create a directory anywhere in hard disk, assume "D:\axis2_example_dmodi\dmodi\". You will 
write Java code (Web service at Server side) here. This will be your service:-

//HelloWorldService.java
package dmodi;
public class HelloWorldService {
    public String sayHello(String name) {
        return "Hello, I am server.." + name;
    }

    public String sum(String n1, String n2) {
        int num = Integer.parseInt(n1) +Integer.parseInt(n2);
        return "The summation:" + num;
    }
    public String sub(String n1, String n2) {
        int num = Integer.parseInt(n1) -Integer.parseInt(n2);
        return "The substraction:" + num;
    }
    public String div(String n1, String n2) {
        int num = Integer.parseInt(n1) / Integer.parseInt(n2);
        return "The division:" + num;
    }
    public String mul(String n1, String n2) {
        int num = Integer.parseInt(n1) * Integer.parseInt(n2);
        return "The multiple:" + num;
    }
}

//Create "META-INF" folder inside "D:\axis2_example_dmodi\" and then write below code and save it as "services.xml" file and save 
//inside "META-INF". 
//services.xml: 
<?xml version="1.0" encoding="UTF-8"?>
<service name="HelloService">
    <parameter name="ServiceClass">dmodi.HelloWorldService</parameter>
    <operation name="sum">
        <messageReceiver
            class="org.apache.axis2.rpc.receivers.RPCMessageReceiver" />
    </operation>
    <operation name="sayHello">
        <messageReceiver
            class="org.apache.axis2.rpc.receivers.RPCMessageReceiver" />
    </operation>
    <operation name="mul">
        <messageReceiver
            class="org.apache.axis2.rpc.receivers.RPCMessageReceiver" />
    </operation>
    <operation name="sub">
        <messageReceiver
            class="org.apache.axis2.rpc.receivers.RPCMessageReceiver" />
    </operation>
     
    <operation name="div">
        <messageReceiver
            class="org.apache.axis2.rpc.receivers.RPCMessageReceiver" />
    </operation>
</service>

=======================================================================
That's it. Now you have to compile the Java code and create *.aar File as below:
Compilation of java code:
D:\axis2_example_dmodi\dmodi>javac HelloWorldService.java
D:\axis2_example_dmodi\dmodi>cd ..

//Creating Service file(.aar):-
D:\axis2_example_dmodi>jar -cvf HelloService.aar META-INF\services.xml dmodi\HelloWorldService.class
added manifest
adding: META-INF/services.xml(in = 895) (out= 212)(deflated 76%)
adding: dmodi/HelloWorldService.class(in = 1056) (out= 497)(deflated 52%)

---HelloService.aar created.

Now drop this HelloService.aar into "C:\axis2-1.5-bin\repository\services" folder. It will be automatically deployed 
if server is running else start the server (Command: C:\axis2-1.5\bin>axis2server.bat).

//Open browser and type:- http://localhost:8080/axis2/services/HelloService?wsdl
//localhost: can be replaced with IP address of your system. After hitting above URL, you will see the HelloService.wsdl file.
Wow, your first web service at server side is ready now.
===================================================================================================

Now since your web service is ready, you have to write a Java client to invoke it, pass some request and get the output.
After all this is what we need to do else what is the use of doing all these stuffs :-).

Writing Client:
Writing client is as simple, you just need a Java file, dependent JARs and run the Java (Client) code.
Supporting JARs are already available in the "lib" directory which comes with downloaded Apache Axis2.
For me it is in "C:\Axis2-1.5.6\lib". Here I have written Java code in Eclipse where setting classpath is too easy.
Just add all the JARs from "C:\Axis2-1.5.6\lib" directory for setting classpath in "Java Build Path" in eclipse. 
However if you don't want to add all the jar files, then below jar files are for you (check the image below):

//Client code: ArithmeticClient.java import javax.xml.namespace.QName; import org.apache.axiom.om.OMElement; import org.apache.axis2.AxisFault; import org.apache.axis2.addressing.EndpointReference; import org.apache.axis2.client.Options; import org.apache.axis2.rpc.client.RPCServiceClient; public class ArithmeticClient { public static void main(String[] args1) throws AxisFault { RPCServiceClient serviceClient = new RPCServiceClient(); Options options = serviceClient.getOptions(); EndpointReference targetEPR = new EndpointReference("http://localhost:8080/axis2/services/HelloService?wsdl"); options.setTo(targetEPR); QName opSum = new QName("http://dmodi", "sum"); //http://dmodi is the namespace, you can see while hitting WSDL. Object[] opSumArgs = new Object[] { 14,7 }; serviceClient.invokeRobust(opSum, opSumArgs); OMElement response = serviceClient.invokeBlocking(opSum, opSumArgs); System.out.println("Sum Called:"+response); opSum = new QName("http://dmodi", "mul"); opSumArgs = new Object[] { 14,7 }; serviceClient.invokeRobust(opSum, opSumArgs); response = serviceClient.invokeBlocking(opSum, opSumArgs); System.out.println("Multiple Called:"+response); opSum = new QName("http://dmodi", "sub"); opSumArgs = new Object[] { 14,7 }; serviceClient.invokeRobust(opSum, opSumArgs); response = serviceClient.invokeBlocking(opSum, opSumArgs); System.out.println("Substraction Called:"+response); opSum = new QName("http://dmodi", "div"); opSumArgs = new Object[] { 14,7 }; serviceClient.invokeRobust(opSum, opSumArgs); response = serviceClient.invokeBlocking(opSum, opSumArgs); System.out.println("Division Called:"+response); } } //Compile and Run this. Output is given below: -------------------------------------------------------- Sum Called:<ns:sumResponse xmlns:ns="http://dmodi"><ns:return>The summation:21</ns:return></ns:sumResponse> Multiple Called:<ns:mulResponse xmlns:ns="http://dmodi"><ns:return>The multiple:98</ns:return></ns:mulResponse> Substraction Called:<ns:subResponse xmlns:ns="http://dmodi"><ns:return>The substraction:7</ns:return></ns:subResponse> Division Called:<ns:divResponse xmlns:ns="http://dmodi"><ns:return>The division:2</ns:return></ns:divResponse> -------------------------------------------------------- You see, Client is passing parameter (14, 7). Web service is returning the data after doing operations in XML format. Now you need to parse the response XML to get the exact data. -------------------------------------------------------- Some more stuffs: Web service invocation by client can be done in two ways: 1) Synchronous invocation: Client will be waiting to get the response after submitting request. 2) Asynchronous invocation: Client will send the request and will not wait for response. The above example was showing Synchronous communication. One more example is given below (Synchronous itself) where we are defining our own NAMESPACE. //QuoteService.java (WebService for Server side) import java.util.HashMap; import org.apache.axiom.om.OMAbstractFactory; import org.apache.axiom.om.OMElement; import org.apache.axiom.om.OMFactory; import org.apache.axiom.om.OMNamespace; public class QuoteService { private HashMap map=null; public OMElement sayQuote(OMElement in){ HashMap map=new HashMap(); map.put("Numbers","0 to 9"); map.put("Letters","A-Z and a-z"); map.put("Name","Deepak Kumar Modi"); String name=in.getText(); String info=(String)map.get(name); OMFactory fac=OMAbstractFactory.getOMFactory(); OMNamespace omNs=fac.createOMNamespace("http://www.deepakmodi2006.blogspot.com/","deepak"); OMElement resp=fac.createOMElement("sayResponse",omNs); resp.setText(info); return resp; } } //services.xml <?xml version="1.0" encoding="UTF-8"?> <service name="QuoteService"> <description> This is a sample Web Service, designed by Deepak.Modi. </description> <parameter name="ServiceClass" locked="false"> QuoteService </parameter> <operation name="sayQuote"> <messageReceiver class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver" /> </operation> </service> //build.xml to create *.aar file <?xml version="1.0" encoding="UTF-8"?> <project name="Deepak kumar Modi" default="main" basedir="."> <property name="src.dir" value="src" /> <property name="classes.dir" value="classes" /> <property name="lib.dir" value="C:\Axis2-1.5.6\lib" /> <path id="project.classpath"> <fileset dir="${lib.dir}"> <include name="**/*.jar" /> </fileset> </path> <target name="clean"> <delete dir="${classes.dir}" /> <delete file="QuoteService.aar"/> </target> <target name="prepare" depends="clean"> <mkdir dir="${classes.dir}" /> </target> <target name="compile" depends="prepare"> <javac srcdir="${src.dir}" destdir="${classes.dir}" classpathref="project.classpath" /> </target> <target name="main" depends="compile" > <copydir src="META-INF" dest="${classes.dir}/META-INF"> </copydir> <jar jarfile="QuoteService.aar" basedir="${classes.dir}"/> <echo message="Main target completed.." /> </target> </project> //Create QuoteService.aar and deploy at the axis2 services directory. //TestClient.java import org.apache.axiom.om.OMAbstractFactory; import org.apache.axiom.om.OMElement; import org.apache.axiom.om.OMFactory; import org.apache.axiom.om.OMNamespace; import org.apache.axis2.addressing.EndpointReference; import org.apache.axis2.client.Options; import org.apache.axis2.client.ServiceClient; public class TestClient { private static EndpointReference targetEPR=new EndpointReference("http://localhost:8080/axis2/services/QuoteService?wsdl"); public static OMElement getSayHelloOMElement(){ OMFactory fac=OMAbstractFactory.getOMFactory(); OMNamespace omNs=fac.createOMNamespace("http://www.deepakmodi2006.blogspot.com/","deepak"); OMElement method=fac.createOMElement("sayQuote",omNs); method.setText("Numbers"); System.out.println(method); return method; } public static void main(String[] args){ try{ Options options=new Options(); options.setTo(targetEPR); ServiceClient sender=new ServiceClient(); sender.setOptions(options); OMElement sayQuote=TestClient.getSayHelloOMElement(); OMElement result=sender.sendReceive(sayQuote); System.out.println(result); }catch(Exception axisFault){ axisFault.printStackTrace(); } } } //Output: ------------------------------------------------ <deepak:sayQuote xmlns:deepak="http://www.deepakmodi2006.blogspot.com/">Numbers</deepak:sayQuote> <deepak:sayResponse xmlns:deepak="http://www.deepakmodi2006.blogspot.com/">0 to 9</deepak:sayResponse> ------------------------------------------------END------------------------------------------------

No comments:

Post a Comment