<< J2EE design decisions | 首页 | High availability Tomcat >>

EJB fundamentals and session beans

By Jim Crume, Kevin Mukhar, James L. Weaver, Chris Zelenak

Java Enterprise Edition (Java EE) has a powerful facility dedicated to expressing the business logic of an application and for accessing a database using a JavaBeans-like concept. That facility is Enterprise JavaBeans, known as EJBs for short.

In this article, we'll begin exploring the world of EJBs, which is a very important capability of the Java EE platform. EJBs provide infrastructure for developing and deploying mission-critical, enterprise applications. We'll first look at some EJB fundamentals, and then focus on one type of EJB: the session bean.

In this article, you will learn the following:

 

  • The benefits of using EJBs
  • The three kinds of EJBs: session, entity, and message-driven beans
  • The makeup of session beans
  • How to develop session beans
  • Differences between stateful and stateless session beans

Understanding EJBs
Application architectures often consist of several tiers that each has its own responsibilities. One such architecture that consists of three tiers is illustrated in the Unified Modeling Language (UML) diagram shown in Figure 1.

 

 

 

 

 
The two elements on the left side of the diagram in Figure 1 are called components in the UML notation. Components represent software modules. The diagram describes what is called a multitiered, or layered, architecture. Multitiered architectures have many advantages, not the least of which is the ability to change any one of the layers without affecting all of the other layers. This is in contrast to a single-tier architecture, within which all aspects of the program design coexist in a single element. Changes or actions that affect one portion of the single-tier element also potentially affect the other members of that element.
Consider the three-layer architecture shown in Figure 1, consisting of user interface, application logic, and database layers. If the database layer is changed, only the application logic layer is affected. The application logic layer shields the user interface layer from changes to the database layer. This facilitates ongoing maintenance of the application and also increases the application's ability to incorporate new technologies in its layers.
These layers provide an excellent model of how EJBs fit into your overall program design. EJBs provide an application logic layer and a JavaBeans-like abstraction of the database layer. The application logic layer is also known as the middle tier.
Note
JavaBeans and Enterprise JavaBeans are two different things, but because of their similarities (and for marketing reasons), they share a common name. JavaBeans are components built in Java that can be used on any tier in an application. They are often thought of in relationship to servlets and as GUI components. Enterprise JavaBeans are special, server-based components, used for building the business logic and data access functionality of an application.
Why use EJBs?
Not too long ago, when system developers wanted to create an enterprise application, they would often start by "rolling their own" (or purchasing a proprietary) application server to support the functionality of the application logic layer. Some of the features of an application server include the following:
 
  • Client communication: The client, which is often a user interface, must be able to call the methods of objects on the application server via agreed-upon protocols.
  • Session state management: You'll recall our discussions on this topic in the context of JSP (JavaServer Pages) and servlet development back in Chapter 6.
  • Transaction management: Some operations, for example, when updating data, must occur as a unit of work. If one update fails, they all should fail.
  • Database connection management: An application server must connect to a database, often using pools of database connections for optimizing resources.
  • User authentication and role-based authorization: Users of an application must often log in for security purposes. The functionality of an application to which a user is allowed access is often based on the role associated with a user ID.
  • Asynchronous messaging: Applications often need to communicate with other systems in an asynchronous manner; that is, without waiting for the other system to respond. This requires an underlying messaging system that provides guaranteed delivery of these asynchronous messages.
  • Application server administration: Application servers must be administered. For example, they need to be monitored and tuned.

The EJB specification
The EJB specification defines a common architecture, which has prompted several vendors to build application servers that comply with this specification. Now developers can get off-the-shelf application servers that comply with a common standard, benefiting from the competition (in areas such as price, features, and performance) among those vendors.

Some of the more common commercial EJB application servers are WebLogic (BEA), Java Enterprise System (Sun), OC4J containers for Oracle Database 10g, and WebSphere (IBM). There are also some very good open source entries in this market such as JBoss and JOnAS. Sun also provides an open source reference implementation (Java EE SDK) of the Java EE 5 and EJB 3.0 specifications that developers can use to develop and test applications for compliance with those specifications. (The reference implementation may not, however, be used to deploy production systems.) Currently under development, the reference implementation is codenamed "Glassfish." The platform provides a basic EJB 3.0 test platform; more details can be found on the Website and in the related discussion forums. These application servers, in conjunction with the capabilities defined in the EJB specification, support all of the features listed here and many more.

