Introduction
I'm planning to prepare a modular version of my JavaHotel application having data access logic hidden in a stateless EJB but creating a simple EJB took me more time that I expected. On one hand it should be simple and other hand (particularly after reading this
web page) it is pretty complicated. So I created a simple Eclipse project showing all important points. Code is available
here. The purpose is:
- Create EJB stateless bean.
- Access to this bean from standalone Java application to perform JUnit tests.
- Access to this bean from another Web component.
- Share common definition without duplicating code.
Shared code
I created Eclipse general (not Java) project being a placeholder for
common definition. By virtue of Eclipse "Link source" option this code can be shared between other projects. This project contains above all the interface with business logic implemented by EJB. It is pure Java interface without any EJB annotation stuff. This share code contains also ServiceLocator class resolving access to EJB.
package com.sample.ejbcalc;
public interface IHelloCalc {
String getHello();
int add(int elem1, int elem2);
}
package com.sample.ejblocator;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import com.sample.ejbcalc.IEJBName;
import com.sample.ejbcalc.IHelloCalc;
public class EJBSampleLocator {
public static IHelloCalc construct() throws NamingException {
InitialContext ctx = new InitialContext();
Object remoteObj = new InitialContext().lookup(IEJBName.JNDIRemote);
IHelloCalc inter = (IHelloCalc) remoteObj;
return inter;
}
}
Bean implementation
Source code is available
here.
package com.ejbcalc.impl;
import javax.ejb.EJB;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import com.sample.ejbcalc.IEJBName;
import com.sample.ejbcalc.IHelloCalc;
/**
* Session Bean implementation class CalcImpl
*/
@Stateless
@EJB(name = IEJBName.JNDIRemote, beanInterface = IHelloCalc.class)
@Remote
public class CalcImpl implements IHelloCalc {
@Override
public String getHello() {
return "Hello, I'm your Calculator";
}
@Override
public int add(int elem1, int elem2) {
return elem1 + elem2;
}
}
Pay attention to all annotation stuff.
Standalone JUnit Java application
Source code is available
here. Important (Glassfish). It is necessary to add gf-client.jar to classpath. This JUnit uses EJBSampleLocator utility from shared code.
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
import com.sample.ejbcalc.IHelloCalc;
import com.sample.ejblocator.EJBSampleLocator;
public class TestEJB {
private static IHelloCalc i;
@BeforeClass
public static void setUpBeforeClass() throws Exception {
i = EJBSampleLocator.construct();
}
@Test
public void test1() {
assertEquals("Hello, I'm your Calculator",i.getHello());
}
@Test
public void test4() {
assertEquals(4,i.add(2, 2));
assertFalse(i.add(2, 2) == 5);
assertEquals(2,i.add(2, 0));
assertEquals(2,i.add(0, 2));
assertEquals(-1,i.add(2, -3));
}
}
Web component accessing EJB
Last (but not least) Web component. Source code is available
here. One
servlet reuses common ServiceLocator (like standalone application). But it is also possible to use @EJB annotation and Glassfish injects EJB directly.
package com.ejbjsp.servlet;
import java.io.IOException;
import javax.ejb.EJB;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.sample.ejbcalc.IHelloCalc;
@WebServlet("/Servlet2")
public class Servlet2 extends HttpServlet {
private static final long serialVersionUID = 1L;
@EJB
private IHelloCalc i;
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
response.getOutputStream().println("<h1>
I'm Servlet 2 </h1>
Bean greetings " + i.getHello() + "</pre&>
");
response.getOutputStream().println("<br />
<h1>
Ask Bean. What is 2 + 2 ? Bean's advice: " + i.add(2, 2) + " ! </h1>
");
response.getOutputStream().flush();
}
}