Kevin's Blog

IT, Java, Web, Ubuntu

Web Service Development using Tomcat and OpenEJB

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.

h&m online

Loading Facebook Comments ...
Loading Disqus Comments ...

6 Comments

  1. The Web service features in J2EE 1.4 address both the server and client sides of Web services. The features extend J2EE to allow existing server-side enterprise Java components to become Web services and specify how a J2EE client container can invoke Web services.

  2. Kevin

    11 December, 2009 at 10:51 pm

    The web service I explained here uses JSR-181. It was introduced to JCP by BEA Systems, which is now acquired by Oracle, and Java EE 5 includes it but not J2EE 1.4.
    http://jcp.org/en/jsr/detail?id=244

    JSR-181 uses annotations which were introduced in J2SE 5.0 so with just J2EE 1.4, you cannot use JSR-181.

    I don’t know why you put that comment, which is completely irrelevant to the post, here. Well, your comment has nothing to do with my blog entry although it has the word, ‘web service’. I believe you are probably a spam bot as I found that your homepage URI linked to some product list in some on-line shopping mall. Thus I removed it.

  3. Kevin,

    Sorr for this repost. This would be the correct and related thread to ask for the webservice related and , how to deploy openejb MDBean project.jar into tomcat+openejb environment !

    Thanks for your instructions based details on the openejb.
    Could you suggest the same type of details
    – How to develop the MDBean project and how to deploying openejb MDBean project.jar in to tomcat + openejb integrated environment in Linux?

    Little back ground on my side,
    We have existing webservice project developed based on axis2 in tomcat 6.0.32 using top to bottom approach.
    Now, we want to add asynchronous message processing features. So, exploring to use the JMS + MDB. To add this feature in tomcat, I am working to use the openEJB.
    And, I was trying to find best way to add on this new project by adding openEJB.war to existing tomcat.
    But, trying to simplify the steps to
    how to add the MDBean project in addition to the existing top to bottom up axis2 webservice project?
    How to deploy this new addition MDBean/openejb project.jar in to tomcat+openejb in Lunux?
    How to deploy the openejb based MDB project.jar in to tomcat+openejb ?
    How to send message object to MDBean which would also run in same tomcat having openejb.war?

    I really thankfull for your kind response.

    Subba

    • Before I say anything, I think should clarify certain things you need to know.

      1. Your explanation is insufficient to fully understand your problem so my answers would be very generic. It is very hard to answer those kinds of questions without actually having the code & libraries you have, your development environment & configuration, the scenarios that your application / service should handle, etc., and that’s one of the reasons why people hire software development consultants.

      2. I do NOT use OpenEJB at all.

      3. Then why did I post those two blog entries regarding using OpenEJB, Tomcat and Hibernate, and OpenEJB and Web Services?
      The reason is because I could not find any detailed tutorials for those technologies (you may already know it as you googled it already, I guess) so did it for others looking for it. I had some experiments and found several ways to do it and posted the simplest and easiest ones. Based on my experience, it is not convenient at all to implement those technologies. So if you decide to use it, I believe, you will experience many problems regarding only implementing those rather than solving your actual problems in the business logic (e.g. I had a problem with using OpenEJB and other versions of Hibernate than the one I mentioned in the blog post so I had to use that particular version).

      4. What do I use then? I use the Spring Framework.

      5. Does the Spring Framework solve the problems you mentioned? Yes, it does solve those easily although I don’t know the details of yours so cannot really say with one hundred percent certainty.

      6. So do I recommend it instead of using OpenEJB? Yes, I do. If you can use the Spring instead of OpenEJB, you can use almost any technologies, libraries and frameworks with the Spring so that you don’t really need to be concerned about combining different technologies together (of course, it is still not the silver bullet, you may not use it for everything, but in general, for normal applications and web services, it is just sufficient). However, you need to learn how to use it, and it might not be as easy as reading one or two blog posts to figure it out. I still recommend it though. It is useful now and will be more and more useful in the future as your application grows and its requirements change.

      Now, in regard to your questions,
      =================================
      how to add the MDBean project in addition to the existing top to bottom up axis2 webservice project?
      -You can just use OpenEJB to have both the MD Bean and web service if your axis2 web service complies with JSR-181 like this one then it will be easy to run it with OpenEJB and without Axis2.
      -Or what you want is sending SOAP messages over JMS, you probably want to use some other library for JMS working with Axis2 such as JMS Transport.

      How to deploy this new addition MDBean/openejb project.jar in to tomcat+openejb in Lunux?
      -As long as you use the Java platform and the OS you use supports it, you don’t need to worry about deploying those to the tomcat server in different OSs.

      How to deploy the openejb based MDB project.jar in to tomcat+openejb ?
      -It is up to you. You can add it to the web service you’ve already got or can make a separate message service and add it.

      How to send message object to MDBean which would also run in same tomcat having openejb.war?
      -It is also up to you. You can have both in the same project and make them directly communicate or have them separately and use message service / web service to communicate. It depends on your implementation of the technologies.
      ==================================

      Finally, mixing and combining different technologies is not an easy topic especially when you have some legacy applications with which your new applications must work. If it is for your company, I rather recommend you hire the consultant. If it is solely for studying, you can anyway try it by making message service then understand it and try to combine it with the web service. Without understanding each technology, you cannot easily use these together. Well, if I were you, I would rather spend time on studying the Spring Framework. Don’t get me wrong. I’m not a fan of it. It is just suited for my needs. One day, if I find any better one, I will definitely use the new one.

      Regards,
      Kevin

  4. Thanks for a very good tutorial.

1 Pingback

  1. ejb object

Leave a Reply

© 2014 Kevin's Blog

Theme by Anders NorenUp ↑

%d bloggers like this: