May 2007 - Posts
Finally my head banging to the wall is over. Unlike many examples on the internet I was trying to fill a report without using an active java.sql.Connection object. The worst thing I hated and wanted to do in my development is to realize that it's not my java code that has the problem. The problem by the way was that the generated PDF had no output.
JasperPrint jasperPrint = JasperFillManager.fillReport(inputStream, parameters);
In my jrxml file a simple tweak of the parameter
whenNoDataType="NoPages"
to
whenNoDataType="AllSectionsNoDetail"
solved the problem. Atleast for now though... The reason why I want to do this is that some of the parameters I want to supply my report would come from a webservice. It wasn't totally possible with just a JDBC connection. Whew! I'm sure people would thank me someday for posting this stuff. :)
The usual way of binding a commandLink to a command in JSF is in the form
<h:commandLink action="#{backingBean.doSomething}" value="Press Me"/>
assuming that fixedItem is a managed backing bean mapped in faces-config.xml that has a method signature
public String doSomething()
{
return "success"
}
everything would work fine. But what if I wanted to get the servlet response stream to generate a PDF, a word document or a CSV file for instance? Doing something like
public String doSomething()
{
//Do response stuff here
return "success"
}would throw an exception like
java.lang.IllegalStateException: Cannot forward after response has been committed
Before I continue, I've been warned that putting control to my JSF backing bean is generally a bad idea. Quoted from Tim Halloway of javaranch as he answered one of my posts:
Rule #1 is that if you have any
code in your backing bean that requires functionality from a web
framework, you're probably doing things wrong. That includes
java.servlet.* classes and (except for the datatable model stuff) JSF
classes.
Rule #2 is that JSF is geared towards presenting JSP
views, not generating raw data streams or doing other fancy stuff. If
you expect to produce a PDF, you're better off creating a servlet to do
that and aiming the requester at the servlet. JSF is not a "master
control program" that demands that everything be routed through it.
It's a framework for managing beans and views. Use as needed. If a
vanilla JSP, a servlet, or a Struts processor (or whatever) would
handle that part of the webapp's functionality better, use that. The
request, session and application objects managed by JSF contain no
magic that makes them different than if those objects had been created
or updated by any other J2EE-compatible code.
But for the sake of this post. We're going to be stubborn and still do the stuff. First of all, we need to create a utility I'd like to call HttpJSFUtil.
/*
* HttpJSFUtil.java
*
*/
package org.devpinoy.util.http.jsf;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
*
* @author paul.timothy
*/
public final class HttpJSFUtil
{
private HttpJSFUtil()
{
}
public static HttpSession getSession()
{
return (HttpSession)FacesContext.getCurrentInstance().getExternalContext().getSession( true );
}
public static HttpServletRequest getRequest()
{
return (HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest();
}
public static HttpServletResponse getResponse()
{
return (HttpServletResponse)FacesContext.getCurrentInstance().getExternalContext().getResponse();
}
public static Object getManagedBean(String name)
{
return FacesContext.getCurrentInstance().getApplication().createValueBinding(name).getValue( FacesContext.getCurrentInstance() );
}
public static Object getManagedBean(FacesContext fc, String name)
{
return fc.getApplication().createValueBinding(name).getValue(fc);
}
}
Right. So the next step would be... What? Surprise! We create an actionListener. That's right, as in
<h:commandLink value="Download to PDF" actionListener="#{backingBean.createReport}">
if you noticed, we didn't supply an action parameter but an actionListener instead. In you backing bean you have to add a method that has the signature
public void yourMethodName(ActionEvent event)
{
}
To see the complete sample:
public void createReport(ActionEvent event)
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
System.out.println("Listener is creating a report");
HttpServletResponse response = HttpJSFUtil.getResponse();
ClassLoader classLoader = this.getClass().getClassLoader();
InputStream inputStream = null;
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment; filename=wpinvenotry-" + new Date() + ".pdf");
response.setHeader("Cache-Control", "no-cache");
try
{
System.out.println("Loading jasper file...");
inputStream = classLoader.getResourceAsStream(jasperDir + jasperName);
Map parameters = new HashMap();
parameters.put("USER_NAME", "Lamia");
System.out.println("Filling report....");
JasperPrint jasperPrint = JasperFillManager.fillReport(inputStream, parameters);
System.out.println("Writing to stream...");
JasperExportManager.exportReportToPdfStream(jasperPrint, baos);
System.out.println("Size of output: " + baos.size() );
response.setContentLength( baos.size() );
ServletOutputStream sos = response.getOutputStream();
baos.writeTo(sos);
sos.flush();
System.out.println("Closing stream...");
inputStream.close();
}
catch(JRException jrex)
{
jrex.printStackTrace();
}
catch(Exception ex)
{
ex.printStackTrace();
}
FacesContext faces = FacesContext.getCurrentInstance();
faces.responseComplete();
}
You will have to call the faces.responseComplete() method at the end of your method or you'll get an Exception. Also, since we're only calling the backing bean as a parameter to our JSF component, there wouldn't be a need for your backing bean to implement ActionListener(like the usual way). BTW, the JasperReport stuff on the above code is problematic, it doesn't show any output and I'm wondering why. The PDF file is downloaded without any problem BTW.
I'm not sure if all DOM objects in HTML has the offsetLeft, offsetTop or offsetParent properties. Let me show you something that took me 2 days to figure out. Actually, I didn't figure it out because it was Eric Pascarello of javaranch who helped me. Let's get started
Assumming you have the following tags
<table>
<tr>
<td><a href="http://devpinoy.org/controlpanel/blogs/posteditor.aspx?SelectedNavItem=NewPost§ionid=136#"><label id="a">Menu1</label></a></td>
<td><a href="http://devpinoy.org/controlpanel/blogs/posteditor.aspx?SelectedNavItem=NewPost§ionid=136#"><label id="b">Menu2</label></a></td>
<td><a href="http://devpinoy.org/controlpanel/blogs/posteditor.aspx?SelectedNavItem=NewPost§ionid=136#"><label id="c">Menu3</label></a></td>
</tr>
</table>
And a div
<div id="submenu" style="visibility:hidden; position:absolute; right:0 ; top:0; width:0">
<table>
<tr><td>A SubMenu 1</td></tr>
<tr><td>A SubMenu 2</td></tr>
<tr><td>A SubMenu 3</td></tr>
</table>
</div>
How do you make it appear under a div? Of course we know javascript is gonna come in play here. You might be thinking about the style.left property but unfortunately the left style property won't have any value for a label tag. So let's make the div tag appear first when we hover to one of the menus. I'll be using the href beside <label id="c"> tag.
The javascript function
<script>
//untested code, you get the idea of what it's doing
function showMenu(menu)
{
if (menu != null)
{
var menuStyle = menu.style;
if (menuStyle.visibility == "visible")
{
menuStyle.visibility = "hidden";
}
else
{
menuStyle.visibility = "visible";
}
}
}
</script>
then in your href...
<td><a href="BLOCKED SCRIPTvoid(0)" onMouseOver="showMenu(submenu)" ><label id="c">Menu3</label></a></td>
that should do the trick. But it's crazy because the div would probably be placed somewhere on the upper-left corner and you know you don't like that. You want to place it under the label with id="c".
Once upon a time a javaranch member was posting in the HTML and javascript forums. He was asking a question about javascipt. Then came a man named Eric and solved his problem. Here is the solution.
We first have to modify and showMenu function
function showMenu(targetObj, menu)
{
var posX = 0;
var posY = 0;
while (targetObj != null)
{
posX += targetObj.offsetLeft;
posY += targetObj.offsetTop;
targetObj = targetObj.offsetParent;
}
posY += 5 //or any value you could think of so the meny won't overlap with the label
if (menu != null)
{
var menuStyle = menu.style;
if (menuStyle.visibility == "visible")
{
menuStyle.visibility = "hidden";
}
else
{
menuStyle.visibility = "visible";
}
}
}
finally, we have to modify our href tag
<td><a href="BLOCKED SCRIPTvoid(0)" onMouseOver="showMenu(c, submenu)" onMouseOut="showMenu(c, submenu)"><label id="c">Menu3</label></a></td>
And that's it! You could also use an image object(<img>) as long as you put an id. For example
<a href="BLOCKED SCRIPTvoid(0)" onMouseOver="showMenu(c, submenu)" onMouseOut="showMenu(c, submenu)"><img src="someimage.gif" id="showhere"></a>
hope that helps. :)
I just got in the office and turned on my computer when I noticed that I didn't have an internet connection. Now, I didn't notice if my SQLServer was already up and running that time. I changed from my current DNS to another DNS including my Alternative DNS server. Funny thing that my SQLServer suddenly couldn't connect(it used to be able to) and says

