Chapter 23. EJB Best Practices

Best Practices for Session Beans

The following sections describe some of the best practices to keep in mind while coding stateless and stateful session beans.

Optimizing JNDI Lookups

Because the Java Naming and Directory Interface (JNDI) lookup can be an expensive operation, caching all the onetime initialization procedures in the session bean’s setSessionContext() method is the recommended practice. The EJB container calls the session bean’s setSessionContext() to associate a session bean instance with its context maintained by the container. Typically, a session bean instance retains its session context as part of its conversational state. In addition, setSessionContext() is called in an unspecified transactional context, so there is no transaction overhead. This method is called only once during the bean’s life cycle.

For example, if you are making some database calls from a stateless session bean, look up the datasource, as shown in Listing 23.1.

Example 23.1. Database Calls from a Stateless Session Bean

        public class TraderBean extends SessionBean {

           public Context = null;
           public DataSource = null;

         public void setSessionContext(SessionContext sc) {

            ctx = new InitialContext();
              ds  = (javax.sql.DataSource) ctx.lookup("MyDataSource");
        //This reference can be used until the bean instance is destroyed
           }
    }

For stateful session beans, it is essential to do this initialization work in the ejbActivate() method and release the resources in the ejbPassivate() method. As far as stateless Session beans are concerned, the ejbActivate() and ejbPassivate() methods are not called since there is no conversational state to passivate.

Similarly, you can cache Java Messaging Service (JMS) connection factories and home and remote stubs for other beans. This optimization might not be a big win when very few clients access your bean; however, you can see the performance advantage when load-testing your application with a large client base.

When Not to Use Stateful Session Beans

Stateful session beans represent a conversational state between a single client and a bean instance. Stateful session beans cannot be shared between multiple users and should not be modeled as a shared cache or any shared resource.

Tip

If multiple clients need to access a single EJB instance, entity beans are the best choice.

Because each client requires its own stateful session bean instance, the number of bean instances and the associated resource requirements can grow quickly. As these resources grow, the EJB container will use passivation techniques to manage its idle resources; passivation is an expensive operation.

Some enterprise applications can take advantage of the stateless programming model, allowing the stateless session bean to leverage efficient pooling techniques implemented within the EJB container of WebLogic Server. In general, stateless session beans are much easier to scale than stateful session beans.

Also, clients of stateful session beans should always call the remove() method after finishing with a stateful session bean instance so that the EJB container can release resources as soon as possible. If you do not call the remove() method on stateful session beans, the EJB container eventually passivates the bean, but this process involves extra disk access, which is not a good practice for high-volume sites.

Stateful session bean writers must also be careful when integrating stateful session beans with Web applications. In practice, it can be difficult to use stateful session beans correctly in servlets or JavaServer Pages (JSPs). If a stateful session bean is used within the scope of a single request, then multiple threads do not use that instance.

However, Web applications often store the reference to a stateful Session bean within the JSP’s session scope. This can be problematic as it can cause the session bean instance to be accessed concurrently. One common scenario is when a user enters a Web site, creates a new HTTP session, which in turn creates a stateful session bean instance, and invokes some business methods on this stateful session bean instance. If the user clicks on the stop or reload button while a stateful session bean is processing a request, the end-user (client) will end up accessing the same bean instance resulting in a concurrent call. For this reason the EJB specification prohibits concurrent access to stateful session beans.

Making loopback calls while coding stateful session beans is also illegal, as shown in this example:

method-A in Bean-A ▸ calls method-B in Bean-B ▸ calls method-A in Bean-A

There are three possible solutions to this problem:

  • Use stateful session beans within the scope of a single request. Although this method is possible for complex requests, creating a new stateful session bean instance for every HTTP request introduces extra overhead.

  • Set <allow-concurrent-calls> to true in the WebLogic deployment descriptor. When this option is true, the EJB container blocks concurrent method calls and only allows a method call to proceed once the previous call has finished.

  • Use entity beans or HTTP servlet sessions for applications that need to store data between requests.

Scalability Issues with Stateful Session Beans

