In addition to the previous post, Java EE Application Development using Tomcat, OpenEJB and Hibernate, this post will demonstrate how to create a web service using Tomcat and OpenEJB. The web service in this blog entry uses the code from the previous post, so if you haven’t read it yet, better read it first.

Firstly, create a web service interface then put the @WebService annotation.

package com.lckymn.kevin.test.openejb.webservice;

import javax.jws.WebService;

import com.lckymn.kevin.test.openejb.domain.User;

@WebService
public interface TestWebService
{
	User getUser(Long id);
}

Secondly, create a class implmenting the web service interface with also the @WebService annotation then specify the targetNamespace and the serviceName as you wish. In my case, these are

targetNamespace: "http://webservice.webhibernate.test"
serviceName: "testWebService"

To use the UserService EJB, injected by OpenEJB, make the web service class session EJB with the @Stateless annotation.

package com.lckymn.kevin.test.openejb.webservice;

import javax.ejb.EJB;
import javax.ejb.Local;
import javax.ejb.Stateless;
import javax.jws.WebService;

import com.lckymn.kevin.test.openejb.domain.User;
import com.lckymn.kevin.test.openejb.service.UserService;

@Local
@Stateless
@WebService(targetNamespace = "http://webservice.webhibernate.test", serviceName = "testWebService")
public class TestWebServiceImpl implements TestWebService
{
	@EJB
	private UserService userService;

	@Override
	public User getUser(Long id)
	{
		return userService.getUser(id);
	}
}

The class above simply returns a User entity object acquired from the UserService EJB, made in the previous post.

That’s it. You have just made your web service. When the server starts and the application is deployed, the EJB container (OpenEJB) registers the above EJB as a web service.

Now, let’s make a web service client. To make a very simple example client, I’m going to create a servlet in the same web application to which the web service belongs, yet it can of course be another web application, Java desktop application, Java console application and so on.

Here is a simple servlet which gets the user ID from the client-side then accesses the web service to get the User. After that it passes the User entity object through the HttpSession to the JSP page to display.

package com.lckymn.kevin.test.openejb.web;

import java.io.IOException;
import java.net.URL;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;

import com.lckymn.kevin.test.openejb.domain.User;
import com.lckymn.kevin.test.openejb.webservice.TestWebService;

