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

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

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

Understanding Java Remote Method Invocation (RMI) 553

were java.lang.String objects, which implement java.lang.Serializable and thus are passed by value. The Logger kept reading the messages off the queue and printing out the results. That is why the two senders’ messages are interleaved.

After 10 seconds, the main program closed the channel. That’s why there are three exceptions at the end—each client could no longer use the channel because it was destroyed. This is the desired functionality; it illustrates how RMI can throw exceptions over the network.

RMI Example: Exploiting Distributed Garbage Collection

Let’s continue our advanced RMI discussion with a final illustrative example.

One problem with our MessageQueue example is that the channel queues are stored in a permanent hashtable. The queues stored in the hashtable could become a memory leak if the end users never destroy the channels. We need a way to automatically clean things up.

To avoid memory leaks, we’re going to augment our Message Queue with some cleanup routines. Rather than hard-coding our own way of detecting clients who disconnect, we’re going to leverage RMI’s built-in Distributed Garbage Collection (DGC) in a very interesting way.

Distributed Garbage Collection

RMI can automatically clean up objects over the network using DGC. This is done through leases. What is an RMI lease? A lease is a temporary holding on an object. If you rent an apartment, you have to renew your lease every year or your landlord will kick you out. The same thing is true with RMI. Whenever a client acquires a remote reference to a remote object, that client automatically starts sending pings back to the server the remote object is on. RMI does this automatically whenever a client acquires a RemoteStub to a remote object. If no pings come for awhile, that RemoteStub’s lease has expired. On the server, there’s a low-priority thread that runs routinely and cleans up any objects whose leases have expired.

In most scenarios involving remote objects, eventually there will be a point when there are no more remote references to a particular remote object—because either clients have dropped their remote references or the lease has expired. There is a way to detect this with RMI—by implementing the java.rmi.Unreferenced interface. This interface defines one method: public void unreferenced(). This method is called whenever the remote object has no more RemoteStub references to it. That is, unreferenced() will get called as soon as all clients’ RemoteStub objects are garbage collected or as soon as leases expire on all clients that may have held RemoteStub objects but crashed. This is exactly what we want.

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

554 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

If you’re using Java RMI-IIOP (a standard Java extension we cover in Chapter 11), you cannot rely on distributed garbage collection. RMI-IIOP does not support it to remain compatible with languages that support only synchronous destruction.

Reimplementing the Channel Class

We’re going to modify our Message Queue so that a queue is automatically destroyed if no more clients hold references to the Channel object for that queue. The basic steps are as follows:

1.Modify the Channel object so that it is now a fully fledged remote object, not just a simple serializable object. Channel objects will no longer be passed by value; they’ll be passed by reference. This means clients will acquire RemoteStub objects rather than copies of Channel objects. When a client receives a stub, the distributed garbage collector will start tracking that client, and it will monitor for when the client drops its Channel reference or disconnects.

2.Make the Channel object implement the java.rmi.Unreferenced interface. When no more remote references to the Channel exist, DGC will automatically call the unreferenced() method.

3.Implement unreferenced() to clear the message queue from the main hashtable. That way, when all clients disconnect from a channel, we’ll destroy that channel’s queue, eliminating memory leaks.

The bulk of the modified code is shown in Source A.9.

Notice that we are also implementing a new IChannel interface, which is the RMI Remote Interface for Channels. This is needed because Channel objects are no longer serializable.

A few other classes have changed as well, but in minor ways. To keep this appendix as brief as possible, the details have been omitted from the text. See the CD-ROM or Web site for the full code.

Compiling and Running the Program

We compile the program in a similar way, except that we now need to generate stubs/skeletons for the Channel class as well. We do this in the same manner as we generated stubs/skeletons for our message queue in the previous example.

The DGC uses 10 minutes as the default timeout for leases. To shorten this, you can set the java.rmi.dgc.leaseValue to the desired number of milliseconds (e.g., by calling java—Djava.rmi.dgc.leaseValue=2000 for 2 seconds). If you want to see the Distributed Garbage Collector in action, set java.rmi.logCalls=true.

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

Understanding Java Remote Method Invocation (RMI) 555

package com.wiley.compBooks.roman.rmi.mqdgc;

import java.util.Random; import java.rmi.*; import java.rmi.server.*;

/**

*Abstraction representing a channel for sending messages. There

*is only one copy of this Channel object, and multiple stubs for

*the channel can be generated and passed around from client to

*client. When all the stubs have been garbage collected, this

*original Channel object will be collected via the Distributed

*Garbage Collector. This will force the Channel object to free

*the associated queue of messages in the Message Queue - see the

*finalize() method below.

*/

public class Channel extends UnicastRemoteObject implements IChannel, Unreferenced {

.

.

.

public void unreferenced() { try {

System.out.println("Channel.unreferenced() called."); queue.destroyChannel(this);

}

catch (Exception e) { System.err.println(e);

}

}

.

.

.

}

Source A.9 MessageQueue.java.

The following is the log for the Message Queue:

MessageQueue starting up...

MessageQueue now in ready mode.

Channel Log created.

<Many minutes later, after all clients disconnected...>

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

556 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

Channel.unreferenced() called.

Channel Log is now closed.

As you can see, even though we never directly destroyed the channel’s queue, the Channel object destroyed its own queue when all remote clients disconnected. When trying this example out, be patient because the DGC often takes a very, very long time before calling unreferenced().

RMI, CORBA, and EJB

Let’s conclude our RMI discussion with a few thoughts on how RMI, CORBA, and EJB are related.

RMI or CORBA?

Historically, developers have had to decide between RMI as a simple networking package and CORBA as a heavyweight networking technology that provides additional enterprise-level services. But, as we mentioned earlier in this chapter, the times are changing.

When you combine RMI with some of the other Java APIs, the benefits of CORBA begin to dwindle. For example, the Java Naming and Directory Interface provides naming and directory services, which are related to CORBA’s Naming Service. The Java Transaction API and Java Transaction Service can be used to perform robust transactions, which are related to CORBA’s Object Transaction Service. Security, MOM support, persistence, and more are all provided in the Java 2 Platform, Enterprise Edition. You can even achieve some semblance of cross-language interoperability by combining RMI with the Java Native Interface (JNI), called RMI/JNI. You can also perform relational database operations over the network by combining Java Database Connectivity (JDBC) with RMI, called RMI/JDBC.

CORBA, on the other hand, is becoming easier and easier to use. CORBA provides a breadth of functionality, which in the past has been very tough to use because you had to learn a separate Interface Definition Language (IDL). Now there are automatic tools that will generate IDL for you. Sun’s Java IDL product, for example, can read a standard remote interface definition and generate IDL automatically. And with the new CORBA Components proposal, it may be possible to provide many of CORBA’s services automatically, providing a rich server-side component architecture for developers.

For these reasons, Sun endorses both RMI and CORBA. There is no clear “winner” in networking technology. As both technologies mature, you’ll start to see

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

Understanding Java Remote Method Invocation (RMI) 557

many of CORBA’s services reflected in the Java 2 Platform, Enterprise Edition (J2EE), as well as the ease-of-use of the J2EE in CORBA. The advantage that the J2EE has right now is industry momentum. Many vendors are embracing the J2EE (in fact, most of those vendors are CORBA vendors). If you want to learn more about CORBA and RMI, please refer to Chapter 11.

RMI and EJB

RMI is an essential part of EJB. In EJB, many distributed objects use RMI as the standard API for networking.

EJB Objects

In EJB, your enterprise beans must be made available for remote clients to invoke. This is achieved by using Java RMI.

Note that enterprise beans are not full-fledged remote objects. That is, your beans do not extend UnicastRemoteObject. Rather, your beans are wrapped in an RMI-aware shell, called an EJB object. EJB objects are the remote objects clients invoke. When a client calls an EJB object, that object delegates the remote call to your bean. This is shown in Figure A.14.

As a bean developer, you need to write the interface to your bean’s EJB object. This interface is called the remote interface, and it is exactly the same concept as the remote interface that we have been discussing this entire chapter. This remote interface duplicates every method signature that your beans have. That’s how things appear seamless to clients—they invoke on the EJB object as if it were the bean itself.

Client Code, such

 

 

EJB Container/Server

 

 

 

as servlets or

 

 

 

applets

 

 

 

 

<< invoke>>

 

 

 

 

 

 

 

 

 

 

EJB Object

Remote

<<delegate>>

Interface

 

 

Enterprise

 

Bean

Figure A.14 RMI and EJBObjects.

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

558 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

Here are some characteristics about remote interfaces in EJB:

■■An EJB remote interface derives (indirectly) from java.rmi.Remote.

■■Each method in an EJB remote interface must throw a java.rmi

.RemoteException.

■■Each of the remote interface’s methods must accept parameters that are valid types for Java RMI. This means your parameters need to be primitives, serializable, or remote objects. This also means that by using the techniques described in this appendix, you can control the pass-by-value or pass-by-reference parameter semantics to your beans.

The EJB object implements the remote interface. But you don’t need to write the EJB object—it is automatically generated for you by the EJB container’s tools. This is because the EJB object must contain proprietary logic for dealing with transactions, interact with the container in a proprietary way, possibly implement fault tolerance if your bean crashes, and perform other operations that involve the container. That is why you should think of the EJB object as being part of the container itself. The EJB object masks these hairy details from the average bean developer.

The EJB object your clients use can be either the actual EJB object or a RemoteStub to an EJB object that is located elsewhere on the network. Your client code doesn’t care because it’s invoking on the EJB object’s interface, which both the object and the stub implement. Thus, EJB local/remote transparency is achieved through RMI.

Home Objects

In EJB, a home object is a factory for creating EJB objects. You look up the Home Object using the Java Naming and Directory Interface (JNDI), which is described in Appendix B. Once you have a home object, you call it using Java RMI.

The home object’s interface (called the home interface) is also a Java RMI remote interface, and it obeys the rules for Java RMI. It must throw remote exceptions, implement java.rmi.Remote, and accept serializable parameters. As with EJB objects, home objects are proprietary to each container. Thus, the home object’s implementation is generated by the EJB container vendor’s tools.

Clients of home objects always deal with the home interface, just as clients of EJB objects always deal with remote interfaces. And as with EJB objects, a reference to a home object could be the actual home object or a RemoteStub to the real home object located elsewhere on the network. This is shown in Figure A.15.

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

Understanding Java Remote Method Invocation (RMI) 559

Client Code, such as servlets or

applets

4: Return the EJB Object reference to the client

EJB Container/Server

1: Create or find a Bean for me

 

 

Home Object

 

 

 

 

 

 

 

 

 

3: Acquire a Bean, and link it

 

 

 

 

 

 

 

Home

 

 

 

 

with the EJB Object

 

Interface

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2: Create the EJB Object

 

 

 

 

 

 

 

 

 

 

 

 

Enterprise

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Bean

 

 

 

 

 

 

 

 

 

 

EJB Object

Remote

Interface

Figure A.15 RMI and home objects.

Summary

In this chapter, you’ve learned how Java RMI adds distributed object computing power to your Java applications. We’ve looked at RMI’s architecture, comparing it to traditional RPCs. We examined stubs and skeletons, the RMI registry, the RMI compiler, and we’ve looked at the two ways parameters were passed in RMI. We also took a brief tour of object serialization.

To make things more concrete, we then went through several RMI examples. First, we looked at a simple networked application that flipped a number to its inverse. We then took RMI a step further, and we implemented a useful Message Queue utility. Our last and most advanced RMI example stepped through how to exploit Distributed Garbage Collection for cleanup of state.

Finally, we wrapped up by discussing how RMI, CORBA, and EJB relate. You’ve taken a big step here and learned an important part of the Java 2 Platform, Enterprise Edition. The next appendix covers another essential concept: naming and directory services.

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

A P P E N D I XB

Understanding the Java Naming

and Directory Interface (JNDI)

he Java Naming and Directory Interface (JNDI) is an essential component of Tthe Java 2 Platform, Enterprise Edition (J2EE). JNDI adds value to your enterprise deployments by providing a standard interface for locating users, machines, networks, objects, and services. For example, you can use the JNDI to locate a printer on your corporate Intranet. You can also use it to locate a Java object or to connect with a database. In EJB, JNDI is used extensively for the

purposes of locating objects across an enterprise deployment.

This appendix will explore the various facets of JNDI, including why it was created, what it’s useful for, and how to use it. After reading this appendix, you’ll be armed with knowledge about naming, directories and how they are accessed from Java. You’ll also see how JNDI is used in the EJB world.

We’ll begin with a quick overview of naming and directories. From there, we’ll go into the specifics of the JNDI package, and we will walk through several examples. Finally, we’ll wrap up with thoughts on how EJB and JNDI are used together.

You’ll notice that this appendix goes into a lot of detail about JNDI, especially for an EJB book. And rightfully so! JNDI is a vital part of J2EE, and it is used in EJB, RMI, JDBC, and more. It is the standard way of looking things up over the network. Because JNDI is so ubiquitous in J2EE, it’s important that you acquire a solid foundation in this technology.

561

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

562 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

Naming and Directory Services

To understand JNDI, we must first understand the concept of naming and directory services.

A naming service is analogous to a telephone operator. When you want to call up someone over the phone and you don’t know that person’s phone number, you can call your telephone company’s information service operator to look up the person you want to talk with. You supply the telephone operator with the name of the person. The operator then looks up the phone number of the person you want to speak with and can dial the number for you, connecting you to that person.

A naming service is an entity that performs the following tasks:

■■It associates names with objects. We call this binding names to objects. This is very similar to a telephone company’s associating a person’s name with a specific residence’s telephone number.

■■It provides a facility to find an object based on a name. We call this looking up or searching for an object. This is similar to a telephone operator finding a person’s telephone number based on that person’s name and connecting the two people together.

Naming services are everywhere in computing. When you want to locate a machine on the network, the Domain Name System (DNS) is used to translate a machine name to an IP address. If you look up “wiley.com” on the Internet, the name “wiley.com” is translated into the object (which happens to be a String) 199.171.201.14 by the DNS.

Another example of naming occurs in file systems. When you access a file on your hard disk, you supply a name for the file such as “c:\autoexec.bat” or “/etc/ fstab.” How is this name translated into an actual file of data? A File System Naming Service can be consulted to provide this functionality.

In general, a naming service can be used to find any kind of generic object, like a file handle on your hard drive or a printer located across the network. But one type of object is of particular importance: a directory object (or directory entry). A directory object is different from a generic object because you can store attributes with directory objects. These attributes can be used for a wide variety of purposes.

For example, you can use a directory object to represent a user in your company. You can store information about that user, such as the user’s password, as attributes in the directory object. If you have an application that requires authentication, you can store a user’s login name and password in directory object attributes. When a client connects to your application, the client supplies

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

Understanding the Java Naming And Directory Interface (JNDI) 563

a login name and password, which you can compare with the login name and password that are stored as a directory object’s attributes. If the data matches, the user is authenticated. If the data doesn’t match, your application can return an error. You can also store other attributes, too, besides a login name and password, such as a user’s e-mail address, phone number, and postal address.

A directory service is a naming service that has been extended and enhanced to provide directory object operations for manipulating attributes. A directory is a system of directory objects, all connected. Some examples of directory products are Netscape Directory Server and Microsoft’s Active Directory. Your company probably uses a directory to store internal company information—locations of computers, current printer status, personnel data, and so on.

What does a directory look like internally? The directory’s contents—the set of connected directory objects—usually forms a hierarchical tree-like structure. Why would you want a tree-like structure? Well, a tree’s form suggests the way a real-world company is organized. For example, the root (or top node) of your directory tree can represent your entire company. One branch off the root could represent people in the company, while another branch could represent network services. Each branch could have subtrees that decrease in granularity more and more, until you are at individual user objects, printer objects, machine objects, and the like. This is illustrated in Figure B.1.

Information about how a directory is organized is contained in metadata. Directory metadata defines the structure of your directory. It defines the schema of how your directory is laid out. Metadata supplies a set of rules about your directory, such as restrictions on tree branches, restrictions on attributes, and more. This is analogous to how a telephone book might restrict information about a person’s home address to include a zip code. Usually, you can modify a directory’s metadata usually by playing with the administrative tools that ship with the directory product.

All in all, directories are not very different from databases. A database can store arbitrary data, just like a directory. Databases provide query operations to look up items in a database, just like directories. You can think of a directory as a scaled-down, simplified database. In fact, most directories are implemented by a database behind the scenes.

Problems with Naming and Directories

There are many popular naming and directory products out today. Directory vendors differentiate their product lines by offering different types of services. Unfortunately, this leads to different naming and directory standards. And each directory standard has a different protocol for accessing the directory. For example, directories based on the Lightweight Directory Access Protocol (LDAP)

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