Welcome!

Rob Woollen

Subscribe to Rob Woollen: eMailAlertsEmail Alerts
Get Rob Woollen via: homepageHomepage mobileMobile rssRSS facebookFacebook twitterTwitter linkedinLinkedIn


Related Topics: Java EE Journal, Java Developer Magazine

J2EE Journal: Article

Best Practices For Writing EJB Applications

Best Practices For Writing EJB Applications

JavaSoft defined the Enterprise JavaBeans specification to give Java developers a foundation for building distributed business components. EJBs are Java components that implement business logic and follow a contract designated in the EJB specification. Enterprise JavaBeans live inside an EJB container that provides a set of standard services, including transactions, persistence, security, and concurrency. This means that the application programmer is freed from developing these services from scratch.

To get the most out of using EJBs in an enterprise-level distributed application supported by a J2EE-compliant application server, programmers should:

  • Closely conform to the EJB specification.
  • Use available tools for bean development and compliance checking.
  • Learn to benefit from the experiences of others.
As outlined in this article, best practices for EJBs are based on experience gained through implementing J2EE for BEA WebLogic Server and helping BEA's customers develop or migrate their multitier applications to the J2EE platform.

EJB Overview
There are four types of Enterprise JavaBeans in EJB 2.0:

  1. Stateless session beans: Provide a service without storing a conversation state between method calls.
  2. Stateful session beans: Maintain state; each instance is associated with a particular client.
  3. Entity beans: Represent an object view of persistent data, usually rows in a database. They have a primary key as a unique identifier. There are two operational styles for entity beans: container-managed persistence (CMP) and bean-managed persistence (BMP).
  4. Message-driven beans: Added in EJB 2.0. These EJBs, the integration between JMS (Java Message Service) and EJB, are used to perform asynchronous work within the server.

Best Practices
For your coding pleasure...here are selected best practices for creating EJBs for an enterprise-level distributed application supported by a J2EE-compliant application server such as the BEA WebLogic Server. Our assumption is that the developer is an intermediate-to-expert Java programmer who's familiar with writing EJBs for an application server. We present best practices for:

  • Transactions
  • EJB security
  • Creating a primary key class
  • When not to use stateful session beans
  • Coding business interfaces
  • Using message-driven beans in transactions
Best practices are shown in summary form as tinted text following the relevant section.

Tips for Transactions
Almost every EJB application uses transactions at some point. Transactions ensure correctness and reliability and are essential to e-commerce applications. Misuse, however, can affect performance and even produce incorrect results. It's important to understand that session beans themselves can't be transactional.

A common misperception is that the member variables of the session bean will be rolled back when their transaction aborts. Instead, session beans merely propagate their transaction to any resource they acquire. For instance, at the beginning of a transaction a session bean has a member variable with a value of zero. During the transaction, the member variable is set to two, and a row is inserted into the database. If the transaction rolls back, the member variable won't be reset to zero. However, the row will no longer be in the database. Since a database is a transactional resource, it will participate in the session bean's transaction, and a rollback will abort any associated work.

Session bean state is not transactional.

User Interactions and Transaction Performance
Transactions can cause performance problems if they span too many operations. In particular, a transaction should never encompass user input or user think time. If a user starts a transaction and then goes to lunch or even visits another Web site, the transaction isn't committed. Instead, it continues to hold valuable locks and resources within the server.

In general, all transaction demarcation should occur within the server. There are a number of well-known techniques to avoid keeping long-running transactions open. When you ask a user to submit a form, break up the operation into two transactions. The Web page should read the data in a single transaction along with a version stamp. This transaction is committed before the form is returned to the user. The user can now modify the data as desired. The form update occurs in a new transaction.

Transactions should never encompass user input or think time.

Container-Managed vs Bean-Managed Transactions for Entity Beans
The EJB specification allows a session bean to choose either container-managed or bean-managed transactions. In the former the bean writer declares transaction attributes in the deployment descriptor. The EJB container then automatically starts and commits transactions as requested. The bean writer doesn't have to write any code to manage transactions. In the latter the bean writer uses the user transaction interface to explicitly start and commit transactions. Container-managed transactions should always be the bean writer's first choice. In bean-managed transactions the bean writer must ensure that the transaction is committed or rolled back. While the BEA WebLogic Server includes a transaction timeout, the bean writer shouldn't rely on this feature, but release transaction resources as soon as possible. In the case of container-managed transactions this is handled automatically by the EJB container.

Use container- instead of bean-managed transactions.

