//Axis2 Web Service Client Tutorial

Axis2 Web Service Client Tutorial

Axis2 is a Java framework that provides comprehensive support for exposing and consuming web services. This short post will look at its SOAP client support and how it can be used to get a simple web service client up and running. For convenience I’ll be calling a web service that I recently built as part of another post.  If you don’t already have a web service to call you can grab the full source code for my sample service from github. Run a Maven build and deploy the WAR to your Servlet container.

What is a Web Service Client?

This post doesn’t attempt to explain the detailed inner workings of a web service client, but its still pretty useful to have an idea of what’s going on under the hood. Most web service clients provide the following

  • A client side proxy for the remote service we want to call, that allows our application to invoke a SOAP service using a simple method call. The proxy insulates our application from the intricacies of sending and receiving SOAP messages.
  • Marshalling of Java objects to XML so that application data can be converted to SOAP payloads for posting to the service endpoint.
  • Un-marshalling of XML back into Java objects so that SOAP payloads returned from the remote service can be interpreted by our application.
  • Establishing and pooling HTTP connections between client and and web service.

WSDL2Java

Axis2 provides WSDL2Java tooling that parses a WSDL to generate the client side proxies required to invoke a remote service. WSDL2Java can be run on the command line but I prefer to use a Maven plugin so that I have a fresh set of proxies generated as part of every build.

Maven Configuration

The Maven POM configuration below shows how the axis2-wsdl2code-maven-plugin can be configured to generate the required client side stubs.

<?xml version="1.0"?>  
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instan
                                    http://maven.apache.org/maven-v4_0_0.xsd">  
     <artifactId>axis2-webservice-client-sample</artifactId>  
     <modelVersion>4.0.0</modelVersion>  
     <inceptionYear>2011</inceptionYear>  
     <packaging>jar</packaging>  
     <groupId>com.blog.webservices.client</groupId>  
     <version>1.0</version>  
      <properties>  
           <axis2.version>1.6.2</axis2.version>  
           <log4j.version>1.2.16</log4j.version>  
      </properties>  
      <build>  
           <resources>  
                <resource>  
                     <directory>src/main/resources</directory>  
                     <filtering>true</filtering>  
                </resource>  
           </resources>  
           <plugins>  
                <plugin>  
                     <groupId>org.apache.axis2</groupId>  
                     <artifactId>axis2-wsdl2code-maven-plugin</artifactId>  
                     <version>1.6.2</version>  
                     <executions>  
                          <execution>  
                               <goals>  
                                    <goal>wsdl2code</goal>  
                               </goals>  
                               <configuration>  
                                    <wsdlFile>src/main/resources/wsdl/AccountDetailsService.wsdl</wsd
                                    <databindingName>adb</databindingName>  
                                    <packageName>com.blog.webservices.client</packageName>  
                                    <outputDirectory>src/main/java</outputDirectory>  
                                    <flattenFiles>true</flattenFiles>  
                               </configuration>  
                          </execution>  
                     </executions>  
                </plugin>  
                <plugin>  
                     <groupId>org.apache.maven.plugins</groupId>  
                     <artifactId>maven-compiler-plugin</artifactId>  
                </plugin>  
           </plugins>  
      </build>  
      <dependencies>  
           <dependency>  
                <groupId>org.apache.axis2</groupId>  
                <artifactId>axis2-kernel</artifactId>  
                <version>${axis2.version}</version>  
           </dependency>  
           <dependency>  
                <groupId>org.apache.axis2</groupId>  
                <artifactId>axis2-adb</artifactId>  
                <version>${axis2.version}</version>  
           </dependency>  
           <dependency>  
                <groupId>org.apache.axis2</groupId>  
                <artifactId>axis2-transport-http</artifactId>  
                <version>${axis2.version}</version>  
           </dependency>  
           <dependency>  
                <groupId>org.apache.axis2</groupId>  
                <artifactId>axis2-transport-local</artifactId>  
                <version>${axis2.version}</version>  
           </dependency>  
           <dependency>  
                <groupId>org.apache.axis2</groupId>  
                <artifactId>axis2-xmlbeans</artifactId>  
                <version>${axis2.version}</version>  
           </dependency>  
           <dependency>  
                <groupId>log4j</groupId>  
                <artifactId>log4j</artifactId>  
                <version>${log4j.version}</version>  
           </dependency>  
      </dependencies>  
 </project>

