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

Mastering Enterprise JavaBeans™ and the Java 2 Platform, Enterprise Edition - Roman E

..pdf
Скачиваний:
41
Добавлен:
24.05.2014
Размер:
6.28 Mб
Скачать

A P P E N D I XD

Understanding EJB 1.1

n this appendix, you’ll learn about the major improvements Sun Microsystems Ihas introduced in the EJB 1.1 specification. We’ve held up production of this book to get you this late-breaking information, and it was definitely worth it. EJB 1.1 addresses many of the problems we’ve raised throughout this book, and it is a major step forward toward bean portability. By late 1999, the first EJB 1.1-based application servers should arrive on the market. This chapter will fill you in on the major details and paradigm shifts necessary to begin programming

with EJB 1.1.

Note that we’ll spend minimal time refreshing you on the basics, and so you should have a solid understanding of EJB 1.0 as well as XML (see Appendix C) before reading this appendix.

This appendix has been written to the third EJB 1.1 public draft. Sun Microsystems may have added minor changes since this appendix was written. Similarly, the code in this chapter is untested, since actual EJB 1.1 products were not available at the time of this writing. Be sure to check the book’s accompanying Web site at www.wiley.com/compbooks/roman for any updates to this technology (you should probably do this right now).

Portable Deployment Descriptors

In Appendix C, we saw that XML is an elegant, simple language you can use to add structure to a document. EJB 1.1 leverages XML to describe your enterprise beans. All EJB 1.1-compliant containers must accept deployment descriptors

635

Go back to the first page for a quick link to buy this book online!

636 M A S T E R I N G E N T E R P R I S E J A V A B E A N S

written in XML, and cannot accept serialized Java objects. Sun will provide a tool that aids converting an EJB 1.0 deployment descriptor to EJB 1.1, as well as validating an EJB 1.1 deployment descriptor.

One Deployment Descriptor Per Ejb-Jar File

With EJB 1.0, you need to write a separate deployment descriptor for each enterprise bean. This has changed in EJB 1.1. With EJB 1.1 you write one deployment descriptor for each ejb-jar file. Your single deployment descriptor contains information for all the beans in the ejb-jar file. This has an interesting side effect: since there is only one deployment descriptor, there is no need for a manifest file that points to all the deployment descriptors within an ejb-jar file. In EJB 1.1, you simply include an XML deployment descriptor, and it must be named META-INF/ejb-jar.xml; manifests no longer exist.

EJB 1.1 XML Deployment Descriptor Example

To get you going, let’s convert an EJB 1.0-style deployment descriptor into EJB 1.1. We’ll start off very simple, and grow our deployment descriptor as we learn more about EJB 1.1 throughout this chapter.

Table D.1 gives an EJB 1.0-style deployment descriptor for an Employee bean.

Source D.1 shows the new EJB 1.1 XML deployment descriptor, which we’ve commented for clarity.

The deployment descriptor is fairly self-explanatory. One interesting part is the <assembly-descriptor> element at the end. The assembly descriptor is where you can add security and transaction information, and we’ll see it in action a bit later. These values may very well change when your bean is actually deployed.

Table D.1 EJB 1.0 Serialized Deployment Descriptor Settings for our Product Entity Bean

DEPLOYMENT DESCRIPTOR SETTING

VALUE

Bean Home Name (for client JNDI lookups)

EmployeeHome

Enterprise Bean Class Name

EmployeeBean

Home Interface Class Name

EmployeeHome

Remote Interface Class Name

Employee

Re-entrant

false

Primary Key Class Name

EmployeePK

Container-managed fields

employeeID, name, email

 

 

Go back to the first page for a quick link to buy this book online!

Understanding EJB 1.1 637

<!--

This statement must be included with every EJB 1.1 deployment descriptor. It refers to the EJB 1.1 document type definition (DTD). Unfortunately, Sun has yet to provide a URL for the SYSTEM id.

-->

<!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems Inc.//DTD Enterprise JavaBeans 1.1//EN" SYSTEM "TBD">

<!--

This is the required root element of all EJB 1.1 deployment descriptors. -->

<ejb-jar>

<!--