The EJB specification was created by experienced members of the development community; such a body is called an expert group. In the EJB specification's expert group are members from such organizations as JBoss, Oracle, and Google. Thanks to them, we now have a standard, specifications-based way to develop and deploy enterprise-class systems. We are approaching the Java dream of developing an application that can run on any vendor platform as-is. This is in contrast to the vendor-specific way we used to develop, where each server had its own way of doing things, and where the developer was locked into the chosen platform once the first line of code was written!

The version of the EJB specification that is included with the Java EE 5.0 recommendation is 3.0, and this is the version we refer to when discussing EJBs. The EJB 3.0 specification has added many improvements to its predecessor (version 2.1, which was a part of the J2EE 1.4 recommendation), including metadata annotations to simplify deployment concerns, a higher degree of control over bean persistence, and a much more simplified (but no less powerful) programming model for developing EJBs.

The three kinds of EJBs
There are actually three kinds of EJBs: session beans, entity beans, and message-driven beans. Here, we will present a brief introduction to each type of bean. The balance of this article will then focus on session beans.

 

Note
When referring to EJBs in the general sense, we'll use the term EJBs, enterprise beans, or simply beans.

 

Session beans
One way to think about the application logic layer (middle tier) in the sample architecture shown in Figure 1 is as a set of objects that, together, implement the business logic of an application. Session beans are the construct in EJBs designed for this purpose. As shown in Figure 2, there may be multiple session beans in an application. Each handles a subset of the application's business logic.

A session bean tends to be responsible for a group of related functionality. For example, an application for an educational institution might have a session bean whose methods contain logic for handling student records. Another session bean might contain logic that maintains the lists of courses and programs available at that institution.

There are two types of session beans, which are defined by their use in a client interaction:

 

  • Stateless: These beans do not declare any instance (class-level) variables, so that the methods contained within can act only on any local parameters. There is no way to maintain state across method calls.
  • Stateful: These beans can hold client state across method invocations. This is possible with the use of instance variables declared in the class definition. The client will then set the values for these variables and use these values in other method calls.

There may be more work involved for the server to share stateful session beans than is required to share stateless beans. Storing the state of an EJB is a very resource-intensive process, so an application that uses stateful beans may not be easily scalable. Stateless session beans provide excellent scalability, because the EJB container does not need to keep track of their state across method calls. You'll see how to develop both stateless and stateful session beans later in this article.

All EJBs, session beans included, operate within the context of an EJB server, as shown in Figure 2. An EJB server contains constructs known as EJB containers, which are responsible for providing an operating environment for managing and providing services to the EJBs that are running within it.

In a typical scenario, the user interface (UI) of an application calls the methods of the session beans as it requires the functionality that they provide. Session beans can call other session beans and entity beans. Figure 2 illustrates typical interactions between the user interface, session beans, entity beans, and the database.

 

 

 

 

 

Entity beans
Before object orientation became popular, programs were usually written in procedural languages and often employed relational databases to hold the data. Because of the strengths and maturity of relational database technology, it is now often advantageous to develop object-oriented applications that use relational databases. The problem with this approach is that there is an inherent difference between object-oriented and relational database technologies, making it less than natural for them to coexist in one application. The use of entity beans is one way to get the best of both of these worlds, for the following reasons:

 

  • Entity beans are objects, and they can be designed using object-oriented principles and used in applications as objects.
  • The data in these entity bean objects are persisted in some data store, usually relational databases. All of the benefits of relational technologies—including maturity of products, speed, reliability, ability to recover, and ease of querying—can be leveraged.