Unlike stateless session beans, the container does not maintain a pool of instances to multiplex on client calls. Each client has a unique stateful session bean instance. For a large Web site, the number of clients might be in the thousands, so storing all these instances in memory for the client’s lifetime is not always feasible. To support large numbers of clients and effectively manage resources, the EJB container manages its working set by temporarily transferring the state of an idle stateful session bean instance to disk. Because this process involves the passivation of information to disk, you should be careful when modeling applications with stateful Session beans.

The SessionSynchronization Interface

Stateful session beans with container-managed transactions can optionally implement the javax.ejb.SessionSynchronization interface. This interface contains three methods:

  • afterBegin()

  • beforeCompletion()

  • afterCompletion(boolean)

The container calls the afterBegin() method when the stateful session bean enters a transaction. The beforeCompletion call occurs before the transaction is prepared to commit. The afterCompletion callback accepts the boolean argument. If the container passes true to afterCompletion, the transaction was committed; false indicates the transaction was rolled back.

The beforeCompletion method is often used to perform final transaction processing so that it may be committed with the rest of the transaction. Because the afterCompletion method is called after the transaction is committed or rolled back, the bean developer can add logic to set the cached information to a known state. This is especially true in the case of a rollback where the state of the bean instance might no longer be valid. The afterBegin method can be used in circumstances where internal variables need to be set and used only by transactional code, or possibly to trigger the execution of transactional code.

Session Beans As a Facade to Entity Beans

Enterprise JavaBeans are generally divided into three core types of beans: session beans, message-driven beans, and entity beans. Beans can also be categorized as those that act as business objects and those that act as data objects. Session beans and message-driven beans are business objects; entity beans are data objects. In most applications, business objects are exposed to the Web tier, because business objects can use data objects to deal with data stores. Nevertheless, in some cases, it is necessary to allow users to directly access and manipulate data objects, which means exposing entity beans to the Web tier. This can leave your application open to security threats and can result in poor performance due to the remote nature of Entity beans.

Fortunately, there is a design pattern that allows you to enable user access to data objects without exposing your entity beans to the Web tier. The Session Facade pattern places a session bean between the entity bean and application clients. The Session bean can be thought of as managing access to multiple Entity beans, thus reducing exposure to the client and reducing the number of remote calls made to the Entity beans.

Generally, Session beans are designed to act as an interface between the business tier and the persistent tier. The primary use of a Session bean is to manage data validation, security, and general business-specific functionality. However, by wrapping Entity beans within the façade of a session bean, you can carry out the processing of business rules without tightly coupling Session bean functionality with your Entity bean code. Hence, the stateless Session bean is responsible for starting transactions and committing or rolling back transactions before returning to the Web tier. This approach of using session beans ensures that the resulting transactions are short and encompass only transactional logic.

Best Practices for Entity Beans

Entity beans are primarily used to represent an object view of data stored in persistent storage, such as a database. The entity bean’s persistence can be implemented through the bean itself (Bean-Managed persistence, or BMP) or through the EJB container (Container-Managed persistence, or CMP), where the EJB container automatically manages the retrieval and storage of persistent data. The following sections discuss a few common best practices that relate to using both BMP and CMP entity beans in the context of WebLogic Server.

Consider Writing CMP Entity Beans Instead of BMP Entity Beans

The EJB 2.0 specification has greatly enhanced the capabilities of the persistence framework. In the EJB 1.1 specification, the age-old promise of automated mapping from the object domain to the database realm fell short of expectations. For example, Container Managed Persistence (CMP) was seriously lacking in various critical programming aspects such as multiplicity of relationships. The EJB 2.0 specification provides for Container Managed relationships, which let the container take care of the integrity of the relationships.

Adding abstract getters and setters is another great feature of CMP 2.0. It is the container’s responsibility to implement these methods, and in CMP 2.0, the container can now control with great granularity what data you access and what data you write, thereby tracking most of the information it needs to optimize your data access patterns. What this means is that the container automatically takes care of many of the optimizations you needed to do by hand in CMP 1.1. If you are only reading a bean, the container knows it; if you are not modifying all the fields, the container knows it; and if you are going to load certain data sets for certain methods, the container knows it because you can give hints to the CMP engine and help it optimize the loading and storing time. The improvements made within the EJB 2.0 specification for CMP have given bean developers a realistic methodology for resolving persistent issues. They no longer have to rely on BMP to solve complex coding needs. As more companies purchase or upgrade to EJB 2.0-compliant containers, the use of BMP for data access will decline in favor of CMP.