This describes the purpose of this ejb-jar file, and the beans within it. If you're writing beans for others to use or maintain, the description element is a great place to put special instructions.

--> <description>

This ejb-jar file contains an assembled Employee entity bean. No special instructions.

</description>

<!--

Within this element, we can declare one or more enterprise beans. -->

<enterprise-beans>

<!--

Enterprise bean type: "session" for session bean, "entity" for entity bean.

--> <entity>

<!--

The description for this bean. -->

<description>

This bean represents internal employees. </description>

<!--

This is a unique identifier for this bean. -->

<ejb-name>Employee</ejb-name>

<!--

The home interface class.

Source D.1 A trivial EJB 1.1 XML deployment descriptor (continues).

Go back to the first page for a quick link to buy this book online!

638 M A S T E R I N G E N T E R P R I S E J A V A B E A N S

--> <home>EmployeeHome</home>

<!--

The remote interface class. --> <remote>Employee</remote>

<!--

The enterprise bean class. -->

<ejb-class>EmployeeBean</ejb-class>

<!--

The primary key class. -->

<prim-key-class>EmployeePK</prim-key-class>

<!--

Persistence type: "Container" for container-managed-persistence, "Bean" for bean-managed persistence.

--> <persistence-type>Bean</persistence-type>

<!--

Whether or not the bean is re-entrant. -->

<reentrant>False</reentrant>

<!--

The container-managed persistent fields. You also can put optional <description> elements for each cmp-field.

--> <cmp-field>

<field-name>employeeID</field-name> </cmp-field>

<cmp-field> <field-name>name</field-name>

</cmp-field>

<cmp-field> <field-name>email</field-name>

</cmp-field>

</entity>

</enterprise-beans>

Source D.1 A trivial EJB 1.1 XML deployment descriptor (continues).

Go back to the first page for a quick link to buy this book online!

Understanding EJB 1.1 639

<!--

Application assembly information, such as security roles, method permissions, and transaction attributes.

--> <assembly-descriptor> </assembly-descriptor>

</ejb-jar>

Source D.1 A trivial EJB 1.1 XML deployment descriptor (continued).

This brings us to an interesting point: one advantage of XML deployment descriptors is they evolve over time. When an enterprise bean is first created, the bean provider constructs an XML deployment descriptor and ships it with the bean. Then when an application assembler purchases the bean, he can modify the deployment descriptor for his particular needs. The application assembler can change the enterprise bean’s name, environment properties, description fields, security roles, method permissions, transaction attributes, and more simply by modifying the deployment descriptor.

Now that we’ve had a taste of EJB and XML, let’s take a look at some of the other features in EJB 1.1.

Entity Bean Support Mandated

In EJB 1.0, containers could optionally support entity bean components. It’s been over a year since EJB 1.0, and people are beginning to realize the need for persistent components. Thus, Sun Microsystems has mandated that EJB 1.1 containers must support entity beans. This is great news for you because your entity beans should be able to run in any EJB 1.1-compliant application server.

RMI-IIOP API Standardized

In EJB 1.0, each container had a different API for accessing networked objects. Some containers used plain vanilla Java RMI, some used a flavor of RMI-IIOP, and some had proprietary APIs. The EJB 1.1 specification, along with the Java 2 Platform, Enterprise Edition, enforces that containers must use Java RMI-IIOP. Sun will enforce this via a compatibility test suite that all containers must pass.

The key API difference between Java RMI and RMI-IIOP is that you need to use PortableRemoteObject.narrow() whenever you want to cast any remote object

Go back to the first page for a quick link to buy this book online!

640 M A S T E R I N G E N T E R P R I S E J A V A B E A N S

into a more specific type. For example, whenever you receive a home object or EJB object and need to cast it into a more specific type, you need to use PortableRemoteObject.narrow(). In EJB 1.0, containers did this in a totally nonportable way. For instance, consider the following snippet of code used with the EJB 1.0-compliant BEA WebLogic server, which uses plain vanilla Java RMI:

// 1: Get handle

javax.ejb.Handle handle = <retrieve from disk or elsewhere>

// 2: Get EJB object from handle

javax.ejb.EJBObject genericEJBObject = handle.getEJBObject();