In a typical EJB scenario, when a session bean needs to access data, it calls the methods of an entity bean. Entity beans represent the persistent data in an EJB application. For example, an application for an educational institution might have an entity bean named Student that has one instance for every student that is enrolled in an institution. Entity beans, often backed by a relational database, read and write to tables in the database. Because of this, they provide an object-oriented abstraction to some information store.

As shown in Figure 2, it is a good practice to call only session beans directly from the client, and to let the session beans call the entity beans. Here are some reasons for this:

 

  • This practice doesn't circumvent the business logic contained in the session beans. Calling entity beans directly tends to push the business logic into the UI logic, which is usually a bad thing.
  • The UI doesn't need to be as dependent on changes to the entity beans. The UI is shielded from these changes by the session beans.
  • In order for a client to interact with a bean on the EJB server, there must be a remote reference to the bean, which takes resources. There tends to be far more (orders of magnitude) entity bean instances in an application than session bean instances. Restricting client access to session beans conserves server and network resources considerably.

 

Note
Developing entity beans does not require a business interface; in fact, message-driven beans are the only EJBs that must implement some business interface.

 

Message-driven beans
When an EJB-based application needs to receive asynchronous messages from other systems, it can leverage the power and convenience of message-driven beans. Asynchronous messages between systems can be analogous to the events that are fired from a UI component to an event handler in the same JVM. For example, in the business-to-business (B2B) domain, a wholesaler could have an EJB application that uses message-driven beans to listen for purchase orders issued electronically from retailers.

Which type of EJB should you use?
So, how do you decide whether a given EJB should be a session bean, entity bean, or a message-driven bean? Here are some guidelines for deciding:

 

  • Session beans are great at implementing business logic, processes, and workflow. For example, a StockTrader bean with buy() and sell() methods, among others, would be a good fit for a session bean.
  • Entity beans are the persistent data objects in an EJB application. In a stock trading application, a Stock bean with setPrice() and getPrice()methods would be an appropriate use of an entity bean. The buy() method of the previously mentioned StockTrader session bean would interact with instances of the Stock entity bean by calling their getPrice() methods, for example.
  • Message-driven beans are used for the special purpose of receiving asynchronous messages from other systems, like a wholesaler application that listens for purchase orders.

Now that we've covered some basics concerning the three types of EJBs, we'll use the rest of this article to take a closer look at the first type mentioned: session beans.

The anatomy of a session bean
Every session bean requires the presence of a bean interface and a bean class. A bean interface is the mechanism by which client code will interact with the bean internals, while the bean class is the implementation of those internals, as illustrated in Figure 3.

 

 

 

 

 

The implementation of the business logic of a session bean is located in its bean class. The bean class of the session bean must either implement the javax.ejb.SessionBean interface or prefix its class definition with the metadata descriptor @Stateless.

 

Note
Metadata is a new addition to the Java language with the introduction of J2SE 5.0. It effectively allows developers to elaborate on class definitions, adding further descriptive and behavioral information to the generation of the class file. The EJB 3.0 specification has used this facility to describe the majority of its workings. To learn more about this new addition to the Java language, read the official specification.

 

The bean interface (or business interface, as some refer to it) that exposes the internals of the EJB to calling code may be implemented by the developer, or it can be generated automatically. The compiler will create a bean interface for you that is a map of the public methods available in the bean class.

As a naming convention, we'll append the word Bean to the name of a bean to indicate that it is a bean class. For example, a session bean with the name StockTrader would have a bean class named StockTraderBean.

Developing session beans
It is now time to put all this theory into practice. In this section, we're going to develop our first session bean in an example that's on par with the traditional "Hello World!" sample program.

First, we'll walk through the bean-creation code in a good bit of detail, reinforcing concepts we just covered and introducing new ones. Then we'll explain how to compile the example. For this, we'll use the Java compiler that comes with the Java 2 Platform, Standard Edition 5.0. Finally, we'll deploy the example in JBoss.

Using a stateless session bean
Since this is the first EJB example, we're going to walk through the code now and then run it later. There are three Java source files for this example: SimpleSession.java, SimpleSessionBean.java, and SimpleSessionClient.java.

Listing 1 shows the code for the remote business interface, SimpleSession.java.

 

