Packaging session and message-driven beans (EJB 3)

A car manufacturer has to assemble all essential parts of a car before it can run. As an EJB developer you build core classes that make your application, and you have to assemble them as an EJB-JAR and deploy them into your application server before your customers can execute the application.

Throughout this topic we have used annotations and avoided deployment descriptors. The EJB deployment descriptor (ejb-jar.xml) describes the contents of an EJB-JAR, such as beans, interceptors, the resource they use, security, transaction settings, and so forth. For every annotation we have discussed in this topic there is an element in the descriptor. You’ll recall from topic 2 that deployment descriptors can be used to override settings in metadata annotations. Let’s now uncover the elements of ejb-jar.xml and explain how you can define default interceptors. We’ll conclude this section with a discussion on vendor-specific descriptors and annotations.

Packaging EJB-JAR

Session beans and MDBs can be packaged in a Java standard JAR file as defined in the Java Archive specification at http://java.sun.com/j2se/1.5.0/docs/guide/jar/. To create an EJB-JAR file to package your EJB components, you have to compile your EJB classes and then create a JAR file using the jar tool supplied by JDK. For example, you can use the following command to create the adventure-ejb.jar:

tmp651_thumb


This will create a JAR file containing all class files in the current directory, and any subdirectories below the current directory. You can automate building JAR files using several tools. Most modern IDEs support building EJB-JAR modules, and make the creation of JAR modules somewhat transparent to you. A number of specialized utilities in addition to IDEs also support the build process. Today, the most frequently used tool to assist with builds is Apache Ant (http://ant.apache.org/), although there is a strong movement toward Apache Maven (http:// maven.apache.org/). Listing 11.2 shows a sample Ant build script that was created to automate building an EJB-JAR module.

Listing 11.2 Sample script for building an EJB-JAR file

Listing 11.2 Sample script for building an EJB-JAR file

The EJB-JAR file must include the interfaces and bean classes. It may also include any helper classes. Optionally the helper classes may be packaged in a separate JAR file in the EAR file. You have two options:

■ The JAR containing helper classes may be packaged in the lib directory of the EAR file. Using this approach, the packaged classes will be automatically visible to all modules in the EAR module.

■ If you want to limit the visibility to only a specific EJB-JAR or WAR module, you can create an entry in the Manifest.mf file of the module that contains a Class-Path attribute to the JAR file.

Now that you know the structure of EJB-JAR and how to package it, let’s look at the elements of ejb-jar.xml.

Deployment descriptors vs. annotations

An EJB deployment descriptor (ejb-jar.xml) describes the contents of an EJB module, any resources used by it, and security transaction settings. The deployment descriptor is written in XML, and because it is external to the Java byte code, it allows you to separate concerns for development and deployment.

The deployment descriptor is optional and you could use annotations instead, but we don’t advise using annotations in all cases for several reasons. Annotations are great for development, but may not be well suited for deployments where settings may change frequently. During deployment it is common in large companies for different people to be involved for each environment (development, test, production, etc.). For instance, your application requires such resources as DataSource or JMS objects, and the JNDI names for these resources change between these environments. It does not make sense to hard-code these names in the code using annotations. The deployment descriptor allows the deployers to understand the contents and take appropriate action. Keep in mind that even if the deployment descriptor is optional, certain settings such as default interceptors for an EJB-JAR module require a deployment descriptor. An EJB-JAR module may contain

■ A deployment descriptor (ejb-jar.xml)

■ A vendor-specific deployment descriptor, which is required to perform certain configuration settings in a particular EJB container

The good news is that you can mix and match annotations with descriptors by specifying some settings in annotations and others in the deployment descriptor. Be aware that the deployment descriptor is the final source and overrides settings provided through metadata annotations. To clarify, you could set the TransactionAttribute for an EJB method as REQUIRES_NEW using an annotation, and if you set it to required in the deployment descriptor, the final effect will be REQUIRED.

Annotations vs. XML descriptors: the endless debate

Sugar or sugar substitute? It’s a matter of choice. Zero calories versus the risk of cancer? The debate may well be endless, and the same applies to the debate between annotations and deployment descriptors. Some people find annotations elegant, while they see XML as verbose, ugly, and hard to maintain. Others find annotations unsightly, and complain that annotations complicate things by making configurations reside closer to the code. The good thing is that you have a choice, and Java EE allows you to override annotation settings in the code with deployment descriptors if you desire. We suggest you weigh the pros and cons of these options with a clear mind.

Although we won’t delve deeply into deployment descriptors, let’s look at some quick examples to see what deployment descriptors look like so that you can package a deployment descriptor in your EJB module if you need to. Listing 11.3 shows a simple example of a deployment descriptor for the BazaarAdmin EJB.

Listing 11.3 A simple ejb-jar.xml

A simple ejb-jar.xml

If you are familiar with EJB 2, you may have noticed that the only notable difference between this deployment descriptor and one in EJB 2 is that the version attribute must be set to 3.0, and the home element is missing because EJB 3 does not require a home interface.

If you are using deployment descriptors for your EJBs, make sure that you set the ejb-jar version to 3.0 O because this will be used by the Java EE server to determine the version of the EJBs being packaged in an archive. The name element C identifies an EJB and is the same as the name element in the @Stateless annotation. These must match if you are overriding any values specified in the annotation with a descriptor. The session-type element G determines the type of session bean. This value can be either stateless or stateful. You can use transaction-type Q to specify whether the bean uses CMT (Container) or BMT (Bean). The transaction, security, and other assembly details are set using the assembly-descriptor tag of the deployment descriptor Q and 0.

Table 11.3 lists commonly used annotations and their corresponding descriptor tags. Note that as we mentioned earlier there is an element for every annotation. You will need only those which make sense for your development environment. Some of the descriptor elements you’ll probably need are for resource references, interceptor binding, and declarative security. We encourage you to explore these on your own.

Table 11.3 One-to-one mapping between annotations and XML descriptor elements

Annotation

Type

Annotation Element

Corresponding Descriptor Element

tmp6-54

EJB type

tmp6-55
tmp6-56

name

tmp6-57
tmp6-58

EJB type

tmp6-59
tmp6-60 tmp6-61
tmp6-62

EJB type

tmp6-63
tmp6-64

name

tmp6-65
tmp6-66

Interface type

tmp6-67
tmp6-68

Interface type

tmp6-69
tmp6-70

Transaction management type at bean level

tmp6-71

Table 11.3 One-to-one mapping between annotations and XML descriptor elements

Annotation

Type

Annotation Element

Corresponding Descriptor Element

tmp6-72

Transaction settings method

tmp6-73
tmp6-74

Interceptors

tmp6-75
tmp6-76

Interceptors

tmp6-77
tmp6-78

Interceptors

tmp6-79
tmp6-80

Custom interceptor

tmp6-81
tmp6-82

Lifecycle method

tmp6-83
tmp6-84

Lifecycle method

tmp6-85
tmp6-86

Lifecycle method

tmp6-87
tmp6-88

Lifecycle method

tmp6-89
tmp6-90

Security setting

tmp6-91
tmp6-92

Security setting

tmp6-93
tmp6-94

Security setting

tmp6-95
tmp6-96

Security setting

tmp6-97
tmp6-98

Security setting

tmp6-99
tmp6-100

Resource references (DataSource, JMS, Environment, mail, etc.)

tmp6-101
tmp6-102

Resource injection

Setter/field injection

tmp6-103
tmp6-104

EJB references

tmp6-105
tmp6-106

Persistence context reference

tmp6-107
tmp6-108

Persistence unit reference

tmp6-109

You can find the XML schema for the EJB 3 deployment descriptor at http:// java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd.

Overriding annotations with deployment descriptors

As we explained, you can mix and match deployment descriptors with annotations and use descriptors to override settings originally specified using annotations. Keep in mind that the more you mix the two, the more likely you are to make mistakes and create a debugging nightmare.

NOTE The basic rule to remember is that the name element in stateless, stateful, and message-driven annotations is the same as the ejb-name element in the descriptor. If you do not specify the name element with these annotations, the name of the bean class is understood to be the ejb-name element. This means that when you are overriding an annotation setting with your deployment descriptor, the ejb-name element must match the bean class name.

Suppose we have a stateless session bean that uses these annotations:

tmp6110_thumb1

The value for the name element specified is BazaarAdmin, which is the same as the value of the ejb-name element specified in the deployment descriptor:

tmp6111_thumb

If you do not specify the name element, the container will use the name of BazaarAdminBean as the name of the bean class, and in order to override annotations you have to use that name in the deployment descriptor:

tmp6112_thumb

We used @TransactionAttribute to specify that the transaction attribute for a bean method be requires_new. If we want to override it to use required,1 then we use the following descriptor:

tmp6113_thumb1

In this example, we used the assembly-descriptor element to specify a transaction attribute Q. In addition, the ejb-name element O in the assembly-descriptor matches the original name specified with the @Stateless annotation in the bean class.

Specifying default interceptor settings

Interceptors (as you’ll recall from topic 5) allow you to implement cross-cutting code in an elegant manner. An interceptor can be defined at the class or method level, or a default interceptor can be defined at the module level for all EJB classes in the EJB-JAR. We mentioned that default interceptors for an EJB module can only be defined in the deployment descriptor (ejb-jar.xml). Listing 11.4 shows how to specify default interceptors for an EJB module.

Listing 11.4 Default interceptor setting in ejb-jar.xml

Listing 11.4 Default interceptor setting in ejb-jar.xml

The interceptor-binding O tag defines the binding of interceptors to a particular EJB with the ejb-name element. If we want to define the default interceptor or an interceptor binding for all EJBs in the EJB module, then we can specify * as the value for ejb-name Q. We specify a class to use as the interceptor with the <interceptor-class> tag. As evident from the listing, you can specify multiple interceptors in the same binding, and the order in which they are specified in the deployment descriptor determines the order of execution for the interceptor. In our example, CheckPermissionlnterceptor will be executed prior to ActionBazaarDefaultlnterceptor when any EJB method is executed.

If you want a refresher on how interceptors work, make a quick detour back to topic 5 and then rejoin us here. We’ll wait…

Using vendor-specific annotations and descriptors

We’ve already explained that stateless session beans and MDBs may be pooled. In addition, you can configure passivation for stateful session beans, and you can set up the handling of poisonous messages for MDBs. However, we have not discussed configuration details for either of these scenarios. Unfortunately, these configurations are left to the vendors as proprietary features, and they can be supported with proprietary annotations, proprietary deployment descriptors, or both. Table 11.4 lists the name of the deployment descriptor file for some popular application servers.

Table 11.4 Vendor-specific deployment descriptors for popular application servers

Application Server

Vendor-Specific Deployment Descriptor

BEA WebLogic

tmp6-115

IBM WebSphere

tmp6-116

JBoss

tmp6-117

Oracle Application Server

tmp6-118

Sun GlassFish

tmp6-119

Many developers shun deployment descriptors as a matter of inconvenience. Application server vendors will continue to provide support for annotations that match deployment descriptor elements, as developers voice their preference for these features. Chances are that each vendor has a set of proprietary annotations to set configuration information with the code.

For example, you can use the oracle.j2ee.ejb.StatelessDeployment proprietary annotation to provide configuration information such as pooling and transaction management for stateless session beans. Look at the following code, which configures pooling with Oracle’s proprietary annotation:

tmp6120_thumb1

As other Java EE vendors create their implementations of EJB 3, we anticipate that each vendor will devise its own subset of corresponding annotations as well.

You should review these proprietary annotations with caution for a couple of reasons. First, adding configuration information in the code is not a good idea, although application servers provide the ability to override this information with their proprietary deployment descriptors. This is not desirable because in order to make a change to the setting, the code must be edited and compiled, and in most organizations it must go through a significant quality assurance effort before being released to production. Another reason is that as the code is promoted across different environments (Development, Test, Production, etc.), the deployer may change the configuration to accommodate different servers and environmental configurations.

Second, this defeats the goal of portability of applications. Deployment descriptors serve as a guideline to the deployer to understand the contents, the applications, and the suggested configurations. Deployers manage the deployment to each environment by tweaking the configuration. We recommend using the proprietary deployment descriptors instead of using deployment annotations. If you’re using Oracle, you could use the following element in Oracle’s proprietary descriptor (orion-ejb-jar.xml) element as follows:

tmp6121_thumb1

This concludes our discussion on packaging session beans and message-driven beans. Next we take a peek at packaging entities. Can you feel the anticipation building?

Next post:

Previous post: