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/">
- <s:schema elementFormDefault="qualified"
targetNamespace="http://webservice.devpinoy.org/">
- <s:element name="ListEmployees">
- <s:element name="ListEmployeesResponse">
- <s:element minOccurs="0"
maxOccurs="1" name="ListEmployeesResult">
<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:element name="ListDepartmentsResponse">
- <s:element minOccurs="0"
maxOccurs="1" name="ListDepartmentsResult">
<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:element minOccurs="0" maxOccurs="1" name="employeeId"
type="s:string" />
</s:sequence>
</s:complexType>
</s:element>
- <s:element name="GetEmployeeResponse">
- <s:element minOccurs="0"
maxOccurs="1" name="GetEmployeeResult">
<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. :)