Simplifying EJB Development with EJB 3.0

Java Development News:

Simplifying EJB Development with EJB 3.0

By Debu Panda

01 Oct 2004 | TheServerSide.com

Enterprise JavaBeans (EJB) was introduced for building distributed components. When it arrived it came with a promise to solve all issues and complexities of CORBA. EJB being the heart of J2EE went through several major revisions and got fattened with many features. Early on, most of the developers fell in love with EJB and used EJB in their application even it did not make any sense. “Blame it on EJB” has been the attitude for many developers when their projects did not scale well and they used EJB.

Development of EJB was never easier and it became more complex with every release of EJB specification. EJB has been compared with an elephant due to its complexity and heavy weight nature. Many developers feel EJB is like an extra layer of sugar syrup on a doughnut. In an age where low carb and Atkins diet is craze, the EJB expert committee has no option but to produce a low carb incarnation of EJB thus simplifying the development of EJB. EJB 3.0 expert committee released a sample picture of the lightweight model during JavaOne 2004 when it announced release of first public draft of EJB 3.0 Specification.

At the first glimpse the new model for EJB looks pretty and in this article we will discuss how EJB 3.0 is trying to dress up in a smaller size pretty outfit to make it appealing for developers. In a follow up article we will discuss how EJB 3.0 is simplifying the persistence model.

Cleaning up the Dirty Laundry

Let us look at the complexities in the current EJB model before we dive down discussing the details what EJB 3.0 is bringing on to the table.

  • The current EJB model requires creation of several component interfaces and implementation of several unnecessary callback methods.
  • The component interfaces require implementation of EJBObject or EJBLocalObject and handling of many unnecessary exceptions is required.
  • The EJB deployment descriptor is complex and error prone.
  • The container managed persistence being based on the EJB model is again overly complex to develop and manage. There are several basic features missing such as a standard way to define a primary key using database sequence and EJBQL is very limited.
  • EJB components do not look like its Object Oriented as it has restrictions for using inheritance and polymorphisms.
  • One major drawback of EJBs is that you cannot test EJB modules outside an EJB container and debugging an EJB inside the container is a nightmare for developers.
  • If you used EJB you know the complexities of looking up and invocation of EJB. It appears that you have to know minute details of JNDI to just use an EJB in your application.

Simplifying Developers view

If you developed an EJB with the latest specification you realize how difficult is develop a simple EJB like HelloWorld EJB. You need at least two interfaces, a bean class and a deployment descriptor. Most of the developers wondered why do I need all these. IDEs like Oracle JDeveloper, Eclipse and XDoclet made the life simple for developers for doing these mundane tasks however still it was the responsibility of developer to compile these classes and package the deployment descriptor before the EJB can be deployed in your container of choice.

EJB 3.0 is trying to address the complexities by:

  • Removing need of interfaces and deployment descriptors and these may be generated by the container using metadata annotations
  • Use regular Java classes as EJBs and regular business interfaces for EJBs

Metadata Annotations

EJB 3.0 depends heavily on metadata annotations. Metadata annotation being standardized under JSR 175 and will be part of J2SE 5.0. Annotation is a kind of attribute oriented programming and similar to XDoclet. However unlike XDoclet that requires pre-compilation, annotations are compiled into the classes (depending upon what the @Retention is set to) by the Java compiler at compile-time. In developer’s point of view, annotations are modifiers like public and can be used in classes, fields, methods, parameters, local variables, constructors, enumerations and packages.You can use annotations in your Java code by specifying attributes that can be used for either generating code, documenting code or providing special services such as enhanced business-level security or special business logic during runtime. The goal of J2EE 1.5 (5.0) is to simplify development using annotations and hence it will come up with its set of annotations. Annotations are marked with @ as follows:

 @Author("Debu Panda") @Bean public class MySessionBean

The goal of EJB 3.0 is to simplify development and hence use metadata annotations to generate several artifacts like interfaces and use annotations instead of deployment descriptors.

Using POJOs and POJIs

In canonical terms, JavaBeans and interfaces often referred as Plain Old Java Objects (POJOs) and Plain Old Java Interfaces (POJIs) respectively. The EJB class and interface will now resemble POJO and POJI respectively. The requirement of the unnecessary artifacts like home interface is being removed.