Debug Flags to Instrument BMP Code

Making typographical errors when developing BMP entity beans is an easy mistake. Although BMP entity beans require a fair amount of Java Database Connectivity (JDBC) code, the database access code is the same for almost all BMP beans. However, it is a good practice to include debug code that prints out the SQL statements that are running. Otherwise, it is hard to troubleshoot problems that can result in cryptic database errors.

Writing an Efficient Primary Key Class

Like a database row, entity beans have an associated primary key that the container must be able to manipulate. This primary key can be a single entity bean field. Each entity bean class can define a different class for its primary key, but multiple entity beans can use the same primary key class. The primary key is specified in the entity bean’s deployment descriptor. You can specify a primary key class for an entity bean with CMP by mapping the primary key to a single field or to multiple fields in the entity bean class. You can also provide a custom primary key class. This class is necessary for a compound primary key, one that maps to multiple entity bean fields. With a custom primary key class, the bean writer must implement the hashCode and equals methods. Because the EJB container often uses the primary key class in its internal data structures, this class must implement hashCode and equals correctly and efficiently. Listing 23.2 shows an inefficient, but workable implementation of the hashcode and equals methods, which will be improved in subsequent sections.

Example 23.2. An Inefficient, but Correct, Primary Key Class

    public class MyPk implements java.io.Serializable {
        public String str;
        public int i;
        public byte b;
        public MyPk() {}
        public int hashCode() { return -1; }

        public boolean equals(Object o) {
              if ((o != null) && (MyPk.class.equals(o.getClass()))) {
          MyPk other = (MyPk) o;
          return other.str.equals(str) && other.i == i && other.b == b;
          }
          else {
               return false;
          }
            }
}

Implementing the hashCode Method

The hashCode method must return the same value for two objects that are equal, and it should attempt to distribute the hashCode values relatively evenly. The following code snippet is efficient and correct, but it does not distribute the hashCode values at all. This hashCode implementation transforms any hash table into a list and forces linear searches, which clearly defeats the whole purpose of having an indexed data structure:

   private int hash = -1;
   public int hashCode() {
   if (hash == -1) {
   hash = str.hashCode() ^ i ^ b;
   }
   return hash;
   }

This hashCode implementation computes the exclusive OR (XOR) of the string’s hashCode and the primitive fields. XOR should be preferred to other logical operators, such as AND or OR, because it gives a better distribution of hash values. This implementation also caches the hashCode value in a member variable to avoid recomputing this value.

Implementing the equals() Method

The equals() method compares the current object with the passed parameter and returns true if the objects have the same value. The default java.lang.Object. equals compares the reference (pointer) values and returns true if they are equal. For most primary key classes, this operation needs to be overridden to compare the values within the primary key class:

// An efficient primary key class implementation

public final class MyPk implements java.io.Serializable {
  public boolean equals(Object o) {
    if (o == this) return true;
    if (o instanceof MyPk) {
      MyPk other = (MyPk) o;
      return other.hashCode() == hashCode() &&
             other.i == i && other.b == b &&
             other.str.equals(str);
    }
      else {
      return false;
    }
  }
}

The first line of the optimized equals implementation compares the passed reference against the this keyword. Although this operation seems strange at first, it is a common case when the EJB container checks whether a primary key already exists in its data structures.

Next, getClass().equals is replaced with a much more efficient instance of check. The instance of operator returns true if the passed parameter’s class is MyPk or one of its subclasses. Making the MyPk class final allows the create method to safely use the instance of operator because there cannot be a subclass.

Finally, the hashCode and member variables are compared. Moreover, expressions are short-circuited in Java, which means that if the first expression is false, the second is not evaluated. The equals method takes advantage of this short-circuiting by ordering the && (forced logical AND) operator with the cheapest comparisons first. The hashCodes are compared first because the implementation caches this value, and it is rare for both objects to have the same hashCode but not be equal. Next, the primitive fields are compared, and finally the more expensive java.lang.String.equals is called.

Choose the Right Concurrency Strategy

The concurrency strategy plays an important role in developing entity beans. It specifies how the EJB container should manage concurrent access to an entity bean. Although the database option is the default concurrency strategy, depending on your requirements, you should choose the right concurrency model.

Four different concurrency strategies are available as of WebLogic Server 7:

  • Exclusive—Places an exclusive lock on cached entity EJB instances when the bean is associated with a transaction. Other requests for the EJB instance are blocked until the transaction completes. This option was the default locking behavior for WebLogic Server versions 3.1 through 5.1.

  • Database—Defers locking requests for an entity EJB to the underlying data store. WebLogic Server allocates a separate entity bean instance and allows the database to handle locking and caching. This option is the default. The database concurrency strategy leverages the database’s deadlock detection capabilities. When the database deadlock is detected, one of the deadlocked transactions is aborted. An SQLException is thrown to the client, and the EJB container processes the transaction rollback.

  • Optimistic—Holds no locks in the EJB container or database during a transaction. The EJB container verifies that none of the data updated by the transaction has changed before committing the transaction. If any updated data changed, the EJB container rolls back the transaction.

  • ReadOnly—Used only for read-only entity beans. This strategy activates a new instance for each transaction so that requests proceed in parallel. WebLogic Server calls ejbLoad() for ReadOnly beans, based on the read-timeout-seconds parameter.

Generally, entity beans should use the default database concurrency strategy because it places much less burden on the EJB programmer. Unless your application has a special requirement, always use the default Database concurrency strategy.

Optimize Database Access Calls

Entity bean programmers are concerned about performance because they strive to minimize the number of round trips between the EJB container and the database. By default, the EJB container calls the entity bean’s ejbLoad method at the beginning of a transaction to read the database’s current state. When the transaction commits, the EJB container calls ejbStore to write the entity bean’s contents to the database. Keep in mind that database access occurs on transaction boundaries, not on method-call boundaries.

In writing Entity beans, less experienced programmers can incur performance penalties by making their transactions too fine-grained. For instance, a Web page might need to gather 10 attributes from an entity bean to populate a page. If each method call runs in its own transaction, there are 10 database reads (ejbLoad calls) and 10 database writes (ejbStore calls). If the 10 method calls are wrapped in a single transaction, there is only one database read and one database write. For an operation such as populating a Web page, the database write is actually unnecessary because this transaction is read-only. The following section discusses how the EJB container avoids unnecessary database writes.

Loading Related CMP Fields

WebLogic Server’s EJB 2.0 CMP container enables the EJB deployer to instruct the EJB container on how to optimize database access calls by grouping CMP fields that should be loaded together. For example, instead of loading only the primary key in the finder, the container could select the primary key plus some additional CMP fields that are used in the subsequent business method calls. In this case, only a single database access is needed to run the finder and all the related business methods.

For example, an entity bean could have Employee-ID as a primary key and an EmployeeName attribute. You could call findByPrimaryKey on a specific Employee-ID, and then call a business method that reads the EmployeeName attribute. By default, there would be one database access for the findByPrimaryKey call and another database access to load the employee name attribute. If the deployer had specified a group containing the employee name and employee ID fields, the findByPrimaryKey method and getEmployeeName() method could use the same group. In this case, only one database access is needed. If the getEmployeeName() method is called again within the same transaction, the database access is skipped and the name is retrieved from the cache. This feature is effective, as it does not require that every field be retrieved, which is an expensive operation. This example advocates the recommended practice for the bean developer to structure coarse-grained Entity beans, making many small and efficient data access calls. One of the limitations of the BMP programming model is that it cannot match the CMP container’s cooperation between finders and subsequent business method calls.

Field groups are specified in the Weblogic-rdbms-cmp-jar.xml file, as follows:

     <Weblogic-rdbms-bean>
     <name-name>EmployeeBean</name-name>
     <field-group>
     <group-name>emp-data</group-name>
     <cmp-field>Employee-ID</cmp-field>
     <cmr-field>EmployeeName</cmr-fields>
     </field-group>
     </Weblogic-rdbms-bean>

Optimizing Finders

The general contract for the findByPrimaryKey method is to ensure that the primary key exists and then return the primary key. Usually, the bean implementation selects the primary key from the database, and if a row is returned, the implementation knows the key exists. It is possible to optimize finder method invocations if the primary key is not already loaded in the same transaction.

