Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Professional Java.JDK.5.Edition (Wrox)

.pdf
Скачиваний:
32
Добавлен:
29.02.2016
Размер:
12.07 Mб
Скачать

Chapter 10

Types of EJBs

There are four basic types of EJBs that compose the following discussion: Stateless-Session, StatefulSession, Entity, and Message-Driven beans. Each type has a specific purpose and it is important that you understand each type before deciding on the EJB architectural design for your system.

Session Beans

Session beans contain session information about the clients they are interacting with. Session beans operate on a single client and their life spans are usually very short-lived. They can be transaction aware and interface with shared data sources. The container class can handle a large number of session beans concurrently. If the container was to crash, session beans would lose all the information that they contain. This means the clients would have to reconnect to the session beans and start over.

Stateless-Session

The name stateless simply means that an instance of the bean contains no state information for a particular client. Therefore, many instances of this bean can be created and used by any client that requires its uses. The container can manage different instances of these beans as needed. Only one thread can be associated with a bean at any time, so it is sometimes necessary to have multiple instances of stateless-session beans available for use. Otherwise, clients would have to wait for the instance of the stateless-session bean to be released before they could use it.

Stateful-Session

The opposite of stateless-session beans, stateful-session beans are dedicated to a particular client. The container manages this dedication. In the event that the container has an enormous amount of client stateful-session beans to manage, it can remove the bean from RAM and store it on disk in a state called passivate. When the bean is needed again by the container, it can read it into memory from disk. This prevents the container from filling up the machine’s RAM with stateful-session beans.

A good example of a stateful-session bean is an online Web site that possesses a shopping cart mechanism. An online shopping cart keeps track of items that a user wishes to purchase as the user continues to navigate the site. Stateful-session beans can be used to keep track of this user information.

Entity

Entity beans can be thought of as beans that are used to persist data to a database. They basically represent a single row within a given database. It is important to put emphasis on the word single since entity beans access one row of data at a time. A session bean can have more than one representation of data by simply having multiple instances of itself. Entity beans cannot do that; in fact, an entity bean’s life span is directly tied to its relationship with the data, whereas session beans care about clients and not data.

Message Driven

Message-driven beans are message consumers that clients use transparently when they send messages to specific destinations or endpoints that the message-driven beans are aware of. Message-driven beans are asynchronous and in the past only used JMS for communication. With the arrival of the EJB 2.1 specification, message-driven beans are no longer tied completely to JMS.

466

Communicating between Java Components with RMI and EJB

Message-driven beans are generally invoked and managed by containers. They are completely transparent to the clients that use them to reach a specific destination. When a client makes a request to send a message to a particular destination, the container can then execute the message-driven bean to handle the communication needs.

Examining EJB Containers

As the name suggests, EJB containers are complete systems that house EJBs and allow clients to access the EJBs through the Java Naming and Directory Interface (JNDI) by exposing the EJBs home interface. Here is an example of how clients can look up EJBs locally using JNDI calls:

Context initialContext = new InitialContext();

TestHome testHome = (TestHome) initialContext.lookup(“java:comp/env/ejb/test”);

The home interfaces of the EJBs can actually reside on multiple machines on multiple networks. The location of the EJBs would be totally transparent to the user. It is the container’s job to find the EJB’s home interfaces and provide them to the clients. Figure 10-5 shows the client asking for the EJBRocket home interface, and container 1 gets the interface from container 2 and returns it to the client without the client having any knowledge of where the EJB was located.

Client looks for

EJBRocket

Laptop

Server

Server

Container 1

Container 2

EJBMissle

EJBRocket

Figure 10-5

Some of the more popular application servers that are EJB containers provide a great amount of functionality — including caching, security, connection pools, thread pools, and transaction support — that the EJBs can leverage. This allows EJB developers to separate the business logic of the application from the system logic and also prevents the developer from having to reinvent the wheel every time the developer needs to create an EJB that requires transaction or database support. This adds to interoperability and is exactly what the architects of J2EE had in mind.

467

Chapter 10

All of the system logic can now be controlled by an administrator of the EJB container, and therefore it gives corporations and government agencies more control over security, scalability, and performance.