The developer has to either implement one of the EJB interfaces (SessionBean, EntityBean or MessageDrivenBean) in javax.ejb package or use annotation in the bean implementation class. You can either use Stateless, Stateful, MessageDriven or Entity to annotate your bean class. For example, if you define a stateless EJB as HelloWorld you define the EJB as follows:

 @Remote @Stateless public class HelloWorldBean { public String sayHello(String s) { System.out.println("Hello: "+s; } }

The interfaces for EJBs either remote or local do not have to implement EJBObject or EJBLocalObject. You have to either supply the business interface for your EJB and implement that interface in your bean class or have it generated during the deployment. Interfaces are optional for Entity beans however required for SessionBean and MessageDrivenDriven. If you do not implement an interface for your session bean, a bean interface will be generated for you. The type of generated interface either local or remote is dependent on the annotation you used in the bean class. If you look at the above code example, it is very clear that @Remote is used to generate a remote interface for the HelloWorld bean. If needed, you may have both remote and local interfaces for your EJB.

From the above example, it is very clear that the developer do not have to a lot of mundane tasks such as defining interfaces and implementing callback methods.

The name of the generated interface is derived from the name of the bean implementation class. Generated interfaces are well and good for developers. However, I do not see any benefit of generating interfaces as most IDE like Oracle JDeveloper generates these on fly.

This is not clear from the draft what is client side requirement for EJB lookup and it is not clear, how do we get hold of these interfaces those are required to invoke this EJB? I will recommend against using a generated interface for few reasons:

  • The name of generated interface will be derived from the bean name
  • You may not be willing to expose some methods in the EJB in the interface and the generated interface may expose all methods by default.
  • You need the interface at the client side to invoke the EJB.

Removing need for Callback methods

EJB 2.1 and prior releases required implementation of several lifecycle methods such as ejbPassivate, ejbActivate, ejbLoad, ejbStore, etc. for every EJB even if you do not need those. For example, ejbPassivate is not required for a stateless session bean still you require to implement that method in your bean class. As EJB 3.0 now resembles regular Java classes implementation of these lifecycle methods have been made optional. If you implement any callback method in the EJB then container will invoke that method.

The only exception is the ejbRemove method in Stateful Session bean where you can use Remove annotation to annotate a Stateful session bean business method. If you use of this annotation it will hint the container to remove the Stateful session bean instance after the completion (normal or abnormal) of the annotated method. For example, you can specify the following to remove a Stateful Session Bean instance after checkOut method is executed.

 @Stateful public class Cart { ... ... @Remove public void checkOut() { ... } }

Annotations vs. deployment descriptors

As we discussed earlier deployment descriptors will no longer be required for EJBs and annotations will be used instead. The default values for each attribute in the deployment descriptor will be chosen and developers do not have to specify these attributes unless they want a value other than the default value. These can be specified using annotations in the bean class itself. The EJB 3.0 specification is defining a set of metadata annotations for use by developers such as bean type, type of interfaces, resource references, transaction attributes, security, etc. For example, if we want to resource reference for a particular EJB then we will define as follows:

@Resource(name="jdbc/OracleDS", resourceType="javax.sql.DataSource")

J2EE vendors such as Oracle, BEA, IBM will add annotations for attributes in their vendor specific deployment descriptors and developers will use these to avoid using deployment descriptors. This looks very attractive for developers as the nasty XML descriptors they hated most gets out of their way but this introduces few problems and we need to be careful before embracing annotations.

  • This defeats the goal of portability of applications because if an EJB uses a vendor specific deployment descriptor this cannot be just changed without having to recompiling/repackaging the EJBs.
  • The deployment descriptors provided a holistic view of EJB modules to the assembler/deployer (ejb-jar) without having to look at individual the EJBs and they tweaked these as per the deployment requirement and if descriptors are not available or not generated until the end of deployment this could be a nightmare for them.
  • Deployment descriptors were used by the tools to identify the EJBs in an EJB module and were very useful when you try to migrate from one container to another.
    EJB 3.0 spec also proposes a way to override the annotations in the deployment descriptors. However details of overriding annotations is missing in the specification.

There is no doubt that getting rid of deployment descriptors will make the life easier for new developers but this may become a management nightmare if not used carefully.

Simplifying Container Managed Persistence

CMP entity bean is getting a major overhaul in EJB 3.0 to make it compelling for developers. Persistence frameworks like OracleAS TopLink, open source Hibernate have become darling of developing persistence framework for J2EE applications that has disliked Entity beans for its complexity and heavyweight in nature. EJB 3.0 is adopting a lightweight persistence model like TopLink and Hibernate to simplify the container managed persistence and this sounds compelling for developers. Let us do a quick look on the plans for entity beans and we will discuss about the details of the persistence improvement in another article.

Entity beans are being reincarnated as POJOs and there will be no component interfaces required for entity beans. Entity beans will now look as pure objects as this will also support inheritance and polymorphism.

Following is the source code for an entity bean:

 @Entity public class Employee{ private Long empNo; private String empName; private Address address; private Hashmap projects = new Hashmap(); private Double salary; @Id(generate=SEQUENCE) public Long getEmpNo() { return empNo; } protected void setEmpNo(Long empNo) { this.empNo = empNo; } public String getEmpName() { return EmpName; } public void setEmpName(String EmpName){ this.EmpName = EmpName; } @Dependent public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } public Set getProjects() { return projects; } public void setProjects(Set projects) { this.projects = projects; } public Double getSalary() { return salary; } public void setSalary(Double salary) { this.salary = salary; } .... }