For example, in Transaction-1 you issue a Find for the primary key denoted as PK1. At a later point in the process, a subsequent Find operation is again issued for PK1. The EJB container will recognized the earlier request and return the cached primary key of PK1. This is true for both CMP and BMP beans. In general, BMP finders simply access the database and return the associated primary keys. However, CMP finders can be better optimized, as discussed in the following section.

Optimizing CMP Entity Beans

It is a common misunderstanding among EJB developers that because BMP gives the bean writer explicit control over data access logic, BMP should outperform container-generated code. WebLogic Server’s EJB 2.0 CMP engine achieves high performance by minimizing the number of round-trips between the EJB container and the database.

In a BMP entity bean, finder methods return primary keys from the database. The EJB container then creates a bean reference for each key and returns the references to the client. Note that the BMP finder can return only the primary key.

Optimizing BMP Entity Beans

If your BMP bean handles a large amount of data, it is possible to optimize database reads by implementing the ejbLoad method to read a subset of data or skip the read operation entirely. For instance, when a business method call is invoked, the entity bean needs to determine whether the data has already been read in this transaction. You can find this information by storing a bitmask, with one bit for each field, in the entity bean. Then ejbLoad sets a bit when its associated field is loaded, and the remaining bits are cleared. The business method checks the bitmask to determine whether it needs to load its data.

You should use the bitmask technique carefully. If every CMP field is brought in only on demand, the entity bean can exhibit extremely poor performance. The bitmask approach is best used when entity bean fields are very large, but seldom used. For example, an Employee entity bean might have a picture stored as a binary image in the bean. Assuming that many users of this entity bean do not display the picture, the bean limits the amount of data transferred from the database by loading the picture only when requested. If the remainder of the bean’s fields are simple relational types or are frequently used, they should all be loaded in the ejbLoad call. The memory overhead of loading a few extra integers is minimal compared to the cost of extra trips to the database.

Optimizing Database Writes for BMP Entity Beans

Two database write optimizations can be performed with BMP entity beans:

  • Avoiding database writes in read-only transactions

  • Using tuned writes to store only modified data in the bean

Read-only transactions are common in real-world e-commerce applications because entity bean data is often used to populate Web pages. Tuned writes are used to write only modified fields, instead of every field in the entity bean. Both optimizations are implemented using the same technique and are generally combined.

The entity bean keeps a bitmask with one bit per BMP field. The bit mask is cleared in the ejbLoad callback. As with EJB 2.0 CMP beans, the bean should access its fields through get and set methods, which simplifies porting EJBs to CMP. With BMP beans, the bean writer implements the get and set methods. The get method simply returns the associated field. The set method sets the bitmask field associated with the EJB field and then assigns the value. The ejbStore implementation first checks the bit mask. If the bit mask is all zeros, ejbStore returns immediately without writing to the database. The ejbStore method can also perform tuned writes because the bit mask shows which fields were modified in the transaction.

A common error when implementing this pattern is to clear the associated bit in the get method. This implementation does not work well because the value can be read again after it has been written. If the bean writer clears the mask in the get method, the previous database writes are lost.

Consider Using Tuned Updates for CMP 1.1 Beans

EJB CMP 2.0 automatically supports tuned updates because the container receives get and set callbacks when container-managed EJBs are read or written. WebLogic Server now supports tuned updates for EJB 1.1 CMP to improve performance. When ejbStore is called, the EJB container automatically determines which container-managed fields have been modified in the transaction. Only modified fields are written back to the database. If no fields are modified, no database updates occur.

With previous versions of WebLogic Server, you could write an isModified method that notified the container when the EJB 1.1 CMP bean had been modified. The isModified method is still supported in WebLogic Server, but we recommend that you no longer use isModified methods; instead, you should allow the container to determine the update fields.

This feature is enabled for EJB 2.0 CMP, by default. To enable tuned EJB 1.1 CMP updates, make sure you set the following deployment descriptor element in the weblogic-cmp-rdbms-jar.xml file to true:

<enable-tuned-updates>true</enable-tuned-updates>

You can disable tuned CMP updates by setting this deployment descriptor element as follows:

