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

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

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

320 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

■■Behind the scenes, Java RMI uses the Java Remote Method Protocol (JRMP) protocol for performing client/server communications. This occurs beneath the stub/skeleton layer as well.

Thus, CORBA and RMI are quite similar in how they perform remote invocations. They each have an API layer (stubs/skeletons) that uses either IIOP or JRMP as the wire protocol for transmitting data across the network.

The protocol being used is the key to interoperability of CORBA and RMI. RMI skeletons are always expecting a request to come in via the JRMP protocol, and CORBA skeletons are always expecting data to come in using the IIOP protocol. But this protocol layer should be totally pluggable. We should be able to, for example, switch out RMI’s JRMP protocol and switch in the IIOP protocol. If we did this, we could perform the following procedure (see Figure 11.4):

1.An RMI client uses the RMI API and invokes a method on an RMI stub.

2.The RMI stub contacts a local ORB, which uses IIOP as the protocol for server communication, rather than the standard JRMP protocol.

3.On the server, an ORB is waiting to receive IIOP requests. With that ORB is the pure CORBA skeleton for our CORBA object implementation. The ORB receives the request. Because it’s formatted using IIOP, the request appears as though it came from a CORBA client, when in fact it came from an RMI client using the IIOP protocol.

4.The ORB passes the request to the CORBA skeleton, which delegates the invocation to the CORBA object implementation. The object implementation services the invocation.

5.When the invocation is complete, the return results are passed back through the pure CORBA skeleton, which returns control to the ORB. The ORB sends the results back over IIOP as usual.

6.A client-side ORB receives the return results via IIOP, and returns the results to the RMI client’s stub. The stub then returns control to the RMI client code.

This scenario is nice because it allows Java clients to use the RMI API to invoke methods on CORBA objects. What about CORBA clients invoking on RMI object implementations? This could be done as follows (see Figure 11.5):

1.A CORBA client invokes a method on a pure CORBA stub.

2.The IIOP protocol is used, as normal, as the wire-protocol over the network.

3.On the receiving end, an ORB is waiting to receive requests formatted with IIOP. The ORB receives the request and calls a special RMI skeleton that knows how to accept the call from an ORB. (Notice that our RMI skeletons are receiving the request via IIOP, rather than the traditional JRMP protocol.)

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

CORBA and RMI-IIOP 321

4.The RMI skeleton delegates the invocation to the RMI remote object implementation.

5.The RMI remote object implementation churns away and returns a result to the RMI skeleton.

6.The RMI skeleton returns the result to the ORB. The ORB returns the data over the network using IIOP (again, our RMI remote objects return data over IIOP rather than over JRMP).

7.The pure CORBA stub receives the result over IIOP and returns control to the CORBA client code.

So why is IIOP our protocol of choice, rather than JRMP? The reason is that IIOP is a much more robust protocol than JRMP (we’ll see the specific benefits in the next section). IIOP is supported by numerous vendors in the industry and has been designed with interoperability of heterogeneous distributed objects in mind.

The scheme we’ve just presented is the basis for the unification of CORBA and RMI, and it is called RMI over IIOP (or RMI-IIOP). RMI over IIOP allows for CORBA clients, RMI clients, CORBA object implementations, and RMI object implementations to be mixed and matched. This accomplishes our goal of creating a bridge between RMI and CORBA. To keep things straight, you may want to refer back to these two scenarios as you read the rest of this chapter.

Benefits of RMI over IIOP

Let’s now take a look at what we gain by using RMI over IIOP:

RMI and CORBA code achieve greater reusability. When performing simple networking of objects, you don’t need to choose between RMI and CORBA anymore. You can develop portable client code in Java using either the RMI or CORBA APIs. You can also develop portable Java object implementations using either the RMI or CORBA APIs. RMI over IIOP lessens the impact of switching between the two.

Code written in almost any language can call RMI object implementations. RMI objects are now truly language-independent network citizens, and they can be invoked from clients written in any language to which CORBA maps. This allows you to plug RMI object implementation into an existing system. It also paves the way for the future, as existing RMI code can be leveraged as languages evolve. And with the COM/CORBA bridge, the possibility emerges for a COM-compliant object to connect with an RMI server.

RMI clients can now be integrated into legacy systems. Perhaps you have an existing investment written in C++, COBOL, or some other language that CORBA maps to, including C, C++, Java, SmallTalk, Ada, and COBOL. As

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

322 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

we’ve mentioned, you can use straight CORBA to take these existing object implementations into the interoperable CORBA realm. Add RMI over IIOP, and you’ve got the simplicity of an RMI client, while still leveraging your existing investment.

IIOP gives RMI robust firewall navigation. One nice thing about using an industry standard protocol such as IIOP is that you gain all the support behind it. For example, as we mention in Appendix A, RMI has the ability to tunnel through firewalls. This is a very slow and arduous process, and it is really a security loophole. The CORBA community is making headway in developing an extensible way for distributed objects to communicate through firewalls. Special IIOP firewall proxies are being developed that will permit IIOP traffic to pass through. If you use the IIOP protocol, any RMI or CORBA code you write will have a natural way of navigating firewalls. Unfortunately, there is a severe limitation to the effectiveness of these proxies: You have to have the firewall proxy on both the client and the server systems. A company can’t set up a business-to-consumer e-commerce site and expect an IIOP proxy to solve the firewall problem. If the client’s system has a firewall, the client won’t be able to send an IIOP call out through the net. For limited applications (such as intranet applications or Internet applications where they can control the client and server systems), IIOP proxies add value. Iona is an example of a vendor that provides such an IIOP proxy, called WonderWall. Inprise makes one too, called Gatekeeper. See the book’s accompanying Web site for links to these products (www.wiley.com/compbooks/roman).

IIOP gives RMI a portable way to propagate contexts. Let’s say your code is involved in a transaction or has security credentials associated with it. Most systems (including EJB) manifest transaction and security data in contexts. When you perform an invocation, you want this context information to be propagated automatically to the receiving system, so the object implementation can execute its business logic for you within the same contexts. We first introduced this concept of propagation in Chapter 10. With RMI, context propagation is done in a proprietary way, as RMI itself has no built-in way to accomplish propagation. This is a huge hindrance because as soon as propagation becomes proprietary, you cannot combine products from separate vendors. The IIOP protocol, and thus, RMI over IIOP, standardizes the way contexts are propagated. This is very important in the EJB world. In the past, you could have a mix of only CORBA-based EJB Servers working together because CORBA-based EJB servers are sharing transaction/context information in the same way (using IIOP). With RMI over IIOP, RMI-based EJB servers can be mixed with RMI-based or CORBA-based EJB servers because everyone is propagating context information using IIOP. This greatly improves EJB interoperability. (Note: The initial release of RMI/IIOP does not include support for propagation of service contexts. We hope this issue will be fixed in the next release.)

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

CORBA and RMI-IIOP 323

RMI object implementations can be invoked dynamically. Using CORBA’s Dynamic Invocation Interface (DII), described earlier in this chapter, you can perform runtime discovery of RMI object implementations and perform dynamic invocations. This is not a huge benefit, though, because you can use Java Reflection to achieve similar results with straight RMI.

Problems That Arise When Combining RMI with IIOP

Everything we’ve said so far sounds very pretty. But is it really that easy for RMI and IIOP to work together? After all, these are two technologies that have been developed separately. Indeed, when you scratch the surface you’ll find many semantic problems. Let’s take a look at the difficulties that Sun Microsystems and the OMG are working hard together to resolve.

Differences in Parameter Passing Conventions

CORBA objects have traditionally been passed around the network by reference. This means that when a client receives a reference to a CORBA object, that CORBA object never moves from its remote host. Clients invoke on the original objects rather than on copies of the CORBA objects passed to them. Java Objects are also passed by reference in the Java language.

RMI is more robust than CORBA here. RMI does not mandate that all objects are passed by reference. With RMI, you can pass an object by value, which means that a copy of the object is sent, rather than a remote reference to the original object. This is accomplished through object serialization, as shown in Appendix A.

Needless to say, this is a huge semantic difference between RMI and CORBA.

Solution: The OMG Objects-by-Value Specification

Fortunately, the OMG has developed an Objects-by-Value specification (published in February 1998), which allows CORBA objects to be passed by value. A special value type was added to OMG IDL, which allows for objects to be identified as passed by copy, rather than by reference.

Value objects in CORBA work much like objects that are passed by value in Java RMI. As you’ll see in Appendix A, the RMI parameter passing convention works as follows:

If the parameter is primitive or implements java.io.Serializable, it is passed by value. A copy of the parameter is sent to the target JVM.

If the parameter implements java.rmi.Remote, it is passed by reference.

A remote stub is passed to the target JVM, which serves as a “cross-JVM” reference to an object.

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

324 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

CORBA’s Objects-by-Value specification works very similarly. Objects-by-Value relies on a language (such as Java) to provide a mechanism (such as serialization) that will pack and unpack an object’s state, so that it can be passed over the wire. In fact, Java serialization (or an equivalent) is used in the Java version of Objects-by-Value.

To keep this discussion relevant to EJB, we’ve just touched on Objects-by-Value. The curious reader can download the complete Objects-by-Value specification free from ftp://ftp.omg.org/pub/docs/orbos/98-01-18.pdf.

The Objects-by-Value specification is quite useful. By introducing Objects-by- Value, RMI over IIOP can now support RMI’s by-value parameter passing convention. In addition, straight CORBA programmers can use it to send objects over the wire, reducing potential network round trips in pure CORBA systems.

Other Semantic Differences between RMI and CORBA

Parameter passing conventions are not the only differences between RMI and CORBA. There are other semantic differences as well. Let’s take a look at the major concerns:

Distributed garbage collection. RMI gives you an automatic way of cleaning up objects over the network with a distributed garbage collector (introduced in Appendix A). CORBA, on the other hand, has no such mechanism. Why? Because not every language that CORBA maps to even has the concept of asynchronous garbage collection.

Narrowing. When you receive an object using Java RMI, you can simply cast it into the desired object using a Java cast (as shown in the numerous examples in Appendix A). This is possible because RMI automatically downloads the appropriate stub for the object you’re dealing with. CORBA, however, does not have a mechanism for automatic stub downloading.

Java RMI programmers don’t want to learn OMG IDL. One of the niceties of Java RMI is that it’s all Java, which means you don’t need to learn a separate interface definition language (such as OMG IDL) to handle your networking needs. But with RMI over IIOP, you can mix CORBA clients with RMI server object implementations. Those CORBA clients are pure CORBA clients (with pure CORBA stubs), and they need to work with some IDL. That IDL needs to come from somewhere. Should we force Java RMI programmers to churn out an IDL file? If we make Java RMI coders learn OMG IDL, a large benefit of RMI has been lost.

Solution: The Java-to-IDL Mapping Specification

To resolve the semantic differences between RMI and CORBA, a separate OMG specification was made, called the Java-to-IDL Mapping specification. This

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

CORBA and RMI-IIOP 325

document details all of the subtleties of combining the RMI API with the IIOP protocol. It addresses issues such as distributed garbage collection and inheritance, as well as the resolution of the differences between RMI and CORBA. In essence, the Java-to-IDL Mapping document is the complete specification for RMI over IIOP.

Note the difference between the Java-to-IDL Mapping and the IDL-to-Java Mapping. Both are OMG specifications, but each has a very different purpose. The Java-to-IDL Mapping is not simply a description of how the Java language syntactically maps to OMG IDL. It is a specification for how RMI and CORBA camps can be combined.

Here are some highlights of the Java-to-IDL Mapping goals:

■■Java RMI and CORBA are semantically different. Trade-offs need to be made in several places to enable interoperability between the two technologies. Inevitably, some of the current Java RMI semantics are going to be unusable in the CORBA realm. Thus, the Java-to-IDL Mapping specification defines a subset of Java to which RMI programmers must now adhere. This subset is called RMI/IDL.

■■RMI/IDL needs to be a strict subset of Java RMI, to avoid creating yet another networking dialect.

■■RMI/IDL needs to support as large a subset of Java RMI as possible.

Let’s take a look at how Java-to-IDL solves some of the semantic differences between RMI and CORBA:

Distributed garbage collection (DGC). RMI over IIOP does not propose to accomplish distributed garbage collection. And rightfully so—DGC is in general a very hard problem to solve. Instead, the Java-to-IDL specification mandates that RMI coders cannot rely on distributed garbage collection when using RMI over IIOP. This is an unfortunate consequence of combining RMI with CORBA. Some RMI features need to be removed when migrating to the RMI/IDL feature subset of RMI.

Narrowing. When using RMI over IIOP, you cannot simply cast an object you receive over the network. Rather, you must explicitly call a narrowing method that will convert the object into the desired type for you.

Java RMI programmers don’t want to learn OMG IDL. One great benefit of Java RMI is that you don’t need to learn a separate interface definition language to perform remote computing. We’d like to preserve this feature. Therefore, RMI over IIOP defines a mapping from RMI/IDL types to OMG IDL types. This mapping means that there is a well-defined way for Java language types used by RMI over IIOP to be automatically mapped into OMG IDL. Once we have this, a vendor can write a tool that automatically performs this mapping. Such a tool is called a java-to-idl compiler. It takes in code written in Java

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

326 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 spits out OMG IDL. This IDL can be used by CORBA clients when calling your RMI remote object implementations. The IDL can also be used by CORBA object implementations that your RMI clients call.

Java-to-IDL allows you to build complete distributed applications in Java and then use apps written in other languages to invoke on your distributed application. The Java-to-IDL mapping simplifies your network programming tremendously. No longer do you have to write IDL and then translate that into Java. Java-to-IDL compilers allow you to write your Java app as you normally would, yet they allow for CORBA interoperability by generating IDL for you. This is a great convenience—Java RMI programmers gain the benefits of CORBA/IIOP interoperability, such as cross-language support, at a very low cost.

Steps to Take for RMI and CORBA to Work Together: An Overview

Now that you’ve seen the theory of combining RMI with CORBA, let’s see exactly what steps you need to take for interoperability.

The RMI-IIOP bundle itself is downloadable from Sun’s Web site. If you are going to be performing any RMI-IIOP programming, you may want to follow up by reading the documents included with this bundle, as well as the Java-to-IDL mapping specification. They give the complete set of changes to which RMI programmers must adapt in order to use RMI-IIOP. See the book’s accompanying Web site for a link to the RMI-IIOP download.

RMI-IIOP Client with a CORBA Object Implementation

Our first scenario depicts an RMI-over-IIOP client with a CORBA object implementation. As with all RMI clients, an RMI-IIOP client needs to call methods on a remote interface. In addition, the CORBA object implementation that the RMI client calls must have accompanying OMG IDL. You’d like to avoid writing OMG IDL explicitly because RMI is about simple network programming.

To accomplish this, perform the following steps:

1.Write your RMI remote interface. You write the remote interface in Java as you’d normally do for any RMI program. The remote interface is RMI’s client/server contract for distributed objects.

2.Generate the needed client-side RMI over IIOP stubs. The stubs will be used by the RMI-over-IIOP client to invoke on the CORBA object implementation. See the following section, “How Do I Generate Stubs and Skeletons?” for more details.

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

CORBA and RMI-IIOP 327

3.Generate the OMG IDL. When you define your CORBA object implementations, you’re going to need IDL. This IDL must match your RMI remote interface if you want RMI clients to be able to invoke your CORBA object implementations. Rather than laboriously writing it yourself, you can automatically generate it through a Java-to-IDL compiler. The Java-to-IDL compiler takes in your RMI remote interface and spits out OMG IDL. Where do you get a Java-to-IDL compiler? There’s one that ships free with RMI-IIOP. In fact, it’s built into the rmic tool. Simply call rmic with the –idl switch to generate IDL from your Java code.

4.Generate the needed server-side CORBA files. You’re going to need some helper code, such as skeletons for your CORBA object implementations. And remember that this helper code can be in any CORBA-compliant language in which you choose to implement your CORBA object implementations. This is where the IDL you generated in step 3 comes into play. When you define your CORBA object implementations, you can use any

How Do I Generate Stubs and Skeletons?

In Appendix A, you learned that the RMI compiler (rmic) is a tool for generating stubs and skeletons with RMI. Now, with RMI over IIOP, rmic has been bolstered with additional functionality to generate IIOP stubs and skeletons. The new RMI compiler generates two styles of stubs and skeletons:

It generates normal JRMP stubs and skeletons. This is the default behavior of rmic.

It also can generate IIOP stubs and skeletons. Use the –iiop flag to tell rmic you want IIOP stubs/skeletons.

The JRMP stubs and skeletons are only useful for creating a pure RMI client/server solution that uses JRMP. The IIOP stubs and skeletons are useful in the following three scenarios:

■■If you have an RMI client with a CORBA object implementation, you need an IIOP stub so that your RMI client can invoke on the CORBA object over IIOP.