// 3: Cast EJB object to our specific remote interface type Employee emp = (Employee) genericEJBObject;

This is invalid when using RMI-IIOP because RMI-IIOP does not support directly casting remote objects. With RMI-IIOP you need to use a helper function to cast the returned object for you. The following code illustrates portable EJB 1.1 casting.

// 1: Get handle

javax.ejb.Handle handle = <retrieve from disk or elsewhere>

// 2: Get EJB object from handle

javax.ejb.EJBObject genericEJBObject = handle.getEJBObject();

// 3: Cast EJB object to our specific remote interface type Employee emp = (Employee)

javax.rmi.PortableRemoteObject.narrow( genericEJBObject, Employee.class);

There are some other differences with using RMI-IIOP as well, such as lack of distributed garbage collection, but this is the only key API difference. See Chapter 11 for more details on RMI-IIOP.

Although you use Java RMI-IIOP as an API, your container does not need to use IIOP as transport protocol. Containers can use JRMP (Java RMI’s native protocol) or a proprietary protocol for network communications. In the future, Sun Microsystems will likely mandate that IIOP is used as the de facto protocol, allowing for true transaction and security on-the-wire interoperability.

Everything JNDI

We saw the value proposition of JNDI in Appendix B—JNDI is a universal lookup API for resources across a deployment, such as printers, computers, or networks.

Go back to the first page for a quick link to buy this book online!

Understanding EJB 1.1 641

EJB 1.0 used JNDI to look up home objects from client code. EJB 1.1 takes JNDI to the extreme, leveraging it to look up many types of resources:

■■Enterprise bean home objects from client code

■■Enterprise bean home objects from within a bean

■■Resource factories (such as JDBC drivers or JMS drivers)

■■Environment properties

■■The Java Transaction API (JTA) UserTransaction interface

This is wonderful news for you because you need to learn only a single API— JNDI—to look up any resource. When you look up EJB 1.1 resources using JNDI, you always follow these steps:

First, acquire a JNDI initial context. The initial context is a starting point for locating resources via JNDI. See Appendix B for more details.

Next, use the initial context to look up the desired resource. The resource could be a home object, a resource factory, the JTA, or environment properties.

If the resource is a remote object, you must cast it RMI-IIOP style. To cast a remote object into a more specific type, you need to use the RMI-IIOP

PortableRemoteObject.narrow() method.

We now give examples of how to look up each of these resources.

How to Look Up Home Objects from Client Code

Whenever a client wants to use enterprise beans, it needs to first acquire the bean’s home object. It then uses the home object to create EJB objects. The client can then call business methods on the EJB objects, which delegate calls to the enterprise bean instances.

The following code shows how to look up home objects using BEA’s WebLogic in EJB 1.0. Note that this API may be different for other EJB 1.0 containers.

//Get System properties for JNDI initialization Properties props = System.getProperties();

//Get the initial context

Context ctx = new InitialContext(props);

// look up the home object

EmployeeHome home = (EmployeeHome) ctx.lookup("EmployeeHome");

// start creating EJB objects...

Employee emp = home.create();

Go back to the first page for a quick link to buy this book online!

642 M A S T E R I N G E N T E R P R I S E J A V A B E A N S

By way of comparison, all EJB 1.1 containers must support JNDI in conjunction with RMI-IIOP style casts, as shown below.

//Get System properties for JNDI initialization Properties props = System.getProperties();

//Get the initial context

Context ctx = new InitialContext(props);

//look up the home object EmployeeHome home = (EmployeeHome)

javax.rmi.PortableRemoteObject.narrow( ctx.lookup("EmployeeHome"), EmployeeHome.class);

//start creating EJB objects...

Employee emp = home.create();

The key difference here is that every EJB 1.1 container must use RMI-IIOP style casting via PortableRemoteObject.narrow().

How to Look Up Home Objects from within a Bean

For your enterprise bean to use other enterprise beans, you need to locate the other enterprise beans’ home objects via JNDI. In EJB 1.0, this was handled quite poorly. Remember that to use JNDI, you first need to supply initialization parameters such as the JNDI service provider you’re using, which differs from container to container. But if you’re a bean provider, how do you know what JNDI service provider to use? After all, you’re writing reusable components that should run in any container, and each container has its own JNDI service provider. The EJB 1.0 hack solution to this is to externalize all JNDI initialization settings to the environment properties that your bean reads in at runtime (see Chapter 6).

