Mastering Enterprise JavaBeans™ and the Java 2 Platform, Enterprise Edition - Roman E.
.pdf
|
|
Understanding Java Remote Method Invocation (RMI) |
|
513 |
|
|
|
|
|
|
|
||
|
Client |
|
Client |
|
||
|
|
|
|
|
|
|
RMI facility to
lookup remote Stub objects
Network |
|
Network |
|
|
|
Once a stub is |
|
|
|
acquired... |
|
|
Remote |
Skeleton |
|
RMI Registry |
Objects |
||
|
Remote Object
Figure A.3 Bootstrapping with the RMI Registry.
3.Finally, append the name of the remote object to which you wish to acquire a remote reference. For example, if your remote object is bound as the name “myObject”, you can reference it from any machine in the world with the RMI URL rmi://foobar.baz.com/myObject.
Looking Up a Remote Object
So far, our discussion has touched the following concepts:
■■An RMI Registry is a remote object used by clients for bootstrapping, or initially connecting, to your remote objects. Remote objects register themselves with the registry, which clients connect to at a well-known port.
■■RMI URLs are used to identify the locations of objects over the network.
How do clients use these two abstractions to actually connect to remote objects? This is what the java.rmi.Naming class is used for. When a client wants to acquire a reference to a remote object, he or she goes through java.rmi.Naming.
Go back to the first page for a quick link to buy this book online!
514 
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
RMI URLs versus JNDI
RMI URLs are great for identifying object locations across the network, but they are fairly inflexible for enterprise computing. You need to hard-code RMI URLs into your Java code (or provide them in properties files). If the locations of your distributed objects change, you must change and possibly redeploy each client of those distributed objects. In essence, there is no location transparency of distributed objects.
A much more flexible system of looking up distributed objects is to use naming and directory services through the Java Naming and Directory Interface (JNDI). Naming and directory services allow for your client code to escape hard-coding the locations of distributed objects, yielding a much more robust deployment. We’ll study how that’s done in Appendix B.
java.rmi.Naming is responsible for connecting to RMI registries for the purposes of finding remote objects.
The most important method that java.rmi.Naming exposes is the lookup() method, which takes an RMI URL, connects to an RMI registry on a target JVM, and returns a java.lang.Object representing the remote object. The returned object is actually the remote stub, and it can be cast into your remote object’s interface type.
RMIC—The RMI Compiler
The stubs and skeletons we described earlier provide a screen to block networking issues and make it appear as if things are happening locally. Both stubs and skeletons must implement your custom remote objects’ interfaces. Because of
Skeletons in the Java 2 Platform
The RMI runtime in Java 2 contains generic code that will perform the function of skeletons for you. Hence, skeleton generation is optional in Java 2. Stubs, on the other hand, are still required to be generated for each remote object.
This makes sense because a skeleton is responsible for delegating invocations to a remote object. It doesn’t matter to what interface the skeleton code conforms. A stub, on the other hand, is accessed directly by your client code and hence must implement your remote object’s remote interface. This gives clients the illusion that they are invoking on a local object implementation.
Go back to the first page for a quick link to buy this book online!
Understanding Java Remote Method Invocation (RMI) 
515
|
.java |
|
|
|
.class |
|
|
.class |
Remote object |
|
Remote object |
|
Stub |
||||
implementation |
Java compiler |
implementation |
RMI Compiler |
|||||
|
|
|
|
|
|
|||
|
.java |
|
|
.class |
|
.class |
Remote interface |
Remote interface |
Skeleton |
||||
Figure A.4 Generating stubs and skeletons with RMIC. |
|
|||||
this, no two stubs or skeletons are the same, and they must be generated anew for each remote object class that you create. Fortunately, Sun ships a tool to perform this generation for you. The name of the tool is rmic, the RMI compiler. It takes as input your remote object implementation (the class that implements your remote interface), and it creates a stub and skeleton for that remote object. This is shown in Figure A.4. The stub mimics each method exposed by the remote object, copying the method signatures exactly, so clients can call that stub locally as if the remote object itself were there.
Object Serialization and Parameter Passing
This next section discusses how parameters are passed in Java RMI. We also explore the power of object serialization and how it assists in parameter passing and object marshalling/unmarshalling.
Passing by Value
When invoking a method using RMI, all parameters to the remote method are passed by value. This means that all parameters are copied from one machine
Taking a Look at the Generated Proxy Code
You can use the -keepgenerated option of rmic to see the generated stub (or “proxy”) code. This is useful if you want to learn how RMI works internally. It’s also great if you want to rewrite your own stub/skeleton layer of RMI. You can use these generated proxies as a basis for your code.
Go back to the first page for a quick link to buy this book online!
516 
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
to the other when the target method is invoked.
Passing objects by value is in stark contrast with the Java programming language, which uses a pass-by-reference calling convention for an object’s state. In Java, when calling a method normally with an Object parameter, the reference to the object is copied, but the actual object’s data is not.
There’s a big problem with passing by value. If you’re trying to pass an object over the network and that object contains references to other objects, how are those references resolved on the target machine? A memory address on one machine does not map to the same memory address on another machine. Also, the referenced object may not even exist on the target machine. How do we get around this?
Object Serialization
Java introduces the concept of object serialization to handle this problem. Serialization is the conversion of a Java object into a bit-blob representation of that object. Once in bit-blob form, the object can be sent anywhere—onto your hard disk or across the network. When you’re ready to use the object again, you must deserialize the bit-blob back into a Java object. Then it’s magically usable again.
The Java language handles the low-level details of serialization. In most cases, you don’t need to worry about any of it. In order to tell Java that your object is serializable, your object must implement the java.lang.Serializable interface. That’s all there is to it—take this one simple step, and let Java handle the rest. java.lang.Serializable defines no methods at all—it’s simply a marker interface that identifies your object as something that can be serialized and deserialized.
How Objects Are Serialized
Once your objects implement java.lang.Serializable, they can be serialized into a stream of data. The serialization process is accomplished automatically by Java Serialization. You can provide your own custom serialization by implementing the writeObject() method on your object. This might be useful if, for example, you’d like to perform some sort of compression on your data before your object is converted into a bit-blob.
Similarly, deserialization is also automatic in most cases. If you want to, you can provide your own deserialization method as well. This method is called readObject(), and it is called automatically whenever your object is deserialized. This might be useful if, for example, you’d like to decompress your object’s data during the deserialization process.
This process is shown in Figure A.5.
Go back to the first page for a quick link to buy this book online!
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
java.io.Serializable |
|
Class2 |
|
|
|
||
|
|
|
|
||||
|
|
|
|
|
|||
|
|
|
|
Class3 c |
|
|
|
|
|
MyClass |
|
|
|
|
|
int a |
|
|
|
|
|
|
|
transient long b |
|
|
|
|
|
||
String s |
|
|
java.io.Serializable |
|
|
|
|
Class2 c |
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 |
|||||
518 |
|
||||||
|
|
|
|
java.io.Serializable |
|
java.io.Serializable |
|
Class3
java.lang.String
When serializing MyClass, Object Serialization will recurse through the dependencies shown, packaging up the entire graph of objects as a stream. In this diagram, everything will get serialized except for transient long b, since it is marked as transient.
Figure A.6 Object serialization.
handled automatically by Java serialization, as shown in Figure A.6. You simply need to make sure that each of your member objects implements the java.lang. Serializable interface.
What Should You Make Transient?
How do you know which member variables should be marked transient and which should not? Here are some good reasons why you would want to mark an object as transient:
■■The object is very large. Large objects may not be suitable for serialization because operations you do with the serialized blob may be very intensive.
Go back to the first page for a quick link to buy this book online!
Understanding Java Remote Method Invocation (RMI) 
519
Examples here include saving the blob to disk or transporting the blob across the network.
■■The object represents a resource that cannot be reconstructed on the target machine. Some examples of such resources are database connections and sockets.
■■The object represents sensitive information that you do not want to pass in a serialized stream.
Note that object serialization is not free—it is a very heavyweight operation for large graphs of objects. Make sure you take this into account when designing your distributed object application.
Uses of Object Serialization
Object serialization is the mechanism used when passing parameters by value using RMI. When you pass an argument using RMI, RMI checks whether your object is serializable. If it is, it serializes the object and sends it over the network. The recipient takes the object and deserializes it, making it available for use. When the object is deserialized, all of its references to other objects are automatically reconstructed because those objects referred to were also part of the bit-blob. There’s no danger of a reference being invalid after an invocation because references are dynamically reconstructed in real time. This is shown in Figure A.7.
Thus, object serialization assists Java RMI with the marshalling (packaging) of parameters and the unmarshalling (unpackaging) of parameters. But serialization has a wide variety of other purposes as well. For instance, object serialization provides an instant file format for your objects. All you need to do is serialize them and write the serialized bit-blob to disk. It’s a quick and easy way to make your state persistent. For more information about Object Serialization, please see the book’s accompanying Web site.
How RMI Simulates Pass by Reference
As we’ve said, Java RMI relies on Object Serialization for passing parameters via remote method invocations. The scenario we’ve described is pass by value, where an entire graph of objects is serialized into a bit-blob, sent across the network, and then deserialized on the target machine.
But passing parameters by value can lead to inefficiencies. What if your referenced graph of objects is very large? What if you have lots of state to send across the network? The ensuing network lag from performing the invocation may be unacceptable.
Go back to the first page for a quick link to buy this book online!
522 
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
Because Java RMI stubs are also serializable, they are passable over the network as a bit-blob. This is why earlier we said that all parameters in Java RMI are passed by-value. Thus, Java RMI only simulates pass by reference by passing a serializable stub, rather than serializing the original object. By making your parameters remote objects, you can effectively avoid the network lag in passing large objects.
In summary, we have the following rules for passing objects using Java RMI:
■■All Java basic primitives are passed by value when calling methods remotely. This means copies are made of the parameters. Any changes to the data on the remote host are not reflected in the original data.
■■If you want to pass an object over the network by value, it must implement java.lang.Serializable. Anything referenced from within that object must follow the rules for Java Serialization. Again, any changes to the data on the remote host are not reflected in the original data.
■■If you want to pass an object over the network by reference, it must be a remote object, and it must implement java.rmi.Remote. A stub for the remote object will be serialized and passed to the remote host. The remote host can then use that stub to invoke callbacks on your remote object. There is only one copy of the data at any time, which means that all hosts are updating the same data.
Exporting Your Remote Objects
To make your object a remote object available to be invoked on by remote hosts, your remote class must perform one of the following steps:
Extend the class java.rmi.server.UnicastRemoteObject. UnicastRemoteObject is a base class from which you can derive your remote objects. When your remote object is constructed, it will automatically call the UnicastRemoteObject’s constructor, which will make the object available to be called remotely. You can see this by looking at the code for UnicastRemoteObject constructor, included with the Java 2 platform (formerly known as JDK Java Development Kit 1.2):
protected UnicastRemoteObject() throws RemoteException {
exportObject((Remote)this);
}
Don’t extend java.rmi.server.UnicastRemoteObject. Perhaps your objects are inheriting implementation from another class. In this case, because Java does not allow for multiple implementation inheritance, you cannot extend UnicastRemoteObject. If you do this, you must manually export your object
Go back to the first page for a quick link to buy this book online!




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
Class3 Obj3 = new Class3();