I'm using a domain account. After switching back and forth our two DNS servers trying to start the server. Even when I restart my compute, this behavior would still persist until some miracle happened and I was finally able to connect. Until now, I'm puzzled by this behavioir of sqlserver 2000. I have sp4 installed and I swear it was working right before I did the changes to the DNS. Well, atleast I could go on for the day and figure that out later.
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. :)
Right now... I feel like I'm having a different view at my career. Before (and even until now) I would create a list of the technologies I want/need to learn and put some sort of priority next to them such as
5 - Hibernate
4 - JSF
3 - SCJP
2 - Webservices
I always have this posted on my desk. But now, I feel different. I feel like it's not the technology I'm after anymore but more of the problems I want to solve using these technologies. I remember my uncle who is a musician telling me that he doesn't see playing guitar as something that's hard to do anymore... But he sees it now as an art. I feel the same now, I don't see programming or using technology as something that's hard to do anymore... I see it, as some form of art. And to be able to do good art requires patience and dedication. It may come to a time that it may also require experience. I realized that it's not enough that I'm good with Java or any other technology you're using. It's not even enough that you could formulate algorithms or design a well factored code or database. I feel that it's important to me now that I be able to apply these knowledge on various business domains such as banking, insurance, and telecommunications.
I came to this realization when I knew I was gonna work for a maintenance project (which is hell of a boring task). I guess it served me as some sort of motivation that it's not the underlying technologies that I'm gonna be using that I will learn something from. But the business process itself.
I hope I could mold myself into some highly-analytical geeky developer and not just a geeky developer.
I've been doing an internal project for my company. I had this idea of just connecting to our existing HR system to retrieve some employee records instead of creating another database table. Well, far so good. Thanks for Cruizer and Keithrull's advices on how I should implement this system as a Service Oriented Architecture. I had lots of problems at first but then there are these great tools that just simplify your task and do all the hard work for you. In this post, I will tell you about my story on how I first learned it but would not be showing any code(not until my next post about this).
Our current HR system is built on the .Net platform. So it's not uncommon that I just asked one of the .Net guys to expose one or more methods of the already existing system as a webservice. Now, I have a the serer part built for me. I have to find a way to communicate with this service and for that I would need an API. There is this poppular opensource tool just for that. You guess it, it's Apache Axis. Axis abstracts all the boring SOAP-processing stuff to its user. Almost everything is done for you in an instance. Thank God I didn't live before the pre-Axis era.
Axis comes with this tool called WSDL2Java which you run in the command line. It goes something like this
c:\>WSDL2Java -cp <AllTheDarnJarsHere> <WSDL URL>
WSDL stands for Web Service Description Language. I remember having to create a batch(.bat) file because of some classpath issues with jar files that Axis depends on. Anyway, what this does is generate the client stuff in behalf of you. All that's left is to use the generated java files which by the way is placed in the directory you called WSDL2Java in to and would have the same package name as the one you specified in the XML namespace of the WSDL. After including these java files in your classpath, you would be able to invoke the webservice methods you exposed on the server-side of the application.
That wasn't much but I hope it gave you the idea. The next time I post about this I will show all detailed steps and some code you can play with.