<enable-tuned-updates>false</enable-tuned-updates>

In this case, ejbStore always writes all fields to the database.

Consider Using Read-Only/Read-Mostly Entity Beans

Read-only entity beans are very powerful and effective in the following environments:

  • Database reads dominate, but there are very few database updates.

  • Your application can tolerate slightly stale data.

WebLogic Server’s EJB container provides a ReadOnly concurrency strategy for read-only type entity beans to provide improved performance for read-intensive applications. By specifying the ReadOnly value for the <concurrent-strategy> tag in the weblogic-ejb-jar.xml deployment descriptor, the EJB deployer can specify a timeout value (<read-timeout>) for the entity bean’s cached state, allowing the cache to be refreshed after the timeout is expired.

Note

Previously, read-only entity beans used an exclusive locking strategy to keep the distributed cache coherent.

Like any other entity bean, the bean state is refreshed with the ejbLoad method call. When a method call is made on a read-only entity bean, the EJB container checks whether the associated data is older than its timeout value. If the timeout period has elapsed, ejbLoad is called and the bean state is refreshed. Because read-only entity beans do not have database updates, ejbStore will never be called. Also, read-only entity beans never participate in transactions.

Handling Transactions in EJBs

Almost every EJB application uses transactions at some point. Transactions ensure atomicity and reliability and are essential for Web-based applications. Because transactions are expensive within the server, misusing them significantly affects performance. Many EJB applications limit their performance by making their transactions too fine-grained, hence causing problems if they span too many operations. In reality, transactions should never rely on user input. Your application will not be scalable if you start a transaction and wait for a user to complete the form or click Submit on a Web form. In fact, it is best to avoid handling transactions in the Web tier all together. JSP/servlets should be concerned with presentation logic and use an interface to communicate with the business logic. Transactional business logic should be handled within the EJB layer.

Regardless of the underlying concurrency strategy, transactions acquire locks and use many server resources. For example, if a user starts a transaction and then goes to lunch or even visits another Web site, the transaction is not committed until it times out. Instead, the transaction continues to hold valuable locks and resources within the server until the transaction times out. Unless there is a business reason for doing so, transactions should not last for more than 5–10 seconds. In addition, the transaction demarcation should occur inside the server. The following sections discuss well-known techniques to avoid keeping long-running transactions open.

Use Container Managed Transactions Instead of Bean Managed Transactions

The EJB specification enforces a restriction that entity beans cannot participate in Bean-Managed Transactions (BMT). However, it does allow session beans to choose BMT or Container-Managed Transactions (CMT). In CMT, the bean developer defines transaction attributes in the deployment descriptor. The EJB container then automatically starts and commits transactions as requested. The bean developer does not have to deal with managing transactions. In BMT, the bean developer uses the javax.transaction.UserTransaction interface to control transaction boundaries.

The benefit of this approach is that the bean developer has full control over starting and rolling back transactions. The developer has to start a transaction by issuing a begin statement and complete the transaction by issuing a commit or rollback statement.

As discussed earlier, transactions consume a lot of resources in the application server and in databases. That is why keeping transactions as short as possible is always a recommended practice.

CMT encompasses a set of method calls. When the outer method finishes, the transaction is committed or rolled back by the container. In BMT, the bean developer must ensure that the transaction is committed or rolled back. Although the transaction manager imposes a default transaction timeout, the bean writer should not rely on this feature, but instead release transactional resources as soon as possible. With BMT, the bean writer needs to ensure that every exceptional path handles the transaction rollback or commit correctly. The EJB container automatically issues rollbacks or commits for CMT.

However, you might need to use BMT in the following two situations:

  • You define multiple transactions from within a single method call. WebLogic Server demarcates transactions on a per-method basis.

    Tip

    However, instead of using multiple transactions in a single method call, it is better to break the method into multiple methods, with each of the multiple methods having its own CMT.

  • You define a single transaction that spans multiple EJB method calls. For example, you define a stateful session EJB that uses one method to begin a transaction, and another method to commit or roll back the transaction.

    Caution

    Implementing separate methods to initiate and commit or rollback requires detailed information about the working internals of an EJB object.

CMT should always be the bean developer’s first choice.

