Introduction
Developing EJB has never been easier. If there is any change in logic it has to be packaged and redeployed into container for debugging. Here I have discussed how EJB can be tested before deploying. This is one of the goals of EJB3.0. (refer EJB3.0 spec at http://java.sun.com/products/ejb/docs.html). Source code for discussed example is also attached.
Target Audience
This document is in particular a reading material for EJB Developers and any one who has the knowledge of Java,J2EE.
Tools Used
NetBeans3.6
The process
I donât need to explain advantages of this debugging style
Let us assume we have to develop Employee Portal using EJB. Design contains an EmployeeServiceEJB and DepartmentServiceEJB. EmployeeServiceEJB gives name of the employee if employee id is passed. This EJB also returns department name of the employee if the id is passed. For that first it fetches department id from EmployeeServiceEJB which fetches department name from DepartmentServiceEJB.Let us see How it can be developed without deploying the EJBs into container.
Classes
Sequence
EmployeeServiceEJB_Skel (Name depends on the container) class will be generated while deploying into the container. It will be generated by the container.
So at the time of debugging this object is not available which makes it impossible to debug EJB without deploying.
Requirements
Container generated classes are for transaction, remoting, etc , In debugging point of view it is a delegation of call from Remote Interface to Bean class.
While debugging in IDE, work around is required to avoid calls for Skeleton Objects as they are not generated at the time of debugging
Using business interface bean method can be executed without calling container-generated classes. But however after deploying bean method should be called through these container-generated classes. This is achieved through Service locator.
Classes
Code Snippet. [Check inheritance hierarchy in the class diagram]
EmployeeBusinessService getEmployeeBusinessService() {
EmployeeBusinessService service = new EmployeeServiceEJB();
return service;
}
Code Snippet. [ Check inheritance hierarchy in the class diagram ]
EmployeeBusinessService getEmployeeBusinessService() {
Context context = getContext("emp");
EmployeeServiceHome home = null;
Object homeObject = context.lookup("emp/ejb/EmployeeServicess");
home = (EmployeeServiceHome)PortableRemoteObject.narrow(homeObject, EmployeeServiceHome.class);
EmployeeService empService = home.create();
return empService;
}
ServiceLocator makes this decision based on the environment variable. This environment variable is configured on the server or IDE. A complete service locator method_
public EmployeeBusinessService getEmployeeService() throws BaseException {
if( isServerDeployment() ){
try {
Context context = getContext("emp");
EmployeeServiceHome home = null;
Object homeObject = context.lookup("emp/ejb/EmployeeServices");
home =EmployeeServiceHome)PortableRemoteObject.narrow(homeObject, EmployeeServiceHome.class);
EmployeeService empService = home.create();
//INSTANCE OF EMPLOYEE BEAN REMOTE INSTANCE
return empService;
}catch(Exception e) {
e.printStackTrace();
throw new BaseException(e.getMessage());
}
}else{
//INSTANCE OF EMPLOYEE BEAN
return new EmployeeServiceBean();
}
}
protected boolean isServerDeployment() {
String DEPLOYMENT_TYPE = System.getProperty("deployment.type"); return ("Server".equalsIgnoreCase(DEPLOYMENT_TYPE))?true:false;
}
protected Context getContext(String appName) throws Exception {
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, INITIAL_CONTEXT_FACTORY);
env.put(Context.SECURITY_PRINCIPAL, SECURITY_PRINCIPAL);
env.put(Context.SECURITY_CREDENTIALS, SECURITY_CREDENTIALS);
env.put(Context.PROVIDER_URL, BASE_PROVIDER_URL+appName);
System.out.println("Connecting to Base URL"+ BASE_PROVIDER_URL+appName);
return new InitialContext(env);
}
Environment variable deployment.type can be set using -d option. In server start up script -ddeployment.type=server In ide java parameter -ddeployment.type=ide
Since connection pool is not available in IDE environment a direct connection is required at the time of debugging.
If code is executed in server jvm it will pickup pooled connection else a direct connection is created.
protected Connection getConnection() throws SQLException {
Connection con = null;
try {
if( isServerDeployment() ) {
con = getPooledConnection();
}else {
con = getDirectConnection();
}
}catch(SQLException sqle) {
throw sqle;
}catch (Exception e){
e.printStackTrace();
}
return con;
}
An EJB can be unit tested using JUNIT test scripts
public void testGetEmpName() throws Exception {
EmployeeBusinessService business = EmployeeServiceLocator.getInstance().getEmployeeService();
String name= business.getEmpName("1234");
assertEquals(name,"abcd");
}
if this test script is run using deployment.type=ide it will be executed inside the IDE else it will call the method in the container.ie the same script can be used to test while developing and after deployment.For this jndi.properties should be set properly
if log4j is used for logging, it has to be initialized with log4j.properties.The following code snippet does it
org.apache.log4j.PropertyConfigurator.configure("{server.dir}/log4j.properties");

This is achieved by changing deployment.type=server