Mastering Enterprise JavaBeans™ and the Java 2 Platform, Enterprise Edition - Roman E
..pdfJ2EE in the Real World: Combining Servlets with Enterprise JavaBeans 501
One way to perform all retrieval of these entity beans is to define specialized finder methods. For example, a method such as
findBeansMatching(String criteria, int numToReturn)
could yield at most numToReturn matches, which is highly useful for displaying discrete chunks of data. The trade-off here is overall database load. Databases are designed to handle batch operations very well. Single individual queries cannot be optimized as well. Therefore, if you need to scan through all the entity beans in the database, your overall database usage has increased.
Another question you should be asking yourself is if you really need a finder method at all. Remember that every time a finder method is called, an EJB object is constructed for every element in the returned Enumeration (or Collection in Java 2). Instead, having a session bean perform these queries for you directly at the database level may improve performance. Once you’ve found the Primary Keys for the entity beans you’re looking for, you can construct EJB objects for only those beans via a findByPrimaryKey() on the found keys.
Summary
In this chapter, we’ve finally completed our e-commerce deployment. We began the chapter by writing our e-commerce servlets, and we showed how they tied in with enterprise beans. We then executed the deployment and looked at ways to extend it. Finally, we covered some broad performance tuning tips that apply not only to this deployment, but to almost any other EJB deployment as well. If you’ve made it this far, then congratulations because you now have a realworld e-commerce deployment using EJB under your belt!
Go back to the first page for a quick link to buy this book online!
506 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 ease of use of RMI is becoming available in CORBA. In essence, the two camps are converging. We’ll look at exactly how later in this appendix and also in Chapter 11.
This appendix examines the benefits and drawbacks of RMI and details the architecture and logic behind it. We also compare RMI with CORBA, and we examine how RMI and EJB relate. After reading this, you will be able to write your own distributed object applications based on the RMI standard.
Remote Method Invocations
A remote procedure call (RPC) is a procedural invocation from a process on one machine to a process on another machine. RPCs enable traditional procedures to reside on multiple machines, yet still remain in communication. They are a simple way to perform cross-process or cross-machine networking.
A remote method invocation in Java takes the RPC concept one step further and allows for distributed object communications. RMI allows you to invoke methods on objects remotely, not merely procedures. You can build your networked code as full objects. This yields the benefits of an object-oriented programming, such as inheritance, encapsulation, and polymorphism.
Remote method invocations are by no means simple. Below are just some of the issues that arise:
Marshalling and unmarshalling. Remote method invocations (as well as RPCs) allow you to pass parameters, including Java primitives and Java objects, over the network. But what if the target machine represents data differently than the way you represent data? For example, what happens if one machine uses a different binary standard to represent numbers? The problem becomes even more apparent when you start talking about objects. What happens if you send an object reference over the wire? That pointer is not usable on the other machine because that machine’s memory layout is completely different from yours. Marshalling and unmarshalling is the process of massaging parameters so that they are usable on the machine being invoked on remotely. It is the packaging and unpackaging of parameters so that they are usable in two heterogeneous environments. As we shall see, this is taken care of for you by Java and RMI.
Parameter passing conventions. There are two major ways to pass parameters when calling a method: pass-by-value and pass-by-reference, as shown in Figure A.1. When you pass by value, you pass a copy of your data so that the target method is using a copy, rather than the original data. Any changes to the argument are reflected only in the copy, not the original. Pass-by-reference,
Go back to the first page for a quick link to buy this book online!
508 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
and it leaves the destruction of objects to the underlying Java Virtual Machine. But in a distributed object system, things become more complicated. An object residing on a remote host might have a reference (called a remote reference) to a local object. Thus, the remote host has a reference that actually refers to an object across the network, rather than a local object. But how does garbage collection work then? After all, a JVM’s garbage collector runs within that JVM and does not take into account object references from remote hosts. Because of this, a distributed garbage collector is needed to track remote hosts that reference local objects.
Network or machine instability. With a single JVM application, a crash of the JVM brings the entire application down. But consider a distributed object application, which has many JVMs working together to solve a business problem. In this scenario, a crash of a single JVM should not cause the distributed object system to grind to a halt. To enforce this, remote method invocations need a standardized way of handling a JVM crash, a machine crash, or network instability. When some code performs a remote invocation, the code should be informed of any problems encountered during the operation. RMI performs this for you, abstracting out any JVM, machine, or network problems from your code.
Downloadable implementations. Remote method invocations allow you to pass whole Java objects as parameters to methods invoked over the network. This means, for example, that you can pass a java.lang.String over the network as a parameter to a method. If you pass an entire Java object to a target machine, what you’re really passing is that object’s data to the target machine. In our String example, this could be the String’s character buffer. But objects also contain code, and that code might not be available on the target machine. For example, String objects have a method called length()that returns the length of the String. This logic, as well as the other logic surrounding objects, is stored in .class files in Java. The target machine needs those class files so that it can construct the code portion of the objects you send as parameters to methods over the network. RMI allows for these class files to be automatically downloaded behind the scenes, relieving you of this dogmatic chore. This also means RMI is a very dynamic system, allowing for different object implementations to come in over the wire.
Security. We mentioned that RMI contains built-in dynamic class loading. This allows object implementations to arrive from remote, and possibly hostile, sources. Java applets are perfect examples because they are downloaded on the fly and could be malicious. A security mechanism needs be in place to restrict possibly hostile implementations and grant system-level access only to authenticated implementations. RMI has such support.
Activation. You’d like to be able to invoke methods on remote objects, even if they are not in memory yet. If you invoke a method on a remote object that is
Go back to the first page for a quick link to buy this book online!
Understanding Java Remote Method Invocation (RMI) 509
not in memory yet, RMI contains measures to automatically fault the object into memory so that it can service method calls. This is called remote object activation.
As you can see, there’s a lot involved in performing remote method invocations. RMI contains measures to handle many of these nasty networking issues for you. This reduces the total time spent dealing with the distribution of your application, allowing you to focus on the core functionality.
RMI is the Java language’s native remote method invocation service. It ships with the Java 2 platform, and it is required for any 1.1-compatible Java Runtime Environment. It is built entirely in Java and is therefore highly cross-platform. This is a big win for RMI—you can write your networking code once and run it in any recent Java Runtime Environment. Contrast this with proprietary, platformdependent RPC libraries, and you can see some real value in RMI.
Java RMI has historically not been supported by Microsoft. If you wanted to use Microsoft’s Java environment, you needed to download an RMI add-on, available at ftp://ftp.microsoft.com/developr/msdn/unsup-ed/rmi.zip. A recent court order, however, has required Microsoft to support Java RMI in future versions of its product. Make sure the environment you’re developing with does indeed support RMI.
RMI Architecture
In RMI, any object whose methods can be invoked from another Java VM is called a remote object. Remote objects are networked objects, which expose methods that can be invoked by remote clients. The physical locations of remote objects and the clients that invoke them are not important. For example, it’s possible for a client running in the same address space as a remote object to invoke a method on that object. It’s also possible for a client across the Internet to do the same thing. To the remote object, both invocations appear to be the same.
RMI and Interface versus Implementation
In Chapter 1, we discussed one of object-oriented design’s great programming practices—the separation of the interface of code from its implementation.
The interface defines the exposed information about an object, such as the names of its methods and what parameters those methods take. It’s what the client works with. The interface masks the implementation from the viewpoint of clients of the object, so clients deal only with the end result: the methods the object exposes.
Go back to the first page for a quick link to buy this book online!
510 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 implementation is the core programming logic that an object provides. It has some very specific algorithms, logic, and data.
By separating interface from implementation, you can vary an object’s proprietary logic without changing any client code. For example, you can plug in a different algorithm that performs the same task more efficiently.
RMI makes extensive use of this concept. All networking code you write is applied to interfaces, not implementations. In fact, you must use this paradigm in RMI—you do not have a choice. It is impossible to perform a remote invocation directly on an object implementation. You can operate solely on the interface to that object’s class.
To designate that your object can be invoked on remotely, your class must implement the interface java.rmi.Remote. You must perform this by creating your own custom interface extending java.rmi.Remote. That interface should have within it a copy of each method your remote object exposes.
For example, the following code snippet is a valid remote interface:
public interface IMyRemoteInterface extends java.rmi.Remote {
public void foo() throws java.rmi.RemoteException;
}
Your remote object implementation (that is, the networked object) implements this interface. Client code that wants to call methods on your remote object must operate on IMyRemoteInterface.
An additional restriction of RMI is that each method must also throw a java.rmi
.RemoteException. A java.rmi.RemoteException is thrown when there is a problem with the network, such as a machine crashing or the network dying. Your remote objects can throw their own regular exceptions in addition to the required java.rmi.RemoteException.
Stubs and Skeletons
One of the benefits of RMI is an almost illusionary, transparent networking. You can invoke methods on remote objects just as you would invoke a method on any other Java object. In fact, RMI completely masks whether the object you’re invoking on is local or remote. This is called local/remote transparency.
But local/remote transparency is not as easy as it sounds. To mask the fact that you’re invoking on an object residing on a remote host, RMI needs to somehow simulate a local object that you can invoke on. This local object is called a stub, and it is responsible for accepting method calls locally and delegating those
Go back to the first page for a quick link to buy this book online!
Understanding Java Remote Method Invocation (RMI) 511
method calls to their actual object implementations, which are possibly located across the network. This effectively makes every remote invocation appear to be a local invocation. You can think of a stub as a placeholder for an object that knows how to look over the network for the real object. Because you invoke on local stubs, all the nasty networking issues are hidden behind the scenes.
Stubs are only half of the picture. We’d like the remote objects themselves— the objects that are being invoked on from remote hosts—to not worry about networking issues as well. Just as a client invokes on a stub that is local to that client, your remote object needs to accept calls from a skeleton that is local to that remote object. Skeletons are responsible for receiving calls over the network (perhaps from a stub) and delegating that call to the remote object implementation. This is shown in Figure A.2.
One of the more interesting responsibilities of stubs and skeletons is the marshalling and unmarshalling of parameters. RMI relies on a technology called object serialization to assist with this, which we’ll learn about a bit later.
Client |
|
Remote Object |
|
|
|
Remote Interface
Stub |
|
Skeleton |
|
|
|
Network
Figure A.2 Stubs and skeletons.
Go back to the first page for a quick link to buy this book online!
512 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
Bootstrapping and the RMI Registry
For a client and a server to start talking, they need some way to connect. Acquiring this connection is known as bootstrapping. How does RMI accomplish bootstrapping?
RMI provides an entity known as the RMI Registry for this purpose. When you want to make an object remotely accessible, you register it with the registry. You give the registry a name for the object during this registration. From then on, the Registry will route all incoming requests for that name to your object. You can think of the RMI Registry as a giant hashtable that maps names to objects.
The RMI Registry accomplishes this task by sitting at a well-known network port and listening for incoming connections. When a remote client wants to access an object registered with a particular registry, the client issues a request over the network to the registry. The Registry reads the request, looks up the name of the remote object requested, and returns the stub for that remote object to the client. This is shown in Figure A.3.
You can have as many RMI registries as you want on a machine, but only one Registry per VM. And, of course, only one Registry can be bound to a specific port. There are thousands of ports for you to choose from, though, so that’s no problem. If you don’t specify a port, RMI uses port 1099 by default. Remember that both your client and server must agree on which port the Registry sits at, or they will never find each other.
There are two ways to start the RMI Registry. You can launch it as a stand-alone program by typing
rmiregistry
from a command prompt. You can also start a registry from inside your Java program by accessing the java.rmi.Registry class.
RMI URLs
An RMI URL is a Java String that is used to locate a remote object on another Java Virtual Machine. It looks very similar to other types of URLs, such as http:// www.java.sun.com or ftp://ftp.microsoft.com. RMI enforces the following conventions for URLs:
1.The URL must begin with the text rmi://.
2.Next, you may specify the target machine where the Java Virtual Machine is located—for example, rmi://foobar.baz.com/. If you don’t specify a target machine, RMI defaults to the local host.
Go back to the first page for a quick link to buy this book online!