The POM configuration shown here is pretty simple. The interesting bit is the WSDL2Code configuration plugin between lines 22 and 40. The plugin is configured with the following information

  • Line 32– Location of WSDL we’re going to use for code generation.
  • Line 33 – Data binding framework we’re going to use for code generation. In this example I’ve used the standard ADB (Axis Data Binding) framework but we could easily plugin an equivalent framework like JAXB or XMLBeans.
  • Line 34 – Package name for the generated classes.
  • Line 35 – Output directory for generated classes.

Code Generation

Now that we have the POM configured the next step is to run a build and generate our classes. When we run ‘mvn clean install’ the WSDL2Code plugin will read the WSDL and invoke the Axis code generator to build a client side proxy for our service. When the build is complete our project structure should look similar to figure 1.0. You’ll notice that 2 classes were generated, both of which are explained below.

Figure 1.0 Project Structure

AccountDetailsServiceCallBackHandler

This is an abstract class that can be extend to implement a non blocking web service client. A non blocking client invokes the remote service on a separate thread and returns immediately, so as not to ‘block’ the client application while Axis waits on a response. The AccountDetailsServiceCallbackHandler abstract class should be extended to provide implementations for 2 callback methods, that are invoked by Axis once it has received a response from the service.
This non blocking approach is very useful in certain circumstances, for example, when a client application needs to call a number of different services at the same time. Rather than call each service sequentially, the client application can call multiple services simultaneously (on different threads) and handle the response from each service as it arrives, using appropriate callback implementations.

AccountDetailsServiceStub

This class acts as a client side proxy for the remote service and provides a means of building requests, invoking the service and processing responses.

Calling the Service Synchronously

The code sample below shows how we can use the generated classes to call our service synchronously. Note that the main thread will block while it waits on a response from the service.

package com.blog.samples.webservices.client;  
import java.rmi.RemoteException;  
import com.blog.webservices.client.AccountDetailsServicesStub;  
import com.blog.webservices.client.AccountDetailsServicesStub.AccountDetailsRequest;  
import com.blog.webservices.client.AccountDetailsServicesStub.AccountDetailsResponse;  

public class SynchronousWebServiceClientTest  
{  
     public static void main (String [] args) throws RemoteException  
     {  
           AccountDetailsServicesStub servicesStub = new AccountDetailsServicesStub(WebServiceCientUtils.SERVICE_ENDPOINT); 
           AccountDetailsRequest accountDetailsRequest = new AccountDetailsRequest();  
           accountDetailsRequest.setAccountNumber("12345");  
           AccountDetailsResponse accountDetailsResponse = servicesStub.accountDetails(accountDetailsRequest);  
           WebServiceCientUtils.logAccountDetails(accountDetailsResponse.getAccountDetails());  
      }  
 }

Calling the Service Asynchronously

The code sample below shows how we can call our service asynchronously. Invoking ‘startService’ on the service stub kicks off a web service request on a new thread and returns immediately so that execution of the client application is not blocked. We pass in a new instance of our callback handler to handle the web service response.

package com.blog.samples.webservices.client;  
import java.rmi.RemoteException;  
import com.blog.webservices.client.AccountDetailsServicesStub;  
import com.blog.webservices.client.AccountDetailsServicesStub.AccountDetailsRequest;  
public class AsynchronousWebServiceClientTest  
{  
     public static void main (String [] args) throws RemoteException, InterruptedException  
     {  
           AccountDetailsServicesStub servicesStub = new AccountDetailsServicesStub(WebServiceCientUtils.SERVICE_ENDPOINT);
           AccountDetailsRequest accountDetailsRequest = new AccountDetailsRequest();  
           accountDetailsRequest.setAccountNumber("12345");  
           WebServiceCientCallBackHandler callBackHandler = new WebServiceCientCallBackHandler();  
           servicesStub.startaccountDetails(accountDetailsRequest, callBackHandler);  
           Thread.sleep(5000);  
      }  
 } 

A sample callback handler implementation is shown below. Note that we implement the receiveResultAccountDetails method to handle successful responses and receiveErrorAccountDetails to handle errors. Axis2 will invoke the appropriate method depending on whether or not the web service call was successful.