Do Not Use the Supports Transaction Attribute

The valid transaction attributes are Never, NotSupported, Supports, Required, RequiresNew, or Mandatory. In general, the Supports attribute should not be used for enterprise-wide applications. The risk of using the Supports attribute is that the EJBs run in a transaction only if the caller has started a transaction. If you have a business reason to run a method call in a transaction, use Required, RequiresNew, or Mandatory; if you do not need transactional behavior, use Never or NotSupported.

Consider Using the Mandatory Transaction Attribute

Many EJB programmers deploy their beans with the Required transaction attribute. This attribute works in many cases because it inherits the caller’s transaction if one exists; otherwise, Required starts its own transaction. As explained earlier, developers must understand how transaction attributes can affect performance. A new programmer on your team might be reusing the Employee entity bean and mistakenly call every getXXX method in an individual transaction. One way to prevent this is to deploy your entity bean with the Mandatory transaction attribute. Unlike Required, a Mandatory bean does not start its own transaction. If it is called with a transaction, the Mandatory bean participates in that transaction. If a Mandatory bean is called without a transaction, the EJB container immediately throws an exception to the caller. Deploying entity beans with the Mandatory transaction attribute is an easy way to indicate that the operations should be grouped together in a calling transaction.

Consider Using Transactional DataSources for Entity Beans

If you configure a JDBC DataSource factory for use with entity beans, make sure you configure a transactional DataSource (TxDataSource) rather than a non-transactional DataSource (DataSource). With a non-transactional DataSource, the JDBC connection operates in auto commit mode, committing each insert and update operation to the database immediately, instead of as part of a CMT.

Always Demarcate Transactions at the WLS or Database Level

In general, client applications are not guaranteed to stay active over long periods of time. If a client begins a transaction and then exits before committing, it wastes valuable transaction and connection resources in WebLogic Server. Moreover, even if the client does not exit during a transaction, the duration of the transaction might be unacceptable if it relies on user activity to commit or roll back data. Demarcating transactions at the WebLogic Server or relational database management system (RDBMS) level when possible is the recommended practice.

Best Practices for EJB Security

You can provide security support to EJBs in two ways:

  • Declarations in the EJB deployment descriptor

  • A programmatic security interface

In general, EJB security settings should be considered within the entire application’s security model. It is a recommended practice for Web-based applications to handle authentication within the Web tier. That way, the EJB tier contains very few security constraints. This arrangement simplifies the EJB design and because the security checks are localized to the presentation layer, the application can modify security policies without modifying the EJB tier.

Applications with standalone Java clients often directly access EJBs. Because there is no intermediate tier, the security access control must be handled in the EJB tier.

Declarative security control is preferred for simple applications. Because the security constraints are declared in the deployment descriptor, the bean class’s business logic is not coupled with security checks. The declarative security model is based on security roles declared in the deployment descriptor. Declarative security works best when the number of roles is fixed and does not depend on the number of clients. For example, an EJB might include a user role and an admin role. Because there are only two access domains, it is quite easy to declare these roles in the deployment descriptor.

WLS Builder enables you to easily add security constraints in your deployment descriptors. Using declarative security has the advantage of the security policies being independent of the bean code. Security settings can easily be adjusted at deploy time to match the constraints of the runtime environment.

However, declarative security should not be used when each user requires individual security constraints. Such applications require programmatic security checks within the EJB code. It is also common practice to combine both security models. For example, a trader bean might use declarative security to ensure that only registered traders access any methods. The bean code then includes additional constraints to ensure that each trader gains access only to his account.

Best Practices for Coding Standard Interfaces

Many new EJB developers are confused by the relationship between the remote interface and the bean class. This contrast is necessary for the container to intercept all method calls to the EJB. One confusing aspect is that the EJB class implements methods defined in the remote interface, but the EJB class does not implement the remote interface itself. In fact, the EJB class should never implement the remote interface. Although the EJB specification does allow this practice, it can cause serious bugs. The problem with having the EJB class implementing the remote interface is that the EJB class can be passed as a parameter to any method that expects the remote interface as a parameter.

Remember that the remote interface is needed so that the container can intercept method calls to provide necessary services, such as transaction 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 the EJB class does not 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.