■■If you have a CORBA client with an RMI object implementation, you need an IIOP skeleton so that your RMI object implementation can receive invocations from the CORBA client over IIOP.

■■If you have an RMI client with an RMI object implementation and you want to use the IIOP protocol rather than JRMP, you need both IIOP stubs and skeletons. This allows you to take advantage of the robustness of the IIOP protocol with straight RMI programs.

Once you’ve done these steps, you’ve got all the files you need for an RMI client to invoke on a CORBA object implementation.

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

328 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

language to which IDL maps. You then use an IDL-to-Java compiler to take in your IDL and produce network management code in the language in which you’re implementing your objects. For example, if you use Java, you’ll need an IDL-to-Java compiler. There’s a free IDL-to-Java compiler called idlj that ships with RMI-IIOP. There are docs about idlj that come with RMI-IIOP, as well as a complete specification on the OMG Web site. Most major ORB vendors that support Java include an IDL-to-Java tool with their products as well.

5.Write the client and the server. You can now write your RMI client and your CORBA object implementations.

CORBA Client with an RMI-IIOP Object Implementation

The second scenario depicts a CORBA client with an RMI-over-IIOP object implementation. You’re going to need an RMI remote interface again for your RMI remote objects. You’re also going to need OMG IDL so that the CORBA client can invoke on your RMI remote objects. Again, you’d like to avoid writing OMG IDL explicitly because RMI is about simple network programming.

To accomplish this, you perform the following steps:

1.Write your RMI remote interface. You write the remote interface in Java as you normally would for any RMI program. The remote interface is RMI’s client/server contract for distributed objects.

2.Generate the needed server-side RMI over IIOP skeletons. The skeletons will be used to receive invocations and delegate them to your RMI remote object implementations. You generate the skeletons via rmic, as explained in the previous section.

3.Generate the OMG IDL. When you define your CORBA clients, you’re going to need IDL. This IDL must match your RMI remote interface if you want CORBA clients to call your RMI object implementations. Rather than laboriously writing it yourself, you can automatically generate it through a Java-to-IDL compiler. The Java-to-IDL compiler takes in your RMI remote interface and spits out OMG IDL, as described in the previous section.

4.Generate the needed client-side CORBA files. As in the previous section, you need to generate helper code, such as stubs for your CORBA clients. Thus, you need to generate these network plumbing classes from the IDL with an IDL compiler, such as an IDL-to-Java compiler (as described in the previous section).

5.Write the client and the server. You can now write your CORBA client and your RMI object implementations.

Now you’ve seen both scenarios—an RMI client with a CORBA object implementation, and a CORBA client with an RMI object implementation. If you define your

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

CORBA and RMI-IIOP 329

Table 11.1 Combinations Possible Using RMI-IIOP

CLIENT

SERVER

RMI client with RMI-IIOP stub

RMI server with RMI-IIOP skeleton

RMI client with RMI-IIOP stub

CORBA object implementation

CORBA client

RMI server with RMI-IIOP skeleton

CORBA client

CORBA object implementation

 

 

interfaces the same way in each scenario, you should be able to mix and match RMI clients, RMI object implementations, CORBA clients, and CORBA object implementations. Table 11.1 shows the RMI-IIOP combinations that are possible.

The RMI-IIOP API

We’ve looked at the big picture of RMI-IIOP. But how does RMI programming itself change? After all, there’s no more distributed garbage collection with RMIIIOP. In this section, we’ll take a look at what changes for you, as an RMI programmer.

Choosing an ORB

As we’ve discussed, RMI-IIOP clients must have a local ORB to talk to, which knows how to communicate with other ORBs via IIOP. RMI-IIOP servers must have a local ORB for the same reason.

For RMI over IIOP to work, the ORB vendor you’re using must do the followiing:

■■Implement the Java-to-IDL mapping specification

■■Implement the CORBA Objects-by-Value specification

Sun Microsystems has written its own CORBA ORB, called Java IDL, which is a free reference implementation of CORBA. Java IDL is currently the only ORB that can be used with RMI-IIOP because it implements both specifications listed above.

Note that Java IDL does not provide the full range of features defined by CORBA. For example, Java IDL does not define an Interface Repository. This means runtime checking of parameters when performing dynamic invocations is impossible.

Java IDL ships as part of Java 2 (formerly JDK 1.2). See the book’s accompanying Web site for links to resources on this product.

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