Advanced Java Services |
IIOP ist ein von der Object Management Group (OMG) eingeführtes Protokoll, das es ermöglicht,
daß Applikationen, die in veschiedenen Sprachen geschrieben sind, miteinander kommunizieren können.
IIOP steht für I-nternet I-nter O-RB P-rotocol. Dieses Protokoll ist Bestandteil von CORBA (Common
Object Request Broker Architecture). Diese Architektur, die ebenfalls von OMG eingeführt wurde, stellt
Konzepte und Regeln bereit, mit denen der Datenaustausch zwischen Objekten transparent und
sprachenunabhängig ablaufen kann.
Wir werden unseren Datumsserver nun entsprechend umgestalten und den Datenaustasuch mit IIOP
bewerkstelligen. IIOP ist nicht nur das Standardprotokoll mit dem CORBA-Applikationen kommunizieren
sondern wird auch von Enterprise JavaBeans (EJB) verwendet. Wir werden sehen, daß RMI über IIOP
fast genauso abläuft wie unser voriges Beispiel
Zu einem RemoteObjekt soll wieder clientseitig eine Methode getDate() aufgerufen werden, die das aktuelle Datum auf dem Server liefert. Für unser Beispiel verwenden wir wieder die gleiche IP-Adresse für den Server.
Server IP-Adresse: 192.168.11.22
Das RemoteInterface muß die gleichen Bedingungen erfüllen wie in den beiden vorigen Fällen.
Hier der Code.
import java.util.Date; import java.rmi.Remote; import java.rmi.RemoteException; public interface DateRemoteInterface extends Remote { Date getDate() throws RemoteException ; }
Wie im vorigen Fall erbt die Implementierung von der Klasse PortableRemoteObject. Es gibt hier jedoch keine Alternative, denn nur PortableRemoteObject unterstützt IIOP, UnicastRemoteObject dagegen nicht.
Für die Implementierung des RemoteInterfaces gelten folgende Bedingungen:
Codiert sieht das wie folgt aus.
import java.util.*; import java.rmi.RemoteException; import javax.rmi.PortableRemoteObject ; public class DateRemoteInterfaceImpl extends PortableRemoteObject implements DateRemoteInterface { public DateRemoteInterfaceImpl() throws RemoteException { super(); } // vom DateRemoteInterface geforderte Methode public Date getDate() throws RemoteException { return new Date(); } }
Die Verknüpfung zwischen Objekt und Namen, die der Server vornehmen muß, verläuft analog zum letzten Beispiel. Zuständig dafür ist wieder die Klasse javax.naming.InitialContext. Der Konstruktor von InitialContext erhält ein PropertiesObjekt, in dem man die Umgebung angibt, mit der InitialContext arbeiten soll. Mit dem PropertiesObjekt beschreibt man die Klasse, die für die Namensverknüpfung zuständig ist, hier com.sun.jndi.cosnaming.CNCtxFactory und die URL-Adresse des Servers. 1050 ist ein möglicher Port für IIOP. Die folgende Application startet als erstes die seit 1.4 existierende Konsolanwendung orbd. Das mit orbd -ORBInitialPort 1050 gestartete Tool befindet sich im $JavaHome/bin-Verzeichnis. orbd steht für O-bject R-equest B-roker D-aemon. Eine kurze Beschreibung von orbd findet sich im nächsten Absatz.
Unser IIOP-Server im Code.
import java.util.Properties; import javax.naming.Context; import java.rmi.RemoteException; import javax.naming.InitialContext; import javax.naming.NamingException; public class RMI_IIOP_DateServer { // setting up the server public static void main(String args[]) { try { // starting the Object Request Broker Daemon (ORBD) // legt das Verzeichnis orb.db in dem Verzeichnis an, in dem diese compilierte Javadatei liegt Runtime.getRuntime().exec("orbd -ORBInitialPort 1050") ; DateRemoteInterfaceImpl dateRef = new DateRemoteInterfaceImpl(); // wirft java.rmi.RemoteException Properties env = new Properties(); env.put("java.naming.factory.initial", "com.sun.jndi.cosnaming.CNCtxFactory"); env.put("java.naming.provider.url", "iiop://localhost:1050"); // JNDI naming Context initialNamingContext = new InitialContext(env); // NamingException initialNamingContext.rebind("DateService", dateRef); // NamingException System.out.println("date server ready, waiting for clients"); } catch(Exception ex) { System.out.println("Exception : " +ex); ex.printStackTrace(); } } }
orbd ist ein Tool, das einen Hintergrundprozess startet. orbd muß mit dem Parameter -ORBInitialPort <nameserverport> gestartet werden und initialisiert beim Starten zusätzlich einen Namensdienst (Naming Service). Auf dem angegeben Port wartet orbd auf Clientanfragen. Kommt eine Anfrage, so gibt es den ankommenden Namen weiter an einen Namensdienst. Der Namensdienst sucht dann das zum Namen gehörende Objekt. Es gibt keine absoluten Namen. Jeder Name gehört zu einem bestimmten Kontext. Wir haben diesen Kontext mit dem Statement env.put("java.naming.factory.initial", "com.sun.jndi.cosnaming.CNCtxFactory"); angegeben. cosnaming steht dabei für C-ommon O-bject S-ervices Naming. Mit der Zeile initialNamingContext.rebind("DateService", dateRef); vergeben wir dann für das Objekt dateRef den eindeutigen Namen DateService. Wir verwenden rebind statt bind. Damit werden evtl. vorhandene alte Namensbindungen überschrieben, die bei bind sonst zu einer NamingException führen würden.
Wie im vorigen Beispiel muß die Clientklasse mit einem Objekt der Klasse InitialContext arbeiten. Der Konstruktor von InitialContext erhält ein PropertiesObjekt, in dem man die Umgebung angibt, mit der InitialContext arbeiten soll. Mit dem PropertiesObjekt beschreibt man die Klasse, die für die Namensverknüpfung zuständig ist (com.sun.jndi.cosnaming.CNCtxFactory) und die URL-Adresse des Servers.
Der Code der Clientklasse.
import java.util.*;
import javax.naming.Context;
import java.rmi.RemoteException;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;
public class IIOP_DateClient
{
public static void main(String[] args)
{
try
{
int port = 1050 ;
String url = "iiop://192.168.11.22:"+port ;
String jndiName = "DateService";
Properties env = new Properties();
env.put("java.naming.factory.initial", "com.sun.jndi.cosnaming.CNCtxFactory");
env.put("java.naming.provider.url", url);
Context initial = new InitialContext(env); // NamingException
Object ref = initial.lookup(jndiName); // NamingException
DateRemoteInterface remRef =
(DateRemoteInterface)PortableRemoteObject.narrow(remRef, DateRemoteInterface.class);
// Client erhält Objekt einer Klasse, die das DateRemoteInterface implementiert hat
}
catch(Exception ex)
{
System.out.println(ex);
ex.printStackTrace();
}
}
}
Das Hilfstool rmic muß uns nun noch zwei Hilfsklassen erzeugen. Das ist einmal die Klasse _DateRemoteInterface_Stub.class, die auf beiden Seiten gebraucht wird und die wir schon kennen. Serverseitig wird diesmal noch eine weitere Klasse gebraucht, die Klasse _DateRemoteInterfaceImpl_Tie.class . Damit rmic IIOP-konform arbeitet gibt man beim Aufruf eben dieses Protokoll als Schalter an.
rmic -iiop DateRemoteInterfaceImpl
rmic vergibt die Namen für diese Klassen wieder automatisch. Die Art der Namensgebung unterscheidet sich jedoch jetzt von den vorigen Beispielen. Für den Namen der Stubklasse wird der Name des RemoteInterfaces herangezogen, für die Tieklasse der Name der Implementierung des RemoteInterfaces.
Name des RemoteInterfaces | Name der Stubklasse |
---|---|
Xxx | _Xxx_Stub |
Name der Implementierung des RemoteInterfaces | Name der Tieklasse |
Yyy | _Yyy_Tie |
Wenn wir nun _DateRemoteInterface_Stub.class sowohl beim Server als auch beim Client deponieren, und dazu noch _DateRemoteInterfaceImpl_Tie.class beim Server, dann sollte das Beispiel laufen.