Best Practices for EJB Security
EJB provides a declarative security support as well as a simple programmatic interface for explicit security checks within the bean code. In practice, EJB security settings need to be considered within the entire application's security model. It's common for Web-based applications to handle authentication within the Web tier. In this environment the EJB tier may contain few security constraints. This arrangement simplifies the EJB design, and since the security checks are localized to the presentation layer, the application may modify security policies without modifying the EJB tier.

Applications with stand-alone programmatic clients often access session beans directly. Since there is no intermediate tier, the security access control must be handled in the EJB tier.

Declarative security control is preferred for simple applications. Since the security constraints are declared in the deployment descriptor, the bean classes' business logic is not polluted with security checks. The declarative security model is based on security roles that are declared in the deployment descriptor. Declarative security works best when the number of roles is fixed and doesn't depend on the number of clients. For instance, an application might include a user role and an administrator role. Since there are only two access domains, it's feasible to declare these roles in the deployment descriptor.

However, declarative security shouldn't be used when each user requires individual security constraints. Such applications require programmatic security checks within the EJB code. It's also common to combine both security models. For instance, an Account bean may use declarative security to ensure that only registered users access any methods. The bean code then includes additional constraints to ensure that each user gains access only to his or her account. Use declarative security checks when an application contains few roles. Choose programmatic security when each user needs individual security checks.

How to Write a Primary Key Class for Entity Beans
The EJB primary key class serves as its unique identifier both in the persistent store and in the EJB container. Usually, the primary key class fields map directly to the primary key fields in a database. If the primary key is only a single entity bean field that is a Java primitive class (such as java.lang.String), the bean writer doesn't have to write a custom primary key class. Instead, in the deployment descriptor, the bean writer specifies the name of the class and the name of the primary key field.

If the primary key maps to a user-defined type or to multiple fields, the bean writer must write a custom primary key class. The class must implement java.io.Serializable and contain the primary key fields. For CMP entity beans the field names must match the corresponding primary key field names in the bean class. This allows the EJB container to assign the appropriate CMP fields to their corresponding fields in the primary key class.

For instance, we might define an employee's primary key as a compound key using the first name, last name, and office number. Our compound key would look like Listing 1.

The primary key class consists of the primary key fields, which must be public, and a no argument constructor. The class must also implement the hashCode and equals methods. The EJB container uses a number of data structures internally, many of which are indexed by the primary key class. It is vital that hashCode and equals be implemented correctly and efficiently in the class.

The hashCode method is implemented by returning an integer using the primary key fields. The goal of this function is to produce an integer that can be used to index tables. The hashCode for a primary key should never change. Therefore, the hashCode should be constructed only from immutable values.

A common strategy is to XOR the hashCode of the primary key elements together. OR should never be used, since ORing several values will generally have most or all bits set to 1. Similarly, AND should not be used since most or all bits will converge to 0.

The hashCode method must be implemented such that two equal objects have the same hashCode. However, two objects with the same hashCode aren't necessarily equal. This hashCode implementation stores the hashCode in a member variable to avoid computing it every time hashCode is called.

It can also be tricky to implement equals correctly. The first line of any equals method should check the passed reference against this. This optimization simply checks whether equals has been called against itself. While this sounds strange at first, it is a common operation when the container has a primary key object and is checking to see if it already exists in a data structure.

Next, the equals method should ensure that the passed parameter is its own type. If the primary key class is final, a simple instanceof check can be used. If the primary key class isn't final, the passed parameter might be a subclass of our primary key class. In this case the equals method must use getClass().equals to ensure that the class types match exactly. It is recommended that primary key classes be final, since using instanceof is cheaper than comparing classes.

Primary key classes should be final.

When Not to Use Stateful Session Beans
Stateful session beans represent a stateful conversation between a single client and a bean instance. Stateful session beans can't be shared between multiple users. You shouldn't model a shared cache or any shared resource as a stateful session bean. If multiple clients need to access a single EJB instance, use an entity bean.

Stateful session beans are not shared by multiple users.

Since each client requires its own stateful session bean instance, the number of bean instances and the associated resource requirements can grow quickly. If an application can tolerate the stateless programming model, stateless session beans are easier to scale than stateful session beans.

Applications should always call remove after finishing with a stateful session bean instance. This allows the EJB container to release container resources as soon as possible. If the remove call is omitted, the EJB container will eventually passivate the bean, but this involves extra disk access.

Stateless session beans are easier to scale than stateful session beans.