The only advantage of implementing the remote interface in the bean class is that the Java compiler catches any method that is defined in the remote interface but not implemented in the bean class. However, this also means that the bean class has to provide dummy implementations of the remote interface’s super class to satisfy the Java compiler.

Clearly, implementing the remote interface in the bean class is not a good practice, but catching the bean writer’s errors as early as possible is desirable. WebLogic Server comes with a command-line utility called the EJB Compiler (EJBC), which performs a compliance check to catch as many violations of the EJB specification as possible. The weblogic.ejbc utility analyzes an EJB and flags any specification violations with the related section in the EJB specification. This utility can be performed as an attribute of the Java Complier (javac) on the command line or by using the graphical deployment tools. It catches any methods defined in the remote interface but not implemented in the EJB class.

Another method for catching this kind of error is using a pattern known as business interface. In this pattern, all the business methods are defined in a separate interface. The remote interface extends the business interface and the javax.ejb.EJBObject interface. The bean class can then implement the business interface, as shown here:

     public interface MyBusinessInterface {

         public void businessMethod() throws RemoteException;
     }

     public interface MyRemoteInterface extends MyBusinessInterface, EJBObject {}

     public class MyBean implements SessionBean, MyBusinessInterface {

        public void businessMethod() throws RemoteException{}
     }

By using the business interface, the Java Compiler ensures that the bean class implements the methods in the business interface. The pattern is also safe because the bean class cannot be passed into a method expecting the remote interface. Although both classes can be assigned from the business interface, the remote interface is still a distinct type.

MDB Best Practices

A message-driven bean is a stateless, server-side, transaction-aware component that is driven by a Java message (javax.jms.message). As with standard JMS message consumers, message-driven beans receive messages from a JMS queue or topic and perform business logic based on the message contents.

Exception Handling in MDBs

Throwing application exceptions or remote exceptions inside an MDB’s onMessage or bean methods is not a recommended practice. If any method throws such an exception, the EJB container immediately removes the EJB instance without calling ejbRemove(). This can be a major problem if you are removing or releasing any shared resources in the ejbRemove method. However, from the client perspective, the EJB still exists because future messages are forwarded to a new bean instance that the container creates.

Consider Using a Separate JMS Destination to Handle Poison Messages

MDBs with the Required transaction attribute can cause problems when aborting transactions. A transaction aborts because it was explicitly marked for rollback or because a system exception was thrown. One potential issue is known as the “Poison Message.” For example, an MDB’s onMessage() method has not received the valid input it was expecting. When the MDB encounters invalid input, the underlying logic might be to abort the transaction because the incoming parameter is invalid. When the JMS implementation delivers the message again in a new transaction, the process repeats. Poison messages cause continual rollback and redelivery of these messages, which is clearly not the expected behavior.

A good solution for this potential problem is to separate application errors from system errors. An application error, such as invalid data being passed to the MDB, should be handled by sending an error message to a JMS error destination. This enables the transaction to commit, and the Poison message leaves the system. This process also enables you to ensure that improper messages are not continually redelivered.

Consider Using DUPS_OK_ACKNOWLEDGE Mode

The EJB container automatically handles JMS message acknowledgements for MDBs. When an MDB is deployed in WLS with the Required transaction attribute, the container acknowledges the message when the transaction commits. Acknowledgement mode can be specified in the MDB’s ejb-jar.xml deployment descriptor via the <jms-acknowledge-mode> tag. However, in case of failures, if your application can tolerate duplicate messages, using DUPS_OK_ACKNOWLEDGE mode is recommended. This mode performs better than AUTO_ACKNOWLEDGE because acknowledgements are less frequent. The WLS JMS implementation adds the NO_ACKNOWLEDGE and MULTICAST_NO_ACKNOWLEDGE modes, which can also be selected for message-driven EJBs. NO_ACKNOWLEDGE mode provides the best performance but the worst reliability because messages leave the system as soon as they are delivered. Acknowledgement mode is a trade-off between performance and reliability.

Summary

This chapter completes this book’s discussion of Enterprise JavaBeans by presenting the best practices you can adopt to avoid the common pitfalls for developing Session, Entity and Message-Driven beans in the context of WebLogic Server.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset