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

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

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

Writing Container-Managed Persistent Entity Beans 249

System.out.println("unsetEntityContext called"); this.ctx = null;

}

/**

*Called after ejbCreate(). Now, the Bean can retrieve

*its EJBObject from its context and pass it as a 'this'

*argument.

*/

public void ejbPostCreate(String productID, String name, String description, double basePrice) throws RemoteException { System.out.println("ejbPostCreate() called");

}

/**

*This is the initialization method that corresponds to the

*create() method in the Home Interface.

*

*When the client calls the Home Object's create() method,

*the Home Object then calls this ejbCreate() method.

*

*NOTE: Since we're using Container-Managed persistence,

*this method returns void. With Bean-Managed Persistence,

*we returned the PK. This is because our Bean was

*responsible for dealing with PKs and accessing

*the database. Now that we let the Container handle

*persistence, the Container makes the Primary Key.

*

*We still need to initialize our Bean's fields with the

*parameters passed from the client, so that the Container

*can inspect our Bean and create the corresponding database

*entries.

*/

public void ejbCreate(String productID, String name, String description, double basePrice) throws CreateException, RemoteException { System.out.println("ejbCreate(" + productID + ", " + name + ", " + description + ", " + basePrice + ") called");

this.productID = productID; this.name = name; this.description = description; this.basePrice = basePrice;

}

// No finder methods - they are implemented by Container

}

Source 9.4 ProductBean.java (continued).

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

250 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

Client.java

Our client code is a simple suite of test cases to try out our bean, as shown in Source 9.5.

We perform a JNDI lookup to acquire the home object and create some entity bean data. We then try out a couple of finder methods. We can loop through the finders’ returned numerations and call business methods on each EJB object. We then destroy all the EJB objects we created in a finally{} clause.

package com.wiley.compBooks.roman.entity.product;

import javax.ejb.*; import javax.naming.*; import java.rmi.*;

import java.util.Enumeration;

/**

* Client test application on a Container-Managed Entity Bean, Product. */

public class Client {

public static void main(String[] args) {

ProductHome home = null;

try { /*

*Get a reference to the Product Home Object - the

*factory for Product EJB Objects

*/

Context ctx = new InitialContext(System.getProperties()); home = (ProductHome) ctx.lookup("ProductHome");

/*

* Use the factory to create the Product EJB Object */

home.create("123-456-7890", "P5-350", "350 Mhz Pentium", 200); home.create("123-456-7891", "P5-400", "400 Mhz Pentium", 300); home.create("123-456-7892", "P5-450", "450 Mhz Pentium", 400); home.create("123-456-7893", "SD-64", "64 MB SDRAM", 50); home.create("123-456-7894", "SD-128", "128 MB SDRAM", 100); home.create("123-456-7895", "SD-256", "256 MB SDRAM", 200);

/*

* Find a Product, and print out its description */

Source 9.5 Client.java (continues).

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

Writing Container-Managed Persistent Entity Beans 251

Enumeration enum = home.findByName("SD-64"); System.out.println("The following product descriptions match the

product name SD-64:");

while (enum.hasMoreElements()) {

Product prod = (Product) enum.nextElement();

System.out.println(prod.getDescription());

}

/*

* Find all products that cost $200 */

System.out.println("Calling finder to find all products that cost $200");

enum = home.findByBasePrice(200);

while (enum.hasMoreElements()) {

Product prod = (Product) enum.nextElement();

System.out.println(prod.getDescription());

}

}

catch (Exception e) { e.printStackTrace();

}

finally {

if (home != null) { try {

System.out.println("Destroying products..");

/*

* Find all the products */

Enumeration enum = home.findAllProducts(); while (enum.hasMoreElements()) {

try {

Product prod = (Product) enum.nextElement(); prod.remove();

}

catch (Exception e) { e.printStackTrace();

}

}

}

catch (Exception e) { e.printStackTrace();

}

}

}

}

}

Source 9.5 Client.java (continued).

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

252 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

The Deployment Descriptor

We now need to write our deployment descriptor. In addition to defining the standard entity bean fields, we now need to inform the container about our public container-managed fields. The deployment descriptor is shown in Table 9.2. Notice that we no longer have any JDBC application-specific properties because we’ve externalized all database activity to the container.

In addition to the deployment descriptor, we need to tell the container exactly how to perform persistent operations. This is one trade-off of containermanaged persistence—you still need to declare persistent rules, rather than code them into your bean using JDBC or SQL/J.

If you’re using a relational data store, you’ll need to define exactly how your entity bean’s public fields map to that database. Thus, we must define a series of object-relational mapping entries. These entries map entity bean fields to relational database column names. The EJB container (in this case, BEA WebLogic) will use this mapping when storing or retrieving our container-managed fields from the database. Note that this is very EJB container-specific! Some EJB containers will support object databases and thus will not have a mapping into a two-dimensional relational database. Consult your EJB container’s documentation for more information. Our product line’s persistent entries for BEA’s WebLogic server are shown in Table 9.3.

We also need to specify the implementation of our home object’s finder methods. This is also, unfortunately, proprietary for each EJB container. BEA WebLogic has a simple scripting language for this purpose. For example:

Table 9.2 Deployment Descriptor Settings for ProductBean

DEPLOYMENT

DESCRIPTOR SETTING

VALUE

Bean home name

ProductHome

Enterprise bean class name

com.wiley.compBooks.roman.entity.product.ProductBean

Home interface class name

com.wiley.compBooks.roman.entity.product.ProductHome

Remote interface class name

com.wiley.compBooks.roman.entity.product.Product

Environment properties

<empty>

Re-entrant

false

Primary key class name

com.wiley.compBooks.roman.entity.product.ProductPK

Container-managed fields

productID, name, description, and basePrice

 

 

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

Writing Container-Managed Persistent Entity Beans 253

Table 9.3 Persistent Settings for ProductBean Assuming the BEA Weblogic Container

OBJECT/RELATIONAL SETTING

(ENTITY BEAN FIELD = RELATIONAL COLUMN NAME)

productID=id

name=name

description=description

basePrice=basePrice

■■“findByName(String name)” “(= name $name)” means to find all entity bean products whose container-managed field name matches the parameter “name” passed in by the client.

■■“findCheapProducts(double maxPrice)” “(< basePrice $maxPrice)” means to find all products whose container-managed field basePrice is less than the maxPrice variable that the client specified.

■■“findAllProducts()” “(= 1 1)” simply finds every product there is.

The complete script is shown in Table 9.4. The container will implement this logic, perhaps using JDBC or SQL/J. Whenever a client wants to execute a finder method on the home object, the container will automatically run the implemented JDBC or SQL/J code.

Running the Client Program

To run the client program, type a command similar to the following (depending on your EJB container Java Naming and Directory Interface, or JNDI, initialization parameters) shown on the next page:

Table 9.4 Finder Semantics for ProductBean Assuming the BEA Weblogic Container

FINDER SCRIPTING SYNTAX

“findByName(String name)” “(= name $name)”

“findByDescription(String description)” “(= description $description)”

“findByBasePrice(double basePrice)” “(= basePrice $basePrice)”

“findExpensiveProducts(double minPrice)” “(> basePrice $minPrice)”

“findCheapProducts(double maxPrice)” “(< basePrice $maxPrice)”

“findAllProducts()” “(= 1 1)”

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

254 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

java

-Djava.naming.factory.initial=weblogic.jndi.TengahInitialContextFactory

-Djava.naming.provider.url=t3://localhost:7001

com.wiley.compBooks.entity.Product.Client

The initialization parameters are required by JNDI to find the home object, as we learned in Chapter 4.

Server-Side Output

When you run the client, you should see something similar to the following on the server side. Note that your particular output may vary, due to variances in EJB container behavior.

New Product Entity Bean Java Object created by EJB Container. setEntityContext called

ejbCreate(123-456-7890, P5-350, 350 Mhz Pentium, 200.0) called ejbPostCreate() called

New Product Entity Bean Java Object created by EJB Container. setEntityContext called

ejbCreate(123-456-7891, P5-400, 400 Mhz Pentium, 300.0) called ejbPostCreate() called

New Product Entity Bean Java Object created by EJB Container. setEntityContext called

ejbCreate(123-456-7892, P5-450, 450 Mhz Pentium, 400.0) called ejbPostCreate() called

New Product Entity Bean Java Object created by EJB Container. setEntityContext called

ejbCreate(123-456-7893, SD-64, 64 MB SDRAM, 50.0) called ejbPostCreate() called

New Product Entity Bean Java Object created by EJB Container. setEntityContext called

ejbCreate(123-456-7894, SD-128, 128 MB SDRAM, 100.0) called ejbPostCreate() called

New Product Entity Bean Java Object created by EJB Container. setEntityContext called

ejbCreate(123-456-7895, SD-256, 256 MB SDRAM, 200.0) called ejbPostCreate() called

New Product Entity Bean Java Object created by EJB Container. setEntityContext called

New Product Entity Bean Java Object created by EJB Container. getDescription() called.

ejbStore() called.

New Product Entity Bean Java Object created by EJB Container. getDescription() called.

ejbStore() called. getDescription() called. ejbStore() called.

New Product Entity Bean Java Object created by EJB Container.

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

Writing Container-Managed Persistent Entity Beans 255

ejbRemove() called.

ejbRemove() called.

ejbRemove() called.

ejbRemove() called.

ejbRemove() called.

ejbRemove() called.

We created a number of new products in our client code. For each new product, our EJB container created a dedicated bean instance. It didn’t have to do this—it could have passivated/activated the same bean and switched context between clients. When creating a bean, our container first called newInstance(), followed by setEntityContext(), which got the bean into the pool. It then called ejbCreate(), set up the database data, bound the bean to an EJB object, and finally called ejbPostCreate()—all as expected. It then serviced a few business calls, instantiated a few new beans, and occasionally synchronized the beans with the underlying database.

Client-Side Output

For the client side, after creating some products, we performed a find for all products that cost $200. Indeed, multiple entity beans were returned in our enumeration, as is shown below:

The following product descriptions match the product name SD-64: Product SD-64 has description 64 MB SDRAM

Calling finder to find all products that cost $200 350 Mhz Pentium

256 MB SDRAM Destroying products..

Promises and Realities: Bean-Managed Persistence versus Container-Managed Persistence

Now that you’ve seen both bean-managed and container-managed persistent entity beans, you must be convinced that container-managed beans are the way to go. All that JDBC code was eliminated from our bean class, saving us significant development time.

However, the choice between containerand bean-managed persistence is not necessarily clear-cut. Both bean-managed and container-managed beans have virtues. Container-managed persistence may promise a lot, but its current manifestation fails to deliver on numerous counts, about which you must be informed. Let us look at three promises, and the realities of those promises, for containermanaged persistence.

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

256 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

Promise: Container-Managed Persistence Reduces Code

If you tell the EJB container a couple of things about your bean, containermanaged persistence can perform all data access logic for you. This reduces the size of your bean tremendously—no more JDBC code in your beans—which reduces overall development time.

Reality

Depending on your container, you still may need to write persistent code with container-managed beans. This could be going through a series of wizards to specify how your entity beans map to an underlying store. You also need to specify the logic behind your finder methods. The difference is that your data access logic is now specified declaratively, rather than being written in Java. This does significantly reduce your code size, however, and has the nice feature that you can migrate to new database schemas very quickly without changing any source code.

Another code benefit rarely mentioned is that your container can be very smart about how it caches entity bean state in memory. Advanced EJB containers ship with a shared object cache, which stores entity bean data in memory across transactions. Using a shared object cache, the container can avoid unnecessary ejbLoad/ejbStore calls, which increases transactional throughput exponentially. Note that you can cache entity bean state in memory using bean-managed persistence as well, but the burden of doing this falls on you.

Promise: Container-Managed Persistence Reduces Bugs

One benefit of container-managed persistence is that it eliminates many of the bugs that occur in a deployment—mostly due to buggy JDBC code. The problem with JDBC code is that it’s not “type-safe.” You can’t detect whether it will work at compile time—your JDBC statements are simple strings that can be resolved only at runtime. By way of comparison, with container-managed persistence the EJB container has been written by a database professional whose sole job is to make sure the generated database calls are, in general, accurate. Plus, if you as a user have specified an error (perhaps you misnamed a containermanaged field in the deployment descriptor), you can detect errors at compile time. The way you detect these errors is by running your EJB container tools, which, if they’re any good, should use Java Reflection or the equivalent to figure out whether your deployment descriptor does indeed map to your containermanaged fields. It can also check things such as whether your primary key fields are a subset of your container-managed fields.

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

Writing Container-Managed Persistent Entity Beans 257

Reality

While it may be true that user error is reduced at the database level, there are serious ramifications if there is some kind of bug. Because the container is performing your persistence for you, it becomes very tough to figure out what database operations the container is really doing. You may need to trace through container-generated code if it’s available, decompile the container, or possibly wait on technical support lines, delaying a project.

In addition, some containers may not support mapping of complex field types to an underlying storage. For example, if your container-managed persistent entity bean class has a vector as a container-managed field, you may need to convert that vector into another form that the container can handle when mapping to storage. Most containers also do not support relationships between entity beans, a topic we’ll revisit in Chapter 13.

In general, the vision of container-managed persistence reducing bugs is sound. Actual reduction in errors will improve as EJB container technology matures over the years. Until the EJB market matures, not all vendors will prioritize implementing complex mapping of data types to underlying storages, or correct relationship handling. Be sure to evaluate your container here to ensure it fits your application requirements.

Promise: Container-Managed Persistence Makes It Easy to Port to Different Databases

One nice thing about container-managed persistence is that you aren’t hardcoding a particular database storage API into your beans, such as JDBC. Because you aren’t issuing explicit relational database calls in your persistence layer, you can easily move into a different database, such as a different relational database, or even an object database or legacy storage.

Database independence is very important. EJB defines a market for beans to be purchased off-the-shelf, and those beans must be able to work with whatever target database the customer has. Given that enterprise beans represent intellectual property, they will most likely not ship with their source code. This means that if an entity bean uses bean-managed persistence, the customer cannot easily tweak the data access logic. For these vendors, container-managed persistence is the only alternative to shipping multiple versions of the same bean code.

Reality

Although it is true that container-managed persistence improves portability, portability is not perfect yet. For instance:

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

258 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

■■There is no standard way to specify persistence semantics. Some containers will use property files, and some will use graphical wizards or some other proprietary scheme. As you saw earlier in this chapter, BEA’s WebLogic has its own way of specifying how object-relational mapping and finder methods should be done. But what if you want to install your bean in a different container? You’ll now need to respecify your persistent operations using the new container’s tools. If you have a very complex object model at hand, this could become a hefty task. Hopefully, specifying persistence semantics will be standardized in an upcoming release of EJB, but it’s not likely to happen until well into the year 2000.

■■The problem gets even more out of hand if your entity beans do not map one-to-one to relational tables. Many EJB containers will not support the full functionality needed for a complicated O/R mapping, complicated finder methods involving interesting SQL JOIN operations, and so on. Be sure your target container handles your persistence needs.

In summary, know that container-managed persistence is an EJB feature that helps developers rapidly develop persistence code. Even today, almost every company I’ve dealt with uses container-managed persistence exclusively since it results in such great rapid application development. But also know that con- tainer-managed persistence is an evolving technology vision, and will improve over the years.

Resolving Your EJB Debugging Problems

As you’re finding out, EJB is still in its infancy. EJB containers are not all that sophisticated at the moment, and they may have small weirdnesses to them. In addition, bugs may be introduced by users that are very difficult to debug. How do you debug with EJB?

Unfortunately, true debugging is a problem with EJB. Because your beans run under the hood of a container, you’d have to load the container itself into a debugger (WebLogic and Inprise, for example, support this). But for some containers, this is an impossible alternative because many containers are not even written in Java! They may be written in native code and use the Java Native Interface (JNI) to communicate with beans. For these situations, you may need to use the tried-and-true debugging method of logging.

An even more serious debugging problem occurs if exceptions are being thrown from the EJB container, rather than from your beans. This can happen for a number of reasons:

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