package com.blog.samples.webservices.client;  
import org.apache.log4j.Logger;  
import com.blog.webservices.client.AccountDetailsServicesCallbackHandler;  
import com.blog.webservices.client.AccountDetailsServicesStub.AccountDetailsResponse;  
public class WebServiceCientCallBackHandler extends AccountDetailsServicesCallbackHandler  
{  
          private static final Logger logger_c = Logger.getLogger(WebServiceCientCallBackHandler.class);
          @Override  
          public Object getClientData()  
           {  
                return super.getClientData();  
           }  
           @Override  
           public void receiveResultaccountDetails(AccountDetailsResponse result_p)  
           {  
                super.receiveResultaccountDetails(result_p);  
                WebServiceCientUtils.logAccountDetails(result_p.getAccountDetails());  
           }  
           @Override  
           public void receiveErroraccountDetails(Exception ex_p)  
           {  
                super.receiveErroraccountDetails(ex_p);  
                logger_c.error("An error occurred calling AccountDetails Service", ex_p);  
           }  
 }  

Source Code

You can download the full source code for this tutorial here. I’m having an issue with my GitHub account at the minute but as soon as I get that sorted I’ll push the code up and add a link. If you liked the post or have questions about any of the material covered, feel free to leave a comment below.

By |2019-02-20T08:15:40+00:00January 29th, 2013|Web Services|20 Comments

20 Comments

  1. Venkatraman 11th May 2013 at 2:18 pm - Reply

    Thank you! Your tutorials are very helpful 🙂

  2. Nguyễn Sĩ Bảo Lộc 14th May 2013 at 3:49 am - Reply

    This comment has been removed by the author.

  3. Çhí Kanu 15th May 2013 at 7:22 pm - Reply

    kick ass

  4. George Trandafir 22nd August 2013 at 8:49 am - Reply

    Hello again,

    I tried your little tutorial and I am getting the following exception

    org.apache.axis2.AxisFault: org.apache.axis2.databinding.ADBException: Unexpected subelement ….
    My ws are deployed on tomcat and are working fine because they were tested using SOAPUI.

    Any ideas, please?

    George

  5. George Trandafir 22nd August 2013 at 10:09 am - Reply

    I also tested with TCPMON and the results are ok.

  6. Slammer_100 17th February 2014 at 1:07 am - Reply

    Good stuff. Surprising difficult to get a simple example out of the Axis2 documentation – more about generation and tools than about how to use the actual generated output. Thanks for your write up – right on the money

  7. Hitesh Garg 18th February 2014 at 9:19 am - Reply

    Good toturial..
    Can you please also provide the contain of AccountDetailsServiceStub,so it can be more clear

  8. King Cobra 27th April 2014 at 5:27 pm - Reply

    Brian … Stuff is very good. Need to know your source code does not have WebServiceCientUtils.java class which is being reference in Asynchronous and synchronous. One query do i need to add these classes in client project or webservice project.

  9. Hosting Raja 11th August 2014 at 9:38 am - Reply

    Well said, the post is really the freshest on this valuable topic. I fit in with your conclusions and will thirstily look forward to your next updates
    host a website | hosting

  10. Leisure Den 29th October 2014 at 6:26 pm - Reply

    Hi Brian, many thanks for this extremely useful article, this is really neat!
    Have you sorted your GitHub problem, and if so, can you please give us the URL for your source code?
    Many thanks!

  11. Rajaram 24th November 2015 at 9:52 pm - Reply

    This comment has been removed by the author.

  12. Rajaram 24th November 2015 at 9:53 pm - Reply

    Yes, I can't find that file, along with the AccountDetailsServicesCallbackHandler (even it is customized, I need the skeleton please)

  13. Raghu Vamsi 2nd February 2016 at 1:20 pm - Reply

    I dont see any response object being returned form the Asynch call…how do we get response pls?

  14. Ahmet Ozer 29th February 2016 at 12:00 pm - Reply

    Thanks a lot

  15. Unknown 31st July 2016 at 2:41 pm - Reply

    Very helpful, thanks!

  16. Umesh Kumar 17th August 2016 at 4:31 pm - Reply

    Great blogs …….it is very useful for learners.

  17. manjish 6th October 2016 at 3:51 pm - Reply

    How to use WSDL URL Instead of the WSDL File ?

  18. Mohan Babu 7th October 2016 at 5:32 am - Reply

    Have any tried to use the WSDL URL instead of file?

  19. Brian 7th October 2016 at 5:38 am - Reply

    You could navigate to the WSDL URL in a browser and then save the WSDL to a file.
    If you're creating a web service client it might be worth taking a look at a post I published a few days ago http://briansjavablog.blogspot.co.uk/2016/10/apache-cxf-contract-first-web-service.html. The second half of the post describes how you can create a web service client using Apache CXF.

  20. manjish 7th October 2016 at 8:27 am - Reply

    Thanks @Mohan Babu and @Brian I tried using the service URL in xyz?wsdltag and it worked.

Leave A Comment