If you are looking for a good application server/EJB container to develop EJBs in, try the open-source solution, JBoss.

EJB Loan Calculator Example

The EJB Loan Calculator example will demonstrate how to use a stateless-session bean for the purpose of calculating the monthly payment of a loan given the loan amount, loan term (in months), and interest rate. The beauty of the EJB is that it can be used by any client that requires its loan calculating services. This really shows the benefit of creating EJBs versus individual applications to do all the work. Now, multiple clients can simply call this EJB to perform loan calculations by looking up the loan calculator bean with JNDI.

LoanObject Interface

The first thing you need to do in the example is design the remote interface that clients will be interfacing with. This remote interface must extend the javax.ejb.EJBObject class in order to become a valid remote interface. Any methods associated with this interface must throw a RemoteException in the event of an error. The LoanObject interface is your remote interface that will be used by clients to gain access to its only method that is used for calculating a loan payment. The method calculateLoanPayment takes three doubles and returns the result in double form:

package sample.loanejb;

import java.rmi.RemoteException;

/**

*The LoanObject class is the remote interface of the EJB

*and it contains a method which can be invoked remotely by

*clients.

*/

public interface LoanObject extends javax.ejb.EJBObject {

// The

method

to calculate monthly payments on a given

loan.

public

double

calculateLoanPayment(double dLoanAmount,

double dLoanTerm,

 

 

double dLoanRate)

throws RemoteException;

}

LoanHome Interface

The LoanHome interface is the EJB home interface that is used to create the LoanObjects and distribute them to clients as needed. The LoanHome interface contains only one method called create to accomplish its task. You may have noticed that the create method not only throws a RemoteException but also a CreateException, which is a requirement for the create method:

package sample.loanejb;

import java.rmi.RemoteException;

import javax.ejb.CreateException;

/**

468

Communicating between Java Components with RMI and EJB

*LoanHome is the home interface of the EJB. We have one method create * which is used to create a LoanObject.

*

*/

public interface LoanHome extends javax.ejb.EJBHome {

// Creates a LoanObject

public LoanObject create() throws CreateException, RemoteException;

}

LoanBean Class

The LoanBean class is the implementation of the LoanObject interface. It contains the remote methods that clients will use when connecting to the EJB. The calculateLoanPayment method is implemented fully along with the ejbCreate method below:

package sample.loanejb;

import javax.ejb.*; import javax.naming.*;

/**

*The LoanBean class is the implementation of the

*remote interface. It contains the implementations of the

*LoanObject class.

*/

public class LoanBean implements SessionBean

{

// Used to store the name of the EJB String m_ObjectName;

/**

* This method is used to obtain the monthly payment of a given loan */

public double calculateLoanPayment(double dLoanAmount, double dLoanTerm,

 

 

double dLoanRate) {

double dLoanPayment

= 0.0d;

double dRate

 

= 0.0d;

dRate = dLoanRate /

1200;

// Algorithm =

dLoanAmount * dRate /

//

(1 - (Math.pow(1/(1 + dRate), dLoanTerm)))

dLoanPayment = dLoanAmount * dRate /

(1.0d - (Math.pow(1.0d/(1.0d + dRate), dLoanTerm)));

return dLoanPayment;

}

469

Chapter 10

The ejbCreate method is used to give the developer a chance to execute commands when the EJB is created. In this case, the name of the EJB is being retrieved in the form of a string and then it is saved for later use:

public void ejbCreate() throws CreateException

{

try {

// Get and save our name m_ObjectName = (String) new

InitialContext().lookup(“java:comp/env/loanEJB”);

} catch (NamingException ne) {

throw new CreateException(“Could not obtain the name for this EJB”);

}

}

The methods below are required but not used for stateless-session beans. This example does not need to use them, but they must be implemented because they are required methods of the SessionBean interface that must be implemented for the LoanBean class:

public void setSessionContext(SessionContext ctx)

{

// Not required

}

public void ejbActivate()

{

// used only for stateful session beans

}

public void ejbPassivate()

{

// used only for stateful session beans

}

public void ejbRemove()

{

//Any clean up code you need to do should go here for the

//EJB.

}

}

LoanClient Class

