An Article On Debugging EJB Without Deployment Using NetBeans IDE

Contributed by Raguraman Krishnamurthy as part of the Win With NetBeans comptetition

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


Current Process


The process


New Process


The process

I don’t need to explain advantages of this debugging style

Scenario

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


Hurdles for debugging in IDE

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

Hurdles for debugging in IDE


Overcoming Container generated Problem using Business Interface & ServiceLocator

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

Business Interface

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

Sequence while debugging

Code Snippet. [Check inheritance hierarchy in the class diagram]

EmployeeBusinessService getEmployeeBusinessService() {
	EmployeeBusinessService service = new EmployeeServiceEJB();
	return service;
}

Sequence after deployment

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;
}

Service Locator

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


Connection pool Availability

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;
    }

Unit Testing

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

Log4j

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");

Screen shots


Setting environment variable

Debugging in IDE

Debugging ejb deployed in container

This is achieved by changing deployment.type=server