Advanced   Java   Services RMI  mit PortableRemoteObject Back Next Up Home


RMI mit PortableRemoteObject

An Stelle der Klasse java.rmi.server.UnicastRemoteObject kann für RMI auch die neuere Klasse javax.rmi.PortableRemoteObject verwendet werden. Das RemoteInterface bleibt das gleiche wie vorhin.





Ausgangssituation

Zu einem RemoteObjekt soll clientseitig eine Methode getDate() aufgerufen werden, die das aktuelle Datum auf dem Server liefert. Für unser Beispiel brauchen wir eine IP-Adresse für den Server, wir nehmen die folgende.

Server IP-Adresse:  192.168.11.22

RemoteInterface (KommunikationsInterface für Server und Client)

Das RemoteInterface muß die gleichen Bedingungen erfüllen wie im vorigen Fall.

Wir verwenden dasselbe Interface.

import java.util.Date;
import java.rmi.Remote;
import java.rmi.RemoteException;

public interface DateRemoteInterface extends Remote
{
   Date getDate() throws RemoteException ;
}

Die Implementierung erbt jedoch jetzt von der Klasse PortableRemoteObject.


Implementierung des RemoteInterfaces (nur serverseitig)

Für die Implementierung des RemoteInterfaces gelten etwas andere Bedingungen:

Hier unsere Implementierung.

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 Serverklasse

Hier verläuft jetzt die Verknüpfung zwischen Objekt und Namen, die der Server vornehmen muß, auf eine etwas andere Weise. Zuständig dafür ist nun 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 (RegistryContextFactory) und die URL-Adresse des Servers.

Codiert sieht das wie folgt aus.

import java.util.Properties;
import javax.naming.Context;
import java.rmi.RemoteException;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.rmi.registry.LocateRegistry;

public class RMIDateServer
{
   // setting up the server
   public static void main(String args[])
   {
      try
      {
         DateRemoteInterfaceImpl dateObj = new DateRemoteInterfaceImpl();
         // wirft RemoteException
         // rmiregistry starten
         int port = 1099 ;
         LocateRegistry.createRegistry(port);
         // Creates and exports a Registry on the local host that accepts
         //  requests on the specified port (wirft java.rmi.RemoteException)
         
         Properties env = new Properties();
         env.put("java.naming.factory.initial", "com.sun.jndi.rmi.registry.RegistryContextFactory");
         env.put("java.naming.provider.url", "rmi://localhost:"+port);
         // für den Defaultport 1099 ist die letzte Zeile nicht notwendig

         // JNDI naming
         Context initialNamingContext = new InitialContext(env);
         // wirft NamingException
         initialNamingContext.bind("DateService", dateObj);
         // wirft NamingException
      }
      catch(Exception ex)
      {
         System.out.println("Exception happened:");
         ex.printStackTrace();
      }
   }
}

Naming Service

Mit dem Statement LocateRegistry.createRegistry(port); wird ein Server gestartet, der auf dem angegebenen Port auf Clientanfragen wartet. Diese Anfragen fragen nach einem bestimmten Namen (bei uns "DateService"). Der Server gibt deshalb die Anfragen weiter an einen Namensdienst (Naming Service) oder Anfragevermittler (Request Broker). Der Namensdienst, der mit Registry zusammenarbeiten kann heißt RegistryContextFactory. Wir geben ihn mit dem Statement
env.put("java.naming.factory.initial", "com.sun.jndi.rmi.registry.RegistryContextFactory"); an. Nach Angabe eines Namensdienstes kann man dann einen Namen an ein Objekt binden: initialNamingContext.bind("DateService", dateObj);


Die Clientklasse

Auch die Clientklasse muß jetzt 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 (RegistryContextFactory) und die URL-Adresse des Servers.

Und im Code.

import java.util.*;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.rmi.RemoteException;
import javax.rmi.PortableRemoteObject;

public class RMIDateClient
{
   public static void main(String[] args)
   {
      try
      {
         int port = 1099 ;
         String url = "rmi://192.168.11.22:"+port ;
         String jndiName = "DateServer";
         Properties env = new Properties();
         env.put("java.naming.factory.initial", "com.sun.jndi.rmi.registry.RegistryContextFactory");
         env.put("java.naming.provider.url", url);
         Context initial = new InitialContext(env);   // NamingException
         Object ref = initial.lookup(jndiName);    // NamingException

         DateRemoteInterface remRef =
            (DateRemoteInterface)PortableRemoteObject.narrow(ref, DateRemoteInterface.class);
         // Client erhält Objekt einer Klasse, die das DateRemoteInterface implementiert hat

         System.out.println("Datum auf dem Server: " + remRef.getDate() );

      }
      catch(Exception ex)
      {
         System.out.println("Exception happened:");
         ex.printStackTrace();
      }
   }
}

Die Stubklasse (serverseitig und clientseitig)

Wie im vorigen Beispiel müssen wir noch die Stubklasse erzeugen. Der Aufruf von rmic ist derselbe.

rmic DateRemoteInterfaceImpl

Der Name der Stubklasse (und der Skeletonklasse)

rmic erzeugt bei diesem Aufruf natürlich den Namen der Stubklasse nach dem gleichen Schema.

Name der implementierenden KlasseName der Stubklasse
XxxImplXxxImpl_Stub

Wenn wir nun DateRemoteInterfaceImpl_Stub sowohl beim Server als auch beim Client deponieren, dann sollte das Beispiel laufen.

top Back Next Up Home