Note
The term remote business interface signifies that this interface is accessed and called by "remote" clients. Don't jump to conclusions! We'll define what exactly is meant by that statement when we explain this code later on in the article.

 

Listing 1. SimpleSession.java

package beans;

import javax.ejb.Remote;

@Remote
public interface SimpleSession
{
public String getEchoString(String clientString);
}

 

Listing 2 shows the code for the actual bean implementation, SimpleSessionBean.java.

Listing 2. SimpleSessionBean.java

package beans;

import javax.ejb.Stateless;

@Stateless
public class SimpleSessionBean implements SimpleSession {
public String getEchoString(String clientString) {
return clientString + " - from session bean";
}
}

 

Finally, Listing 3 shows the client code to test the session bean.

Listing 3. SimpleSessionClient.java

package client;

import beans.SimpleSession;
import javax.naming.InitialContext;

public class SimpleSessionClient {
public static void main(String[] args) throws Exception
{
InitialContext ctx = new InitialContext();
SimpleSession simpleSession
= (SimpleSession) ctx.lookup(SimpleSession.class.getName());
for (int i = 0; i < args.length; i++) {
String returnedString = simpleSession.getEchoString(args[i]);
System.out.println("sent string: " + args[i] +", received string: " + returnedString);
}
}
}

 

Organize the files in a directory called SimpleSessionApp, as shown in Figure 4.

 

 

 

 

 
Compiling the simple session bean application
After you've created and organized the sample session bean files as just described, follow these steps to compile the application:
 
  1. Open a command prompt in the SimpleSessionApp directory.
  2. Compile the classes, ensuring that the CLASSPATH is set to contain all the necessary JBoss libraries. These libraries contain all of the EJB functionality needed to make your code interact with the application server, so it is extremely important that you get this step right. At the command line, type the following (this should all be on one line):

    > set CLASSPATH=.;C:\jboss\lib\concurrent.jar;
    C:\jboss\lib\jboss-common.jar;
    c:\jboss\client\jboss-j2ee.jar;
    c:\jboss\lib\commons-httpclient.jar;

    C:\jboss\server\all\lib\jboss.jar;
    C:\jboss\server\all\lib\jboss-remoting.jar;
    C:\jboss\server\all\lib\jboss-transaction.jar;
    C:\jboss\server\all\lib\jnpserver.jar;
    C:\jboss\server\all\deploy\ejb3.deployer\jboss-ejb3.jar;
    C:\jboss\server\all\deploy\ejb3.deployer\jboss-ejb3x.jar;
    C:\jboss\server\all\deploy\jboss-aop.deployer\
    jboss-aop.jar;
    C:\jboss\server\all\deploy\jboss-aop.deployer\
    jboss-aspect-library.jar

     

     

  3. Within the SimpleSessionApp directory where the client and beans directories are located, execute the following commands from the command prompt:

    > javac -d . client/*.java
    > javac -d . beans/*.java

     

     

    The –d option tells the Java compiler to place the class files in subdirectories matching their package structure, subordinate to the given directory. In this case, the given directory is the current directory, signified by the period. As a result, the Java class files should end up in the same directories as the source files.

Deploying the simple session bean application
Now we need to start the JBoss Server. Once the JBoss Server is up and running, you can deploy your class files. In order to deploy your class files, you need to package your different application components together in a compressed jar file. Make the extension of this file .ejb3, so that JBoss can deploy it. To create the application EJB3 file, open a command prompt in the same directory that SimpleSessionApp resides in and type in the following command:

>jar cf SimpleSessionApp.ejb3 beans\*.java

 

Now copy the resulting EJB3 file to the %JBOSS_HOME%/server/all/deploy directory. If your JBoss installation is in C:\JBoss, for example, copy the file to C:\JBoss\server\all\deploy.

JBoss will automatically detect and deploy your code for you. The directory structure should now have the files shown in Figure 5.

 

 

 

 

 
Now for the last step: running your new bean!
Running the simple session bean application
To run the sample client, set the CLASSPATH to the same value you did earlier to compile the application.
On a default Java EE 5 SDK Windows installation, ensure the CLASSPATH is set correctly by using the following command:
 
> set CLASSPATH=.;C:\jboss\lib\concurrent.jar;
C:\jboss\lib\jboss-common.jar;
C:\jboss\server\all\lib\jboss.jar;
C:\jboss\server\all\lib\jboss-remoting.jar;
C:\jboss\server\all\lib\jboss-transaction.jar;
C:\jboss\server\all\lib\jnpserver.jar;
C:\jboss\server\all\deploy\ejb3.deployer\jboss-ejb3.jar;
C:\jboss\server\all\deploy\ejb3.deployer\jboss-ejb3x.jar;
C:\jboss\server\all\deploy\jboss-aop.deployer\jboss-aop.jar;
C:\jboss\server\all\deploy\jboss-aop.deployer\
jboss-aspect-library.jar
 
Next, with SimpleSessionApp as the current directory, execute the following command from the command prompt (remember that this is all one line):
 
> java
-Djava.naming.factory.initial=
org.jnp.interfaces.NamingContextFactory
-Djava.naming.factory.url.pkgs=
org.jboss.naming:org.jnp.interfaces
-Djava.naming.provider.url=
localhost client.SimpleSessionClient
Now is the time for all good men
 
When you run the SimpleSession client program, it will produce the following output:
 
sent string: Now, received string: Now
sent string: is, received string: is
sent string: the, received string: the
sent string: time, received string: time
sent string: for, received string: for
sent string: all, received string: all
sent string: good, received string: good
sent string: men, received string: men
 
It may not seem very practical, but it makes you unbelievably popular at parties.
Reviewing the stateless session bean source code
We have three Java source files to walk through here. We'll start with the client and work our way back up to the session bean interface and class.
The main() method of the SimpleSession class kicks things off by using the JNDI (Java Naming and Directory Interface) to help us get a reference to the business interface of the session bean. JNDI provides a common interface to directory services (this includes LDAP, CORBA providers, and in this case, your local filesystem). The directory that we're dealing with here is internal to the EJB server and holds the reference to the business interface of our session bean. That reference is accessed by providing the JNDI lookup with the bean interface's qualified name. We could also specify the bean's location by absolute JNDI pathname, passing the lookup() function the string literal ejb/ beans.SimpleSession.
Once the lookup() function has returned an object for our use, we immediately cast it to the base interface SimpleSession. Pay special attention to our decision to acquire a JNDI reference by using the SimpleSession class name. By requesting a JNDI reference for an interface annotated by the @Remote metadata descriptor, we have implicitly stated the method that we wish to use to communicate with the bean—pretty cool, huh?
 
InitialContext ctx = new InitialContext();
SimpleSession simpleSession
= (SimpleSession) ctx.lookup(SimpleSession.class.getName());
 
The client code for this example, which follows, demonstrates that we can pass an argument to a method of a session bean that exists on the server, operate on the argument in the method, and return a different value to the client. More specifically, the code loops through the arguments that were passed to the client's main() method via the command line, and passes them one at a time to the getEchoString() method of the session bean class. This is accomplished by calling the getEchoString() method of the bean interface that exists on the client:
 
for (int i = 0; i < args.length; i++) {
String returnedString = simpleSession.getEchoString(args[i]);
System.out.println("sent string: " + args[i] +", received string: " + returnedString);
}
 
Note that invoking the getEchoString() method of the bean interface on the client invokes the getEchoString() method of the session bean class on the server. This is possible through the use of remoting, the mechanism by which method calls present on the server hosting the bean are remotely invocated.
The business method of our session bean that the client class calls takes a String argument passed in and returns that same string with a status message appended to it back to the calling client:
 
public String getEchoString(String clientString) {
return clientString + " - from session bean";
}
 
This method is also defined in the bean interface specified in the SimpleSession.java code listing:
 
public String getEchoString(String clientString);
 
The bean interface deserves a second look for one very important reason: metadata.
 
import javax.ejb.Remote;

@Remote
public interface SimpleSession
 
While the @Remote may not look like much, its presence is extremely relevant to the development of the session bean. This annotation tells the compiler and EJB container that the interface in question is to be made available to remote clients. The compiler will provide the interface with all the necessary functionality that is needed to let remote clients invoke methods from the EJB container directly, and all you needed to do was add an extra argument to your interface declaration. If it were any easier, the program would be coding itself.
Speaking of easy, take another look at the SimpleSessionBean.java file; take particular note of the @Stateless annotation.
 
package beans;

import javax.ejb.Stateless;

@Stateless
public class SimpleSessionBean implements SimpleSession
 
The @Stateless descriptor is an instruction to the compiler and EJB container, indicating that the class file in question should be deployed and managed as a stateless session bean. As discussed earlier in the article, this annotation is the primary method you'll use to develop your EJBs.
In this SimpleSessionApp example, you learned how to develop a session bean, including how to deploy and start it in a Java EE application server. You also learned how to develop a client application that uses session beans. Because the SimpleSessionApp was deployed as a stateless session bean, it can't be counted on to retain data between method invocations. The next section will introduce the idea of a stateful session bean and compare these two types.
Choosing between stateful and stateless session beans
As mentioned previously, session beans are a great choice for implementing business logic, processes, and workflow. When you choose to use a session bean to implement that logic, you have yet another choice to make: whether to make that session bean stateful or stateless.
Consider a fictitious stock trading application where the client uses the buy() and getTotalPrice() methods of a StockTrader session bean. If the user has several different stocks to buy and wants to see the running total price on the tentative purchases, then that state needs to be stored somewhere. One place to store that kind of transient information is in the instance variables of the session bean itself. This requires that the session bean be defined as stateful by usage of the @Stateful bean class metadata descriptor.
There are advantages and disadvantages to making a session bean stateful. The following are some of the advantages:
 
  • Transient information, such as that described in the stock trading scenario, can be stored easily in the instance variables of the session bean, as opposed to defining and using entity beans (or JDBC) to store it in a database.
  • Since this transient information is stored in the session bean, the client doesn't need to store it and potentially waste bandwidth by sending the session bean the same information repeatedly with each call to a session bean method. This bandwidth issue is a big deal when the client is installed on a user's machine that invokes the session bean methods over a phone modem, for example. Bandwidth is also an issue when the data is very large or needs to be sent many times repeatedly.

The main disadvantage is that stateful session beans don't scale up as well on an EJB server, because they require more system resources than stateless session beans do. Not only do stateful session beans require memory to store the state, but they also can be swapped in and out of memory (activated and deactivated) as the EJB container deems necessary to manage server resources. The state gets stored in a more permanent form whenever a session bean is deactivated, and that state is loaded back in when the bean is activated.

 

Note
The generic bean interface from which all EJBs derive defines several session bean lifecycle methods, including ejbActivate() and ejbRemove(). A stateful session bean class can implement these callback methods to cause special processing to occur when it is activated or removed.

 

Using a stateful session bean
Let's look at an example of using a stateful session bean in a generally familiar context: the common calculator. This example mimics some very simple calculator operations: adding, subtracting, and keeping a running total. (This may not be very impressive by today's standards, but you would have paid good money for a calculator with those functions in the early 1970s!) That "keeping a running total" part is what demonstrates the use of a stateful session bean. Figure 6 shows the GUI client for this example.

 

 

 

 

 
There are three Java source files in this example: Calculator.java (in the beans package), CalculatorBean.java (in the beans package), and CalculatorClient.java (in the client package). Since CalculatorClient.java focuses primarily on presentation, we won't list it here.
Listing 4 shows the code for the bean interface, Calculator.java. It defines the business method of the calculator.
Listing 4. Calculator.java
 
package beans;

import javax.ejb.Remote;

@Remote
public interface Calculator {
public void clearIt();
public void calculate(String operation, int value);
public int getValue();
}
 
Listing 5 shows the code for the bean class, CalculatorBean.java.
Listing 5. CalculatorBean.java
 
package beans;

import javax.ejb.Stateful;

@Stateful
public class CalculatorBean implements Calculator {
private int _value = 0;
public void clearIt() {
_value = 0;
}
public void calculate(String operation, int value) {
if (operation.equals("+")) {
_value = _value + value;
return;
}
if (operation.equals("-")) {
_value = _value - value;
return;
}
}
public int getValue() {
return _value;
}
}
 
Add these code files to a new application directory called SimpleCalculatorApp. Within the directory add beans and client subdirectories. Place Calculator.java and CalculatorBean.java in the beans directory, and CalculatorClient.java in the client directory.
Now compile the .java files following the same instructions as in the previous example. At the command line, type the following (again, remember that this is all on one line):
 
> set CLASSPATH=.;C:\jboss\lib\concurrent.jar;C:\jboss\lib\jboss-common.jar;
C:\jboss\server\all\lib\jboss.jar;
C:\jboss\server\all\lib\jboss-remoting.jar;
C:\jboss\server\all\lib\jboss-transaction.jar;
C:\jboss\server\all\lib\jnpserver.jar;
C:\jboss\server\all\deploy\ejb3.deployer\jboss-ejb3.jar;
C:\jboss\server\all\deploy\ejb3.deployer\jboss-ejb3x.jar;
C:\jboss\server\all\deploy\jboss-aop.deployer\
jboss-aop.jar;
C:\jboss\server\all\deploy\jboss-aop.deployer\
jboss-aspect-library.jar
 
Next, within the SimpleCalculatorApp directory where the client and beans directories are located, execute the following commands from the command prompt:
 
> javac -d . client/*.java
> javac -d . beans/*.java
 
Now enter the following command at the prompt:
 
>jar cf SimpleCalculatorApp.ejb3 SimpleCalculatorApp
 
Then copy the resulting EJB3 file to your JBoss deployment directory:
 
%JBOSS_HOME%\server\all\deploy.
 
Running the stateful session bean application
After deploying the application, you can now run it. On a default Java EE 5 SDK/JBoss Windows installation, the CLASSPATH would be set correctly by using the following command:
 
> set CLASSPATH=.;C:\jboss\lib\concurrent.jar;
C:\jboss\lib\jboss-common.jar;
C:\jboss\server\all\lib\jboss.jar;
C:\jboss\server\all\lib\jboss-remoting.jar;
C:\jboss\server\all\lib\jboss-transaction.jar;
C:\jboss\server\all\lib\jnpserver.jar;
C:\jboss\server\all\deploy\ejb3.deployer\jboss-ejb3.jar;
C:\jboss\server\all\deploy\ejb3.deployer\jboss-ejb3x.jar;
C:\jboss\server\all\deploy\jboss-aop.deployer\
jboss-aop.jar;
C:\jboss\server\all\deploy\jboss-aop.deployer\
jboss-aspect-library.jar
 
Next, with SimpleCalculatorApp as the current directory, execute the following command from the operating system prompt:
 
> java
-Djava.naming.factory.initial=
org.jnp.interfaces.NamingContextFactory
-Djava.naming.factory.url.pkgs=
org.jboss.naming:org.jnp.interfaces
-Djava.naming.provider.url=
localhost client.CalculatorClient
 
The GUI of the client should appear, as shown earlier in Figure 6.
To operate the calculator, type a number into the text box, select an operation (+ or -) from the drop-down list, and click the = button. The running total will be displayed beside the Calculator value label.
Reviewing the stateful session bean source code
To understand how this example works, we'll walk through some of the GUI client code contained in the CalculatorClient.java source file, and then we'll take a closer look at the EJB code.
Note
In the code examples, you'll notice that some of the import statements are wildcards and some explicitly name the class or interface. For instructional purposes, we've chosen to be explicit on the imports that are relevant to Java EE. We've chosen to be more frugal with lines of code by using wildcards for the more familiar ones that are relevant to J2SE.
The client is a standard Java Swing application, complete with GUI components and event-handler methods. The client needs to call methods of the stateful session bean, so as in the previous example, it gets a reference to the bean's remote interface and gets a reference to the session bean on the server. The code that performs this is in the getCalculator() method of the CalculatorClient class, which is called from the constructor:
 
private Calculator getCalculator() {
Calculator calculator = null;
try {
// Get a naming context
InitialContext ctx = new InitialContext();

// Get a Calculator
calculator
= (Calculator) ctx.lookup(Calculator.class.getName());
} catch(Exception e) {
e.printStackTrace();
}

return calculator;
}
 
When the = button is clicked, two things are passed to the calculate() method of the calculator session bean: the operator (either + or -) and the value to be added or subtracted from the running total:
 
_calculator.calculate(oper, operVal);
 
Since it is a stateful session bean, it is able to store the running total in an instance variable. The client then calls the getValue() method of the calculator session bean to retrieve the running total and subsequently display it:
 
_topNumber.setText("" + _calculator.getValue());
 
When the user clicks the Clear button, the clearIt() method of the calculator session bean is called, which sets the running total to 0.
The implementations of the three calculator business methods of the CalculatorBean class follow. They manipulate the instance variable named _value, which holds the running total between invocations of any of these calculator session bean methods.
 
private int _value = 0;
public void clearIt() {
_value = 0;
}
public void calculate(String operation, int value) {
if (operation.equals("+")) {
_value = _value + value;
return;
}
if (operation.equals("-")) {
_value = _value - value;
return;
}
}
public int getValue() {
return _value;
}
 
The bean indicates its use by the presence of the @Stateful metadata descriptor, just as our earlier bean indicated it was stateless by the use of the @Stateless descriptor. This pattern will follow throughout much of Java EE 5. Much of the hard work present in earlier versions of Java EE has been abstracted into the implementation behind the metadata descriptors.
Keep in mind that a session bean that holds values in instance variables should never be configured as stateless, because the values of the instance variables are not predictable. This is because the EJB container has complete control over managing stateless (and stateful) session beans, including initializing the values of instance variables as the bean is shared among various clients. This is a common trap because sometimes the values are retained, giving a false indication that everything is okay, and then one day, you can't figure out why the program isn't working correctly. From personal experience, that's a fun one to diagnose!
Summary
In this article, we explained what EJBs are and built a case for using them. We touched on the three types of EJBs: session beans, entity beans, and message-driven beans. The balance of this article was then devoted to session beans, and we started that discussion by explaining that session beans are made up of two parts: the bean interface and the bean class. After finishing this article, you should know:
 
  • What EJBs are, the different types of EJB, and their general behavior.
  • How to create stateful and stateless session beans using the @Stateful and @Stateless metadata descriptors. You should also know how to invoke your session bean from a remote client by using a remote bean interface annotated by the @Remote descriptor. Making your application accessible to client applications is best facilitated by using session beans and will allow you to better focus your application's design by abstracting away the client concerns.
  • The difference between stateful and stateless session beans. Stateful session beans are most suitable in situations where you must retain some information about the client's interaction with your application. Stateless session beans are best deployed when you need a very simple, low-overhead interface for your application's clients.
  • How to deploy your EJB using the JBoss Server, and how to create a simple client application that will use the application server to invoke your EJB's functionality.

 

About the author
Jim Crume is a Java architect at Fusion Alliance, an Indianapolis, Indiana-based consulting company that specializes in Web application development. Crume has spent many years as a consultant and specializes in architecting and developing Web-based systems, but he particularly enjoys Java.

Kevin Mukhar is a software developer in Colorado Springs, Colorado. For the past seven years, he has worked on various software systems using different Java enterprise technologies. He has coauthored several other books, including Beginning Java Databases and The Ultimate Palm Robot. In addition to developing software during the day, he is working on a master’s degree in computer science.

James L. Weaver is the chief scientist at Learning Assistant Technologies, a company that specializes in developing learner-centric tools. He is also the president of JMentor, a Java mentoring, training, and consulting practice.

Chris Zelenak is a programmer at Learning Assistant Technologies, where he helps in the development of server-side Cocoon and Rails applications, Java and .Net client applications, and rampant devil’s advocacy. He recently graduated from the computer science department of Indiana Wesleyan University

 

标签 : ,



发表评论 发送引用通报