Stateful session bean writers must also be careful when integrating their stateful session beans with Web applications. These beans should not allow concurrent method calls. As mentioned earlier, it's possible for multiple requests to cause concurrent calls on a stateful session bean. Unfortunately, this error usually shows up under load, so it's often missed in testing. For this reason use stateful session beans only within the scope of a request. Use entity beans or servlet sessions for applications that need to store data between requests.

Coding Business Interfaces
Many new EJB programmers are confused by the relationship between the remote interface and the EJB class. This arrangement is necessary for the container to intercept all method calls to the EJB. One confusing aspect is that the EJB class implements the methods defined in the remote interface, but the EJB class doesn't implement the remote interface itself. In fact, the EJB class should never implement the remote interface. While the EJB specification allows this practice, it can cause serious but subtle bugs. The problem with having the EJB class implement the remote interface is that the class can now be passed as a parameter to any method that expects the remote interface as a parameter.

Remember that the remote interface exists to allow the container to intercept method calls in order to provide necessary services such as transactions or security. If the Bean class is used, the method calls arrive directly on the bean object - creating a dangerous situation in which the container cannot intercept method calls or intervene in case of error. If (as recommended) the EJB class doesn't implement the remote interface, this problem becomes apparent at compile time. The Java compiler will reject the attempt to pass the bean class as a parameter of the remote interface's type.

Never implement the remote interface in the EJB class. The WebLogic Server provides an EJB compliance checker to catch any methods that are defined in the remote interface but not implemented in the EJB class.

Using Transactions with Message-Driven Beans
Message-driven EJBs are the integration between EJBs and the JMS. Like other EJB types, message-driven EJBs live within an EJB container and benefit from EJB container services such as transactions, security, and concurrency control. However, a message-driven EJB doesn't interact directly with clients. Instead, message-driven EJBs are JMS Message Listeners. A client publishes messages to a JMS destination. The JMS provider and the EJB container then cooperate to deliver the message to the message-driven EJB.

Like other EJBs, message-driven beans make use of the EJB container's transaction service. Since these beans never interact directly with clients, they never participate in the client's transaction.

Like session beans, message-driven EJBs may specify either bean-managed or container-demarcated transactions in their ejb-jar.xml deployment descriptor. With container transactions a message-driven EJB may specify either Required or NotSupported. (Since there is no client transaction, there is no reason to support the other transaction attributes.) If the transaction attribute is NotSupported, the message-driven EJB will not participate in a transaction.

If the Required attribute is specified, the EJB container automatically starts a transaction. The message receipt from the JMS Queue or Topic is included in this transaction. The message-driven bean's onMessage method is then called in the transaction context. When the onMessage method returns, the EJB container commits the transaction. If the transaction aborts, the JMS message remains in the JMS destination and is delivered again to the message-driven EJB.

Error Handling in Message-Driven Bean Transactions
Message-driven beans with the Required transaction attribute need to be careful when aborting transactions. A transaction aborts either because it was explicitly marked for rollback or because a system exception was thrown. One potential issue is known as the "Poison Message." In this scenario a message-driven EJB receiving stock trade orders from an order queue might encounter a stock symbol that doesn't exist. When the message-driven EJB receives the error message, the underlying logic might be to abort the transaction because the symbol is invalid. When the JMS implementation delivers the message again in a new transaction, the process repeats. Clearly, this is not the desired behavior.

A good solution for this potential problem is to separate application errors from system errors. An application error, such as an invalid stock symbol, should be handled by sending an error message to an error JMS destination. This allows the transaction to commit, and the "Poison Message" leaves the system. A system error might be that the back-end database has failed. In this case our transaction should roll back so that this message is still on the queue when the database recovers.

Conclusion
EJBs are server-side Java components that leverage the standard transaction, persistence, concurrency, and security services provided by the EJB container. What we've described here are best practices for coding to the J2EE standard, based on experience with the BEA WebLogic Server.

More Stories By Sandra L. Emerson

Sandra L. Emerson is a technical writer and consultant with 20 years' experience in the software industry. She is a coauthor of The Practical SQL Handbook
(Addison-Wesley).

More Stories By Michael Girdley

Michael Girdley is senior product manager for BEA WebLogic Server at BEA Systems, Inc. He has extensive experience programming with Java, HTML, C, and C++, and is a coauthor of Web Programming with Java (SAMS); Java Unleashed, 2nd ed. (SAMS); and Java Programming for Dummies (IDG Books).

Comments (0)

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.