The LoanClient class is the class that communicates with the EJB and performs the necessary operations to calculate the loan payments due each month. The class expects three command-line arguments to be passed to it:

The loan amount. This amount will be converted to a double internally so decimal points in the amount are excepted. An example of a loan amount, if you were financing a car, would be 20000.00.

470

Communicating between Java Components with RMI and EJB

The loan term. The program expects the loan term to be in months. An example of loan term would be 60 months (which is the equivalent of five years).

The loan rate. This is the percentage rate you expect for the loan. In order to enter a percentage rate of 7 12 percent, simply send in the number 7.5.

Take a look at the code. The significant aspects of the class will be explained as the code is presented:

package sample.loanejb;

import java.rmi.RemoteException; import javax.ejb.CreateException;

import javax.naming.*;

import sample.loanejb.LoanHome; import sample.loanejb.LoanObject;

In order to use the LoanHome and LoanObject classes, they must be imported since they are a significant part of the design of this class:

/**

* This is the LoanClient that will communicate with the EJB. */

public class LoanClient {

private LoanHome m_LoanHome;

public LoanClient() throws Exception {

try {

Context ctx = new InitialContext();

m_LoanHome = (LoanHome) javax.rmi.PortableRemoteObject.narrow( ctx.lookup(“LoanEJB”), LoanHome.class);

ctx.close();

}catch (NamingException e) { System.out.println(“Could not lookup LoanEJB home”); throw e;

}

}

The default constructor performs a crucial operation of looking up the remote object LoanEJB that is required in order to use its remote methods. Once the object is found, it is then stored in a LoanHome variable for later use:

public LoanHome getHome() { return m_LoanHome;

}

public static void main(String[] args) throws Exception {

if (args.length != 3) {

471

Chapter 10

System.out.println(“Usage: java -jar client.jar “ + “loanAmount (5000.00, loanTerm (in months, 60), “ + “loanRate (7.5)”);

System.exit(0);

}

The main method expects three arguments to be sent to it as was discussed earlier in this section. If they do not exist, the program will print out a usage statement to the user and exit without further execution:

// Obtain a client object

LoanClient lcClient = new LoanClient();

// Collect arg info into appropriate variables double dLoanAmount = Double.parseDouble(args[0]);

double

dLoanTerm

=

Double.parseDouble(args[1]);

double

dLoanRate

=

Double.parseDouble(args[2]);

// Create LoanEJB LoanObject loanObj;

try {

// Create the EJB object

loanObj = lcClient.getHome().create();

} catch (CreateException ex) { System.out.println(“Error creating EJB!”); throw ex;

}

There are many neat things happening in this segment of the client class. First a LoanClient object is created, which is an object of this class. This triggers the default constructor, which looks up the LoanEJB and stores it in the m_LoanHome variable of the class. Once the home object is obtained, an EJB object is created by calling lcClient.getHome().create() and then it is stored in the loanObj variable which is of type LoanObject. Now you are ready to continue and make remote calls as needed:

double dResult;

try {

dResult = loanObj.calculateLoanPayment(dLoanAmount,dLoanTerm,dLoanRate);

} catch (RemoteException ex)

{

System.out.println(“Error calling loanObj.calculateLoanPayment()”); throw ex;

}finally {

//perform clean up loanObj.remove();

}

472

Communicating between Java Components with RMI and EJB

Using the loanObj, a call to calculateLoanPayment is made to get the monthly payment for the loan specified. Since the object is no longer needed, loanObj.remove is called to perform any cleanup routines that may be needed prior to the EJB being garbage collected:

// Print out result

System.out.println(“The amount it will cost you each month for a” +

period of “ + dLoanTerm +

month(s)\non a $”+ dLoanAmount +” loan with an interest rate of “ + dLoanRate + “ percent is: $” + dResult);

}

}

Finally, the result of the loan is printed out. Here is the printout of a sample result for a loan that has a loan amount of $20,352.07 with a term of 60 months at an interest rate of 7.5 percent.

The amount it will cost you each month for a period of 60.0 month(s) on a $20352.07 loan with an interest rate of 7.5 percent is: $407.81373247452996.

Examining the EJB-JAR.XML File

The ejb-jar.xml file is the basic EJB deployment descriptor that is used by containers to locate classes and interfaces, impose security restrictions, and set up transaction support. Depending on the application server you are using for your EJBs, you may be required to fill out another XML file that is specific to your application server. The ejb-jar.xml file generally coexists with the application server’s deployment descriptor file. For example, JBoss uses both ejb-jar.xml and jboss.xml. The file jboss.xml is obviously jboss-specific and is not compatible with other application servers:

<?xml version=”1.0” encoding=”UTF-8”?>

<ejb-jar> <description>

LoanEJB example takes a loan amount, term in months and interest rate then computes and returns the monthly payment for the loan

</description>

<display-name>LoanEJB example</display-name>

These are the basic description and name tags for the EJB that may show up in the container’s administrator page or elsewhere. They are not critical configurations, but are worth noting:

<enterprise-beans> <session>

<display-name>Loan EJB</display-name> <ejb-name>LoanEJB</ejb-name>

<home>sample.loanejb.LoanHome</home>

<remote>sample.loanejb.LoanObject</remote> <ejb-class>sample.loanejb.LoanBean</ejb-class>

<session-type>Stateless</session-type> <transaction-type>Container</transaction-type>

473

Chapter 10

Explore the elements shown above a little closer. The <ejb-name> element specifies the name for the EJB. The <home> element must point to the EJB home interface. The <remote> element must point to the remote interface. For this example, that is the LoanObject interface. The <ejb-class> element must point to the fully qualified name of the enterprise bean’s class. The <session-type> has only two possible values, Stateful or Stateless. Stateless is what was required for this example. Finally, the <transaction-type> element must specify the type of management that will occur, either Bean or Container:

<env-entry> <env-entry-name>loanEJB</env-entry-name> <env-entry-type>java.lang.String</env-entry-type> <env-entry-value>LoanEJB</env-entry-value>

</env-entry> </session>

</enterprise-beans>

The <env-entry> section contains environment entries that are optionally set for the EJB’s environment. These entries can be looked up by JNDI as shown in this example. The <env-entry-name> element contains the name of the EJB’s environment entry. The <env-entry-type> describes the Java type of the value of the environment entry. The <env-entry-value> contains the value of the environment entry:

<assembly-descriptor>

<security-role> <role-name>guest</role-name>

</security-role>

<method-permission>

<description>This is the guest account to access the EJB</description> <role-name>guest</role-name>

<method> <ejb-name>LoanEJB</ejb-name>

<method-name>*</method-name> </method>

</method-permission>

<container-transaction>

<description>LoanEJB transaction</description>

<method> <ejb-name>LoanEJB</ejb-name> <method-name>*</method-name>

</method>

<trans-attribute>Supports</trans-attribute> </container-transaction>

</assembly-descriptor>

</ejb-jar>

474

Communicating between Java Components with RMI and EJB

The final code segment above is contained in the element <assembly-descriptor>. This element can contain information on security roles, method permissions, and transaction attributes. There are so many here to examine that the best way to describe them is in a table. Here are the descriptions of each child element of the <assembly-descriptor> element.

Element Description

<security-role>

<role-name>

<method-permission>

This element contains info about a security role such as a description and role name

This element contains a security role name that must conform to the NMTOKEN lexical rules.

This element sets permissions for individual methods of an EJB and it ensures that one or more security roles can be allowed to access the methods.

<method>

This element allows you to associate all methods or spe-

 

cific methods of an EJB with a specific security role of the

 

method-permission element.

<container-transaction>

This element has child elements that manage how trans-

 

actions apply to EJB methods.

<trans-attribute>

When dealing with EJB methods, this element tells the

 

container how it should manage transaction boundaries.

 

Valid values are as follows: NotSupported, Supports,

 

Required, RequiresNew, Mandatory, Never.

Summar y

This chapter explored RMI and EJB Java technologies that allow Java components to communicate with each other on different levels using different protocols. It also demonstrated how EJBs are the better approach of the two technologies for communication between Java components and for interoperability needs when dealing with enterprise applications. RMI is still very useful, and depending on your architecture needs, you should choose the technology that works best for you.

The next chapter will focus in on how to perform communication between Java components using other technologies, such as Web services, CORBA, and sockets.

475

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]