Accessing a .Net webservice from a Java client

 Hmmm... Where is the code selector Keith? Anyway, I'm here to show how a .Net webservice and a Java client(in this case, a method in my JSF project) can inter-operate. Ok, I'm no C# coder. So the code I will be posting here will be a code made for me by a friend. Before we start, I'd like to explain more on what we're going to do. We are going to get the list of employees from an HR system. Let's start by taking a look at the already existing C# code.

 
using System;
using System.Data;
using System.Web;
using System.Collections;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.ComponentModel;
using System.Data.SqlClient;
 
namespace HRWebService
{
    /// <summary>
    /// Summary description for Service1
    /// </summary>
    [WebService(Namespace = "
http://webservice.devpinoy.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [ToolboxItem(false)]
    public class HRService : System.Web.Services.WebService
    {

        [WebMethod]
        public DataTable ListEmployees()
        {
            SqlConnection conn = OpenConnectionString();
            if (conn == null)
                return null;
            SqlCommand cmd = conn.CreateCommand();
            cmd.CommandText = "Select empid,firstname,middlename,lastname from employee ORDER BY firstname ASC";
            cmd.CommandType = CommandType.Text;
            SqlDataAdapter da = new SqlDataAdapter(cmd);
            DataTable dt = new DataTable("Employees");
            da.Fill(dt);
            da.Dispose();
            conn.Close();
            conn.Dispose();
            return dt;
        }

        [WebMethod]
        public DataTable ListDepartments()
        {
            SqlConnection conn = OpenConnectionString();
            if (conn == null)
                return null;
            SqlCommand cmd = conn.CreateCommand();
            cmd.CommandText = "Select id,name from department ORDER BY name ASC";
            cmd.CommandType = CommandType.Text;
            SqlDataAdapter da = new SqlDataAdapter(cmd);
            DataTable dt = new DataTable("Departments");
            da.Fill(dt);
            da.Dispose();
            conn.Close();
            conn.Dispose();
            return dt;
        }

        [WebMethod]
        public DataTable GetEmployee(String employeeId)
        {
            SqlConnection conn = OpenConnectionString();

            if (conn == null)
            {
                return null;
            }

            SqlCommand cmd = conn.CreateCommand();

            cmd.CommandText = "SELECT empid, firstname, middlename, lastname from employee WHERE empid = " + employeeId + " ORDER BY firstname ASC";
            cmd.CommandType = CommandType.Text;

            SqlDataAdapter da = new SqlDataAdapter(cmd);

            DataTable dt = new DataTable("Employee");

            da.Fill(dt);
            da.Dispose();
            
            conn.Close();
            conn.Dispose();

            return dt;
        }

        private SqlConnection OpenConnectionString()
        {
            try
            {
                System.Configuration.Configuration rootWebConfig = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("\\HRWS");
                System.Configuration.ConnectionStringSettings connString;
                connString = rootWebConfig.ConnectionStrings.ConnectionStrings["HRWSConnectionString"];
                SqlConnection conn = new SqlConnection(connString.ConnectionString);
                conn.Open();
                return conn;
            }
            catch
            {
                return null;
            }
        }
        
    }
}

I specified this as  the code-behind in a file called TimService.asmx

 

<%@ WebService Language="C#" CodeBehind="HRService.asmx.cs" Class="HRWebService.HRService" %> 

 

We can see that the above code gets a List of departments, employees or  just a single employee record then fills a DataTable with whatever record it gets from the database(Ok, it's not really like that but pretend you understand me).

 

Now, running this in debug mode would give you 3 hyperlinks that leads to the invocation of each service. On my local computer, this can be accessed by invoking the link

http://localhost:1321/HRWS/TimService.asmx

Now, there's this important stuff that we need to get from this service. Be sure that throughout this tutorial that you are running the application(ie, IIS is running). Try to invoke the following URL in your browser.

http://localhost:1321/HRWS/TimService.asmx?WSDL

You should see a bunch of XML that looks something similar to this...

 

  <?xml version="1.0" encoding="utf-8" ?>
- <wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:tns="http://webservice.devpinoy.org/" xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" targetNamespace="http://webservice.devpinoy.org/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
- <wsdl:types>
- <s:schema elementFormDefault="qualified" targetNamespace="http://webservice.devpinoy.org/">
- <s:element name="ListEmployees">
  <s:complexType />
  </s:element>
- <s:element name="ListEmployeesResponse">
- <s:complexType>
- <s:sequence>
- <s:element minOccurs="0" maxOccurs="1" name="ListEmployeesResult">
- <s:complexType>
- <s:sequence>
  <s:any minOccurs="0" maxOccurs="unbounded" namespace="http://www.w3.org/2001/XMLSchema" processContents="lax" />
  <s:any minOccurs="1" namespace="urn:schemas-microsoft-com:xml-diffgram-v1" processContents="lax" />
  </s:sequence>
  </s:complexType>
  </s:element>
  </s:sequence>
  </s:complexType>
  </s:element>
- <s:element name="ListDepartments">
  <s:complexType />
  </s:element>
+ <s:element name="ListDepartmentsResponse">
- <s:complexType>
- <s:sequence>
- <s:element minOccurs="0" maxOccurs="1" name="ListDepartmentsResult">
- <s:complexType>
- <s:sequence>
  <s:any minOccurs="0" maxOccurs="unbounded" namespace="http://www.w3.org/2001/XMLSchema" processContents="lax" />
  <s:any minOccurs="1" namespace="urn:schemas-microsoft-com:xml-diffgram-v1" processContents="lax" />
  </s:sequence>
  </s:complexType>
  </s:element>
  </s:sequence>
  </s:complexType>
  </s:element>
- <s:element name="GetEmployee">
- <s:complexType>
- <s:sequence>
  <s:element minOccurs="0" maxOccurs="1" name="employeeId" type="s:string" />
  </s:sequence>
  </s:complexType>
  </s:element>
- <s:element name="GetEmployeeResponse">
- <s:complexType>
- <s:sequence>
- <s:element minOccurs="0" maxOccurs="1" name="GetEmployeeResult">
- <s:complexType>
- <s:sequence>
  <s:any minOccurs="0" maxOccurs="unbounded" namespace="http://www.w3.org/2001/XMLSchema" processContents="lax" />
  <s:any minOccurs="1" namespace="urn:schemas-microsoft-com:xml-diffgram-v1" processContents="lax" />
  </s:sequence>
  </s:complexType>
  </s:element>
  </s:sequence>
  </s:complexType>
  </s:element>
  </s:schema>
  </wsdl:types>
- <wsdl:message name="ListEmployeesSoapIn">
  <wsdl:part name="parameters" element="tns:ListEmployees" />
  </wsdl:message>
- <wsdl:message name="ListEmployeesSoapOut">
  <wsdl:part name="parameters" element="tns:ListEmployeesResponse" />
  </wsdl:message>
- <wsdl:message name="ListDepartmentsSoapIn">
  <wsdl:part name="parameters" element="tns:ListDepartments" />
  </wsdl:message>
- <wsdl:message name="ListDepartmentsSoapOut">
.... And the List goes on...

 This is called the Web Services Description Language. Wikipedia explains it well but in my own words, the WSDL tells the calling code(the webservice client) how the method would be invoked.

 Now, on the Java end...

 
Now, head to http://ws.apache.org/axis/  and download the latest binary build. Extract it in any directory (mine is placed in C:\java-jars\axis-bin-1_4). You will need the WSDL2Java tool. Here is a link on how to use it. I had problems configuring my classpath and running this tool so I made myself a batch file to make my life easier.

In C:\java-jars\axis-bin-1_4\bin-tim I created wsdl2java.bat (note: this isn't required, I just did this because I'm having trouble running the wsdl2java tool).


My batch file looks like this

java -cp C:\java-jars\axis-bin-1_4\lib\axis.jar;C:\java-jars\axis-bin-1_4\lib\commons-logging-1.0.4.jar;C:\java-jars\axis-bin-1_4\lib\commons-discovery-0.2.jar;C:\java-jars\axis-bin-1_4\lib\jaxrpc.jar;C:\java-jars\axis-bin-1_4\lib\log4j-1.2.8.jar;C:\java-jars\axis-bin-1_4\lib\saaj.jar;C:\java-jars\axis-bin-1_4\lib\wsdl4j-1.5.1.jar org.apache.axis.wsdl.WSDL2Java %* 

the %* in the end allows me to put arguments when I invoke wsdl2java like this...

C:\java-jars\axis-bin-1_4\bin-tim http://localhost:1321/HRWS/TimService.asmx?WSDL

If you observed, the argument is the location/URL of the WSDL. Now the client stub for Java and all generated class files would be placed in org\devpinoy\webservice directory (following the java packaging convention). The reason for why we have that name also is because of this line in our HRService class

    [WebService(Namespace = "http://webservice.devpinoy.org/")]


In my case, the org folder is generated in the  C:\java-jars\axis-bin-1_4\bin-tim folder because this is where I ran the batch file.

Let's take a look at the generated files...

GetEmployee.java
GetEmployeeResponse.java
GetEmployeeResponseGetEmployeeResult.java
HRService.java
HRServiceLocator.java
HRServiceSoap.java
HRServiceSoap12Stub.java
HRServiceSoapStub.java
ListDepartments.java
ListDepartmentsResponse.java
ListDepartmentsResponseListDepartmentsResult.java
ListEmployeesResponseListEmployeesResult.java 

That makes 12 files in total. 

Now, all you have to do is make the java files visible to your classpath. Time to put these classes in use.

Assuming you have the class files imported

import org.devpinoy.webservice.HRService;
import org.devpinoy.webservice.HRServiceLocator;
import org.devpinoy.webservice.HRServiceSoap;
import org.devpinoy.webservice.ListDepartments;
import org.devpinoy.webservice.ListDepartmentsResponse;
import org.devpinoy.webservice.ListDepartmentsResponseListDepartmentsResult;
import org.devpinoy.webservice.ListEmployeesResponseListEmployeesResult;
import org.devpinoy.webservice.GetEmployeeResponseGetEmployeeResult;

you will also need to use an XML parsing API. Java already come with those

import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.w3c.dom.Node;

 

And what we want to do is to get all the List of employees. Before I present the actual code take a look at the SOAP message returned by the .Net service

  <?xml version="1.0" encoding="utf-8" ?>
- <DataTable xmlns="http://webservice.wpinventory.wp.com/">
- <xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
- <xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:MainDataTable="Employees" msdata:UseCurrentLocale="true">
- <xs:complexType>
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element name="Employees">
- <xs:complexType>
- <xs:sequence>
  <xs:element name="empid" type="xs:int" minOccurs="0" />
  <xs:element name="firstname" type="xs:string" minOccurs="0" />
  <xs:element name="middlename" type="xs:string" minOccurs="0" />
  <xs:element name="lastname" type="xs:string" minOccurs="0" />
  </xs:sequence>
  </xs:complexType>
  </xs:element>
  </xs:choice>
  </xs:complexType>
  </xs:element>
  </xs:schema>
- <diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
- <DocumentElement xmlns="">
- <Employees diffgr:id="Employees1" msdata:rowOrder="0">
  <empid>36</empid>
  <firstname>Keith</firstname>
  <middlename>Oliver</middlename>
  <lastname>Rull</lastname>
  </Employees>
- <Employees diffgr:id="Employees2" msdata:rowOrder="1">
  <empid>35</empid>
  <firstname>Java</firstname>
  <middlename />
  <lastname>Guy</lastname>
  </Employees>
- <Employees diffgr:id="Employees3" msdata:rowOrder="2">
  <empid>25</empid>
  <firstname>MyFirstName</firstname>
  <middlename />
  <lastname>MyLastName</lastname>
  </Employees>
  </DocumentElement>
  </diffgr:diffgram>
  </DataTable>

 This is basically what our webservice client would be getting. We will need to parse those and make sense out of it.


        public javax.faces.model.SelectItem[] getEmployeeIds()
        {
            SelectItem[] select = null;
            
            try
            {
                HRService locator = new HRServiceLocator();
                HRServiceSoap soapResponse = locator.getHRServiceSoap();
                
                DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
                DocumentBuilder docBuilder = dbf.newDocumentBuilder();
                
                ListEmployeesResponseListEmployeesResult listEmployeeResult = soapResponse.listEmployees(); //invoke the service                
                
                MessageElement[] listEmployeeElement = listEmployeeResult.get_any(); //get the result
 
                List<Employee> employeeList = new ArrayList<Employee>(); //make a list of employees, soon to be filled               
                
                Employee employee = null;
                
                String employeeName = null;
                

                /*start parsing*/
                for (MessageElement m : listEmployeeElement)
                {                    
                   Document document = m.getAsDocument();
                   
                   NodeList nList = document.getElementsByTagName("Employees");
                   
                   for(int i =0; i < nList.getLength(); i++)
                   {
                       Node n = nList.item(i);
                       
                       NodeList childs = n.getChildNodes();
                       
                       employee = new Employee();
                       
                       employee.setEmployeeId( Integer.parseInt( childs.item(0).getTextContent() ) );
                       
                       employeeName = childs.item(1).getTextContent() + " " + childs.item(2).getTextContent() + " " + childs.item(3).getTextContent();
                       employee.setEmployeeName(employeeName);
                       
                       employeeList.add(employee);                       
                   }
                   
                }
      
                select = new SelectItem[employeeList.size()];
                
                int i = 0;
                for (Employee e : employeeList)
                {
                    select[ i ] = new SelectItem(e);
                    select[ i ].setValue( e.getEmployeeId() );
                    select[ i ].setLabel( e.getEmployeeName() );
                    
                    i++;
                }
                
            }
            catch(Exception ex)
            {
                ex.printStackTrace();
            }
         
            return select;
        }

And that's it. :)

Published Tuesday, May 22, 2007 4:50 AM by lamia

Comments

# re: Accessing a .Net webservice from a Java client

Tuesday, May 22, 2007 8:16 AM by jokiz

i'm just using copysourceashtml for visual studio

# re: Accessing a .Net webservice from a Java client

Friday, July 18, 2008 1:29 AM by ExaritaElulty

this topic for test car

Leave a Comment

(required) 
(required) 
(optional)
(required) 

Enter the numbers above: