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

Professional Java.JDK.5.Edition (Wrox)

.pdf
Скачиваний:
31
Добавлен:
29.02.2016
Размер:
12.07 Mб
Скачать

Chapter 11

Though there has been industry criticism for the age of the JDK’s support for CORBA, 2.3.1 includes many of CORBA’s modern features, and is certainly enough to implement and use most CORBA distributed objects. There are many implementations of CORBA that can be used with Java besides the implementation that comes with the JDK. A list of free CORBA downloads (either trials of commercial implementations or free open-source implementations) can be found on OMG’s Web site at the following URL:

http://www.omg.org/technology/corba/corbadownloads.htm

CORBA is a massive set of specifications and has been an immense undertaking. CORBA has a history of having slow, bloated, and buggy implementations — on top of being extremely complex and difficult to develop with. Today though, as CORBA is a stable and mature technology, its implementations are much faster and reliable, and it is used in many mission-critical environments. CORBA is still complex and not as developer friendly as technologies such as RMI though, and usually for newer systems, J2EE-based servers are the best design choice if the Java platform is the primary development environment. This chapter will briefly examine CORBA, though not in any depth worthy of its complexity.

CORBA Basics

There are four main concepts of the CORBA specification that define how distributed objects written in different languages communicate with one another. Like RMI, there is a naming service, where remote object references can be registered, to be retrieved at some point in time by one or more clients. The Internet InterORB Protocol (IIOP) is used for the communication between clients and servers. This is the protocol that is responsible for defining the format of the marshalling and unmarshalling of remote method invocations and parameter passing. Object Request Brokers (ORBs) are responsible for processing all remote method calls and dispatching them to the appropriate object, both on the client and server. Figure 11-10 demonstrates these CORBA concepts.

The paradigm for object-to-object communication is similar to RMI:

1.Remote object references are obtained using the COS Naming Service.

2.Method call information and parameters are marshalled into a byte stream to send over the network via the Internet InterORB Protocol (IIOP).

3.An Object Request Broker (ORB) receives incoming requests on the remote server, and dispatches them to the object implementing the CORBA interface called.

506

Communicating between Java Components and Components of Other Platforms

Distributed

Object

COS Naming

Service

Distributed

Object

ORB

1. Naming Lookup

3. ORB dispatches request, remote object returns result

Client Application

2. Remote Method Calls sent to ORB over IIOP

Figure 11-10

IDL: Interface Definition Language

The Interface Definition Language (IDL) is a CORBA specification for writing an interface. In CORBA, all distributed objects must implement a CORBA interface. These interfaces are similar to Java’s concept of an interface — an interface allows for multiple implementations. CORBA interfaces though, can be implemented by any language that supports CORBA. Figure 11-11 shows a class diagram of a CORBA being implemented both in Java and C#.

Java Class

«interface»

C# Class

 

 

 

IDL Interface

 

Figure 11-11

 

 

507

Chapter 11

Three things can be declared in CORBA interfaces:

Operations (like Java methods)

Attributes (like JavaBean properties, implemented by getXXX and setXXX methods)

Exceptions

A CORBA interface for each distributed object allows IDL compilers to compile IDL to stub classes in an existing language. For instance, the JDK provides tools that map CORBA IDL types to Java types, and generate stub classes for any given IDL file. These stub classes allow Java programmers to see the CORBA object as a Java class, and call its methods with Java syntax just like any other Java class. IDL is the link between different languages — it provides the description of an interface that can be transformed into the corresponding class in a concrete programming language.

When using remote CORBA objects, the client programmer is using the interface, not the specific object implementing it. The ORB running on the remote machine resolves the request, and dispatches it to the correct implementation. The client never knows which language the remote object was written in, it is all transparent.

In the “Distributed Filesystem Notifications: An Example CORBA System” section that follows at the end of this CORBA section, a CORBA interface called FileNotification will be defined. Seeing the Java representation will help you understand the CORBA representation. Here is the Java representation of that interface:

package book;

public interface FileNotification

{

public void fileModified (String fileName); public void fileDeleted (String fileName); public void fileCreated (String fileName);

}

The equivalent definition of this Java interface in IDL looks like this:

#include “orb.idl”

#ifndef __book_FileNotification__ #define __book_FileNotification__

module book {

interface FileNotification {

void fileModified(

in ::CORBA::WStringValue fileName ); void fileDeleted(

in ::CORBA::WStringValue fileName ); void fileCreated(

in ::CORBA::WStringValue fileName );

508

Communicating between Java Components and Components of Other Platforms

};

#pragma ID FileNotification “RMI:book.FileNotification:0000000000000000”

};

#endif

If you have developed with C++ before, you will notice that the IDL syntax is similar to the C++ syntax, since C++ was the dominant language at the time of CORBA’s inception. This chapter will not go heavily into the IDL syntax, as that is better left to books dedicated solely to CORBA. The main concept of IDL is simple: Separate the interface from the implementation. This principle applies to good software design in general, but is absolutely essential when an implementation could be written in more than one language. There would be no other way to have two disparate languages communicate with one another if not for a common interface.

ORB: Object Request Broker

The Object Request Broker is responsible for mediating incoming CORBA method invocations. ORBs are the core infrastructure of any CORBA implementation. They provide a common entry point for all CORBA requests to any given server. Many different method invocations on a number of CORBA objects go through the same entry point, the ORB. The ORB then dispatches the request to the correct CORBA object instance corresponding to the client’s reference.

Common Object Service (COS) Naming

The Common Object Service (COS) Naming provides a registry to hold references to CORBA objects. It is similar in concept to the RMI registry. When a server wants to expose CORBA object instances to remote clients, it registers each instance with the naming service. Each instance gets a unique name on the server. Clients use the name to retrieve the reference and call its methods.

JNDI provides an InitialContext that can interact with COS Naming and look up various CORBA objects in the same fashion as one would look up an RMI object. As long as the correct stubs for IIOP are in place, setting the following system properties (which is the URL containing the correct hostname and port for the remote COS Naming service), client Java programs can access CORBA objects transparently:

java.naming.factory.initial=com.sun.jndi.cosnaming.CNCtxFactory

java.naming.provider.url=iiop://hostname:1049

Once these properties are set (using the -D option at the command line is one way to set them), the JNDI lookup occurs normally.

Note: Client programs can also use the org.omg.CORBA package to manually access CORBA references, and have all of the many intricacies of CORBA at their disposal.

IIOP: Internet InterORB Protocol

The Internet InterORB Protocol is the protocol that CORBA ORBs use to communicate with one another over a network. All method calls and parameters are marshalled and unmarshalled over this protocol. It is an efficient binary protocol. JDK 1.5 supports version 2.3.1 of the IIOP specification.

509

Chapter 11

RMI-IIOP: Making RMI Compatible with CORBA

RMI-IIOP combines some of the best aspects of RMI with the language independence of CORBA. RMI is far simpler for developers to use than CORBA. The main limitation of RMI is that it only supports the Java language. Though Java is platform independent, sometimes there are legacy components or systems written in other languages that must be interacted with. CORBA provides that channel of communication but can be a painful experience for developers. RMI-IIOP is Java RMI, but uses the IIOP protocol for communication, meaning normal RMI objects can be exposed as CORBA objects to external systems. By the same token, external CORBA objects can be accessed through the RMI APIs, again because of the use of IIOP as the underlying communication protocol.

It would be a perfect world if RMI-IIOP had exactly the same feature set as RMI over JRMP. IIOP was not designed for Java though. Objects passed by value over IIOP (ones that implement java.io

.Serializable instead of java.rmi.Remote — see “Marshalling and Unmarshalling” in the RMI section of this chapter) get passed in the byte stream as Java objects. This means that any parameters passed by value over RMI-IIOP can only be read by Java clients! Fortunately, CORBA has a mechanism to deal with value types. It does, however, mean that the same interface of the value type must be

implemented by the client. For example, suppose a Java RMI object returns a value type of java.util

.ArrayList. A CORBA client cannot read this value type. The CORBA client application then must implement the interface for ArrayList (and make it compatible with the binary representation passed in!). Because of this large extra burden placed by objects passed by value on CORBA systems being communicated with using RMI-IIOP, it generally makes sense to try to make the interfaces pass only primitive types or objects by reference.

CORBA IDL unfortunately does not support method overloading. This, combined with the non-use of value types in passing parameters, can be a burden to designing a distributed system using RMI-IIOP. One design approach is to start thinking from the limiting IDL perspective when you are creating your Java interface for your remote object (if the system must communicate with CORBA clients). Your code may not be as clean using only primitive types, but the ease of interoperability makes it by far worth the price. The client-side development is tremendously simplified when value types do not have to be implemented also. Doing so is essentially implementing an object twice, once in Java and once in the CORBA client’s language, and is asking for buggy and incompatible implementations, not to mention the synchronization nightmare of keeping their functionality and IDL up to date.

In most situations though, RMI-IIOP makes CORBA programming far simpler, and is the preferred method of integrating with CORBA in Java if the advanced features of CORBA are not necessary. The programming model is the same as RMI, and allows the Java developer to easily integrate with other platforms.

How to Turn an RMI Object into an RMI-IIOP Object

To take an existing RMI object and expose it via RMI-IIOP requires a minimal amount of work. Suppose you have a simple RMI HelloWorld interface:

package simple.rmi;

import java.rmi.Remote;

import java.rmi.RemoteException;

public interface HelloWorld extends Remote { public void hello() throws RemoteException;

}

510

Communicating between Java Components and Components of Other Platforms

Normal RMI object implementations extend java.rmi.UnicastRemoteObject. Your simple HelloWorldImpl as a normal RMI object looks like this:

package simple.rmi;

import java.rmi.RemoteException;

import java.rmi.server.UnicastRemoteObject;

public class HelloWorldImpl extends UnicastRemoteObject implements HelloWorld {

public HelloWorldImpl() throws RemoteException { super();

}

public void hello() throws RemoteException { System.out.println(“Hello”);

}

}

Note that UnicastRemoteObject above is in context.

To allow this object to be used over RMI-IIOP, the first step is to make the class extend javax.rmi. PortableRemoteObject instead of java.rmi.UnicastRemoteObject:

package simple.rmi;

import java.rmi.RemoteException;

import javax.rmi.PortableRemoteObject;

public class HelloWorldImpl extends PortableRemoteObject implements HelloWorld {

public HelloWorldImpl() throws RemoteException { super();

}

public void hello() throws RemoteException { System.out.println(“Hello”);

}

}

Now HelloWorldImpl is ready to be used over RMI-IIOP. The last step is to generate the IDL and IIOP stubs from your class. The IIOP stubs allow the object to be sent over the wire using IIOP. The IDL allows CORBA clients to generate the stubs necessary to use the class. To generate both the stubs and the IDL, use the rmic tool from the JDK (in the bin directory under the JDK home). Running rmic from the command line, make sure that simple.rmi.HelloWorldImpl is on the classpath:

rmic -iiop -idl simple.rmi.HelloWorldImpl

511

Chapter 11

The last step is to write the main program that actually starts up the RMI-IIOP server. This book

will talk more about communicating with the Java ORB daemon included with the JDK, orbd, in the “Distributed Filesystem Notifications: An Example CORBA System” section, including registering objects and communicating with remote CORBA ORBs.

When to Use CORBA

CORBA is a difficult platform to develop software. It is robust and successful in mission-critical software systems, but the learning curve is high and development costs can rise. CORBA is best used in distributed systems that must have components written in more than one language, or have the potential to be written in more than one language. J2EE is a more ubiquitous standard for server-side applications today. It also provides CORBA support for some of its components. If you are creating a new server-side application in Java, sticking with J2EE is most certainly your best choice. CORBA support can always be added on later should you need to support clients written in other languages. Here are a couple of good instances of where to add CORBA to your distributed system:

When you have to integrate with legacy systems that support CORBA in your middleware

When there are components written in other languages just not available in Java that are essential to your server-side application (and would require less effort to build a CORBA link than to rewrite the component in Java)

CORBA as a distributed technology is simply not used as much in industry practice as J2EE-based component technologies (or COM/COM+/DCOM). It is a solid platform since it has been around for about ten years. Most of the complaints CORBA developers had originally have been rectified. CORBA implementations are fast and efficient now, and more than robust enough to use in mission-critical applications. CORBA has a steep learning curve, and the only value it adds over J2EE component technology is the ability to write components in different languages than Java. If your system is all Java, it just does not make sense to use CORBA — especially since J2EE can expose Java components to CORBA systems already through RMI-IIOP. It is best to use CORBA when you must integrate with a system that supports it.

CORBA may be a good technology to use when integrating with the Microsoft .NET platform. There has recently been an open source project, IIOP.NET, that integrates .NET Remoting (.NET’s equivalent to RMI) with IIOP. This product is becoming mature, and allows for easy integration between RMI-IIOP and .NET Remoting. This is a big step towards an easier integration between .NET and Java components. The IIOP.NET project can be found at the following URL:

http://iiop-net.sourceforge.net/

IIOP.NET provides an exciting new way to use CORBA. By integrating with .NET Remoting, it allows programmers in the .NET environment and the Java environment to use their remote objects seamlessly (with normal IIOP limitations, of course, with value types, and so on). You have already seen how you can expose a Java component to CORBA using RMI-IIOP; the process is quick and easy, and better yet, can be automated. The process on the .NET side is the same way. CORBA can be used in this manner to allow .NET and Java components to interact transparently. The following example will examine such a system. A .NET component is wrapped with a CORBA interface and components in Java can access it like a normal Java component via RMI-IIOP.

512

Communicating between Java Components and Components of Other Platforms

Distributed File System Notifications:

An Example CORBA System

Java does not contain any classes in the JDK to monitor for file system events. File system events occur when a file is deleted, modified, created, or renamed. These operations are platform specific and work different depending not only on the file system type, but on the host operating system. The only pure Java way to achieve this effect is to run a program that polls the file system and looks for updates — hardly an efficient mechanism of monitoring the file system. It would be far better if you could hook into the operating system and whenever a file system event occurred, be notified. Try to find a component that meets these needs and then provide a CORBA wrapper to access the component from your Java application.

Fortunately, one of the components of the .NET framework fits your needs. The FileSystemWatcher class from the System.IO namespace hooks into the Windows operating system, and notifies the user of file system events. Since your application is written in Java, you need somehow to integrate this nonJava component into your application. CORBA is a fine choice in this case, especially because of the advent of IIOP.NET, which was discussed in the proceeding section. IIOP.NET allows .NET Remoting to run over IIOP, which basically means you can access .NET remote objects from Java’s RMI-IIOP. For this example, you will wrap the FileSystemWatcher class in a .NET remote object, expose this object through CORBA, and then implement the Java client. This text will not go into any code details for the

.NET side, since this is a Java book and not a C# book. However, the code for the .NET side can be downloaded from this book’s Web site at www.wrox.com. Figure 11-12 is a high-level diagram of the architecture for the communication between .NET and Java.

«interface»

FileNotification

Java Implementation

+fileCreated(in fileName : string) +fileModified(in fileName : string) +fileDeleted(in fileName : string)

System.IO.FileSystemWatcher

1

1

FileSystemWatcher C# Wrapper

«interface»

RemoteFileSystemWatcher

+registerNotification(in fileNotification : FileNotification) +removeNotification() : FileNotification

Figure 11-12

513

Chapter 11

You have the IDL for the remote .NET components. The CORBA object that wraps the .NET component, FileSystemWatcher, has the following IDL:

#include “orb.idl” #include “Predef.idl”

#include “FileNotification.idl”

#ifndef __ConsoleCorbaServer_RemoteFileSystemWatcher__ #define __ConsoleCorbaServer_RemoteFileSystemWatcher__ module ConsoleCorbaServer {

interface RemoteFileSystemWatcher {

void registerNotfication(in ::book::FileNotification notification) raises (::Ch::Elca::Iiop::GenericUserException);

void removeNotification(in ::book::FileNotification notification) raises (::Ch::Elca::Iiop::GenericUserException);

void setDirectory(in ::CORBA::WStringValue path) raises (::Ch::Elca::Iiop::GenericUserException);

};

#pragma ID RemoteFileSystemWatcher “IDL:ConsoleCorbaServer/RemoteFileSystemWatcher:1.0”

};

#endif

You can run idlj, the Java IDL compiler, to generate stub classes that will proxy your requests to these methods to the CORBA ORB running on the.NET platform’s host machine. Notice how the IDL generated includes other IDL files, namely, orb.idl, predef.idl, and FileNotification.idl. These other files must be in the same directory when you run idlj for the compilation to work properly. The file orb.idl is the Java mapping definitions from IDL to Java specific types. The IIOP.NET provides predef.idl for some types specific to its .NET to CORBA mappings. The Java IDL compiler is included in JDK 5.0. Running the idlj compiler is simple:

idlj RemoteFileSystemWatcher.idl

By running idlj on the IDL, the following files were generated:

RemoteFileSystemWatcherStub.java

RemoteFileSystemWatcher.java

RemoteFileSystemWatcherHelper.java

RemoteFileSystemWatcherHolder.java

RemoteFileSystemWatcherOperations.java

GenericUserException.java

GenericUserExceptionHolder.java

GenericUserExceptionHelper.java

These are the stub and interfaces necessary to use the remote CORBA object, RemoteFileSystemWatcher (which wraps the .NET component, FileSystemWatcher). Note that since the IDL contained exceptions, exception classes were also generated. The RemoteFileSystemWatcherOperations.java defines the interface methods available to you:

514

Communicating between Java Components and Components of Other Platforms

package ConsoleCorbaServer;

/**

*ConsoleCorbaServer/RemoteFileSystemWatcherOperations.java .

*Generated by the IDL-to-Java compiler (portable), version “3.1”

*from RemoteFileSystemWatcher.idl

*Friday, June 11, 2004 5:56:29 PM EDT

*/

public interface RemoteFileSystemWatcherOperations

{

void registerNotfication (book.FileNotification notification) throws Ch.Elca.Iiop.GenericUserException;

void removeNotification (book.FileNotification notification) throws Ch.Elca.Iiop.GenericUserException;

void setDirectory (String path) throws Ch.Elca.Iiop.GenericUserException; } // interface RemoteFileSystemWatcherOperations

Notice how registerNotification() and removeNotification() have a book.FileNotification object as their parameter. FileNotification is the callback interface defined by RemoteFileSystemWatcher. FileNotification is defined in FileNotification.idl. You will have to generate Java stubs for this CORBA object as well. The difference, though, is that you will have to provide an implementation of FileNotification if you want to receive these filesystem events. By providing an implementation of FileNotification, you will be able to pass to the remote CORBA ORB a local instance which can receive events from the remote server. To implement FileNotification, you must run idlj with a different parameter, one to generate both the client stubs and the server stubs necessary for you to provide your own implementation. Here is the IDL for FileNotification:

#include “orb.idl”

#ifndef __book_FileNotification__ #define __book_FileNotification__

module book {

interface FileNotification {

void fileModified(

in ::CORBA::WStringValue fileName );

void fileDeleted(

in ::CORBA::WStringValue fileName ); void fileCreated(

in ::CORBA::WStringValue fileName );

};

#pragma ID FileNotification “RMI:book.FileNotification:0000000000000000”

};

#endif

515

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]