For example, let’s say our Employee bean uses an Address bean for storing the employee’s address. The following code illustrates the EJB 1.0 way of looking up an Address home from within an Employee bean:

//Retrieve the JNDI initialization paramters from

//the bean's environment

Properties props = sessionContext.getEnvironment();

//Obtain a JNDI initial context with the properties Context ctx = new InitialContext(props);

//Look up the home interface

AddressHome home = (AddressHome) ctx.lookup("AddressHome");

EJB 1.1 makes things right. In EJB 1.1, you don’t need to supply any JNDI initialization parameters. Rather, you simply acquire a default JNDI initial context.

Go back to the first page for a quick link to buy this book online!

Understanding EJB 1.1 643

The container sets the default JNDI initial context before your bean ever runs. Thus, you can write a bean that runs in any container’s JNDI implementation because you don’t need to provide JNDI initialization parameters, as shown in the following code example.

//Obtain the DEFAULT JNDI initial context by calling the

//no-argument constructor

Context initCtx = new InitialContext();

//Look up the home interface Object result = initCtx.lookup( "java:comp/env/ejb/AddressHome");

//Convert the result to the proper type, RMI-IIOP style AddressHome home = (AddressHome)

javax.rmi.PortableRemoteObject.narrow( result, AddressHome.class);

The EJB 1.1 code above is much more portable than the EJB 1.0 code because nobody ever needs to supply container-specific JNDI initialization parameters. Notice also that we look up home objects in java:comp/env/ejb. This is the suggested (but not required) location for home objects in EJB 1.1.

Understanding EJB References

One problem with EJB 1.0 is no structured way to refer to home objects. When a bean provider writes some EJB 1.0 client code that calls a home object, what JNDI location should he use? What if that JNDI location changes upon deployment, perhaps because the deployment is spread out across multiple domain boundaries? Unfortunately, the bean provider’s code will break if the JNDI location changes. And if bean provider’s code ships as .class files only, there is no way to modify the original source code.

EJB 1.1 resolves this situation with EJB references. An EJB reference is a deployment descriptor entry that says enterprise bean A uses enterprise bean B. When enterprise bean A is finally deployed, the deployer sees the EJB reference to enterprise bean B, and makes sure that enterprise bean B is available at the correct JNDI location. If enterprise bean B is located in a different enterprise domain, the deployer can add symbolic links within the JNDI tree using JNDI LinkRef, described in Appendix B.

Source D.2 illustrates a sample deployment descriptor using EJB references.

Programming with EJB references are straightforward. Our Employee bean is using an Address bean, so inside the Employee bean we simply list all the necessary information about the Address bean in an EJB reference. The deployer then knows that our Employee bean uses exactly one other enterprise bean—

Go back to the first page for a quick link to buy this book online!

644 M A S T E R I N G E N T E R P R I S E J A V A B E A N S

...

<enterprise-beans>

<entity>

<ejb-name>EmployeeEJB</ejb-name> <ejb-class>EmployeeBean</ejb-class>

...

<!--

This is an EJB reference. It says that Employee uses Address. -->

<ejb-ref> <description>

This is a reference from an Employee bean to an Address bean. The Address bean holds the employee's address.

</description>

<!--

The JNDI location that Employee uses to look up Address. We declare it so the deployer knows to bind the Address home in java:comp/env/ejb/Address.

--> <ejb-ref-name>ejb/Address</ejb-ref-name>

<!--

Address is an Entity bean. -->

<ejb-ref-type>Entity</ejb-ref-type>

<!--

The Address home interface class. -->

<home>AddressHome</home>

<!--

The Address remote interface class. -->

<remote>Address</remote>

<!--

(Optional) the Address ejb-name. --> <ejb-link>AddressEJB</ejb-link>

</ejb-ref>

</entity>

Source D.2 Declaring an EJB Reference within an EJB 1.1 Deployment Descriptor (continues).

Go back to the first page for a quick link to buy this book online!