public class TestWebServiceClientServlet extends HttpServlet
{
	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
	{
		doPost(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
	{
		Service service = Service.create(new URL("http://localhost:8080/TestWebServiceImpl?wsdl"), new QName(
				"http://webservice.webhibernate.test", "testWebService"));
		TestWebService testWebService = service.getPort(TestWebService.class);

		String userIdParam = request.getParameter("userId");

		HttpSession session = request.getSession();
		if (null == userIdParam || 0 == userIdParam.length())
		{
			session.removeAttribute("userFound");
		}
		else
		{
			Long userId = Long.parseLong(userIdParam);
			User user = testWebService.getUser(userId);
			session.setAttribute("userFound", user);
		}
		getServletContext().getRequestDispatcher("/WEB-INF/jsp/webServiceClient.jsp")
				.forward(request, response);
	}
}

This is just a simple example thus I omitted validation (e.g. checking whether the userId is ‘long’ type or not) and exception handling.

The WSDL location is the server URI + “/” + web service class name + “?wsdl”.
http://localhost:8080/TestWebServiceImpl?wsdl
The parameters of the QName constructor are namespaceURI and localPart, and these are defined in the web service. If you look at the web service code again, these can easily be found from the @WebService annotation.

@WebService(targetNamespace = "http://webservice.webhibernate.test", serviceName = "testWebService")
public class TestWebServiceImpl implements TestWebService
{
	...
}

The value of the targetNamespace element is the namespaceURI of the QName constructor, and the value of the serviceNmae element is the localPart.

This is web.xml. The information of the new servlet, the web service client just created, is added to the web.xml, made in the previous post.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>test-web-hibernate</display-name>
  <servlet>
    <description></description>
    <display-name>TestServlet</display-name>
    <servlet-name>TestServlet</servlet-name>
    <servlet-class>com.lckymn.kevin.test.openejb.web.TestServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>TestServlet</servlet-name>
    <url-pattern>/Test</url-pattern>
  </servlet-mapping>
  <servlet>
    <description></description>
    <display-name>TestWebServiceClientServlet</display-name>
    <servlet-name>TestWebServiceClientServlet</servlet-name>
    <servlet-class>com.lckymn.kevin.test.openejb.web.TestWebServiceClientServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>TestWebServiceClientServlet</servlet-name>
    <url-pattern>/TestWebServiceClient</url-pattern>
  </servlet-mapping>
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>

Finally, add a JSP file to enter the userId to search a user and to display the user info.
In my case, I added the file to the application/WebContent/WEB-INF/jsp directory which is the same location that I set in the TestWebServiceClientServlet (look at the TestWebServiceClientServlet code above).
test-web-hibernate/WebContent/WEB-INF/jsp/webServiceClient.jsp

<?xml version="1.0" encoding="UTF-8" ?>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Insert title here</title>
</head>
<body>
<div>
<form name="userForm" action="TestWebServiceClient" method="post" >
	<input type="text" name="userId" value="" /> <input type="submit" name="userIdSubmit" value="Search" />
</form>
</div>
<div>
	<table>
		<tr>
			<td>User ID: </td><td>${userFound.id }</td>
		</tr>
		<tr>
			<td>Username: </td><td>${userFound.username }</td>
		</tr>
		<tr>
			<td>Surname: </td><td>${userFound.surname }</td>
		</tr>
		<tr>
			<td>Given name: </td><td>${userFound.givenName }</td>
		</tr>
		<tr>
			<td>Email: </td><td>${userFound.email }</td>
		</tr>
	</table>
</div>
</body>
</html>

To test it, open the browser and enter the following URI.

http://localhost:8080/test-web-hibernate/TestWebServiceClient

It displays the screen like below

Enter userId and click the 'Search' button

Enter userId and click the 'Search' button


-Enter a userId to search then click the ‘Search’ button.

It displays the result yet there is one problem. It doesn’t display the userId.

The Search Result: userId is not displayed

The Search Result: userId is not displayed


This is because the id field of the User entity class that I created in the previous blog entry does not have the mutator that is the setId() method so when the entity object is passed through the web service, the id field is not included.

There are two simple ways to solve this problem. Either way works so choose whichever you like.

1. Add the setter method. If there is setId() method, the id field is included when the object is passed through the web service. The reason why I did not write the setter method is that the id is supposed to be set by Hibernate and to avoid any problems caused by setting it manually, I did not write it. However, it is required in order to include the field when passing object through the web service. So adding setter can solve this problem. If you do not like this solution as you do not like to put the setter method due to the reason I explained, you can try the second solution.

@Entity
@Table(name = "users")
public class User implements Serializable
{
	private static final long serialVersionUID = 1L;

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column(name = "user_id")
	private Long id;

	...

	public Long getId()
	{
		return id;
	}

	public void setId(Long id)
	{
		this.id = id;
	}
	
	...
}

OR

2. If you add the @XmlElement annotation to the id field and set the value of the required element to true, the id field is included even without the setter method.

...

import javax.xml.bind.annotation.XmlElement;

...
@Entity
@Table(name = "users")
public class User implements Serializable
{
	private static final long serialVersionUID = 1L;

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column(name = "user_id")
	@XmlElement(required = true)
	private Long id;

	...

	public Long getId()
	{
		return id;
	}

	// No setId() required
	
	...
}

Now, test if it works.

Enter userId and click the 'Search' button

Enter userId and click the 'Search' button

It works!

The Search Result: userId is displayed correctly

The Search Result: userId is displayed correctly

There are also other ways and tools to create a web service in Java. I used to use Apache Axis then later moved to XFire. Now, I use Apache CXF which is considered as XFire 2.0. It is, as explained here, very easy to create a web service client, yet it can be even easier with WSDL2Java from Apache Axis or WSDL2Java from Apache Axis2.