If you look at the code, you will find that the bean class is a concrete class and not an abstract class the current entity bean.

There are several improvements are being made for the query capabilities in EJB QL and support of SQL queries in the entity beans. A new EntityManager API similar to Hibernate and a simplified version of TopLink’ Session API is being proposed to manipulation of entity beans i.e. creation, removal, finding of entity beans.

We will closely examine the details of the proposed CMP entity beans in a followup article.

Simplifying Client View for EJBs

Using EJBs i.e. to lookup and invoke is very complex even if EJB is collocated in the application. J2EE 1.4 and EJB 3.0 spec is working on to simplify the client’s view of EJBs.

If you want to use an EJB presently you have to define the ejb-ref or ejb-local-ref in the deployment descriptor, lookup the EJB and then invoke. If we want to invoke our HelloWorld EJB, following is the simplest way you can invoke an EJB with the current implementation.

First define the EJB references in the deployment descriptor as follows:

 <ejb-ref> <ejb-ref-name>HelloWorldEJB</ejb-ref-name> <ejb-ref-type>Session</ejb-ref-type> <home>hello.HelloWorldHome</home> <remote> hello.HelloWorld</remote> </ejb-ref>

Then lookup the EJB as follows. You have to explicitly handle exceptions for EJB lookup and creation of a bean instance.

 try { Context context = new InitialContext(); HelloWorldHome helloHome = (HelloWorld)PortableRemoteObject.narrow(context.lookup ("java:comp/env/ejb/HelloWorldEJB"), HelloWorldHome.class); HelloWorld hello = helloHome.create(); .... } catch(RemoteException e) { System.err.println("System/communication error: " + e.getMessage()); } catch(NamingException e) { System.err.println("Communication error: " + e.getMessage()); } catch(CreateException e) { System.err.println("Error creating EJB instance: " + e.getMessage()); }

As an alternative to environment variables, EJB 3.0 proposes a way to use setter injection to lookup and invoke EJBs.

Following is way our HelloWorldEJB can be looked up in another EJB by using setter injection.

 @Inject private void setSessionContext(SessionContext ctx) { this.ctx = ctx } ... myHello = (HelloWorld)ctx.lookup("java:comp/env/ejb/HelloWorldEJB");

If you look at the code above carefully the setSessionContext method is annotated with @Inject to specify that dependency injection be used for this method. The injected methods will be invoked by the container to set the EJBContext before any business method be called on that EJB.

Another direct example to inject the HelloWorld session bean would be to simply have @EJB public HelloWorld myHello and this would cause myHello to be injected with an instance of the HelloWorld bean.

You can use dependency injection to lookup any type of environment and resource references such as DataSource, JMS, Mail, Web Service, etc.

Testability Usability Outside Container

A major concern for the current EJB developers is not only development of EJBs is complex but also testing is a nightmare. An EJB container is required is to develop and test the EJBs and the developers have to be familiar with the final deployment platform to perform testing. This may not be a major issue for many enterprise developers but is an issue for ISVs who work on supporting multiple vendors and they have to maintain multiple environments to do the testing of their EJBs. The EJB 3.0 spec promises to provide the ability to test outside the container but this is currently missing in the draft specification.

Conclusion

Although there are a lot of missing information about packaging, assembly and gory details of APIs, the proposals made in EJB 3.0 drafts looks very promising for enterprise java developers. These will certainly help remove the complexities from developers view by passing those to the container vendors. It is to be seen how the container vendors implement these and make EJB 3.0 a compelling option to develop enterprise applications.

References and further reading

Author Bio

Debu Panda is a principal product manager of Oracle Application Server development team, where he focuses his efforts on the EJB container and Transaction Manager. He has more than 13 years of experience in the IT industry and has published articles in several magazines and has presented at many technology conferences. His J2EE-focused weblog can be found at http://radio.weblogs.com/0135826/.