Galileo Computing < openbook >
Galileo Computing - Professionelle Buecher. Auch fuer Einsteiger.
Galileo Computing - Professionelle Buecher. Auch fuer Einsteiger.


Java ist auch eine Insel von Christian Ullenboom
Buch: Java ist auch eine Insel (Galileo Computing)
gp Kapitel 18 Verteilte Programmierung mit RMI und SOAP
gp 18.1 Entfernte Methoden
gp 18.1.1 Wie entfernte Methoden arbeiten
gp 18.1.2 Stellvertreter (Proxy)
gp 18.1.3 RMI
gp 18.1.4 Wie die Stellvertreter die Daten übertragen
gp 18.1.5 Probleme mit entfernten Methoden
gp 18.2 Nutzen von RMI bei Middleware-Lösungen
gp 18.3 Die Lösung für Java ist RMI
gp 18.3.1 Entfernte Objekte programmieren
gp 18.3.2 Entfernte und lokale Objekte im Vergleich
gp 18.4 Definition einer entfernten Schnittstelle
gp 18.5 Das entfernte Objekt
gp 18.5.1 Der Bauplan für entfernte Objekte
gp 18.5.2 Der Konstruktor
gp 18.5.3 Implementierung der entfernten Methoden
gp 18.6 Stellvertreterobjekte erzeugen
gp 18.6.1 Das Dienstprogramm rmic
gp 18.7 Der Namensdienst (Registry)
gp 18.7.1 Der Port
gp 18.8 Der Server: entfernte Objekte beim Namensdienst anmelden
gp 18.8.1 Automatisches Anmelden bei Bedarf
gp 18.9 Einen Client programmieren
gp 18.9.1 Einfaches Logging
gp 18.10 Aufräumen mit dem DGC
gp 18.11 Entfernte Objekte übergeben und laden
gp 18.11.1 Klassen vom RMI-Klassenlader nachladen
gp 18.11.2 Sicherheitsmanager
gp 18.12 Registry wird vom Server gestartet
gp 18.13 RMI über die Firewall
gp 18.13.1 RMI über HTTP getunnelt
gp 18.14 RMI und CORBA
gp 18.15 UnicastRemoteObject, RemoteServer und RemoteObject
gp 18.16 Daily Soap
gp 18.16.1 SOAP-Implementierung der Apache-Gruppe
gp 18.16.2 Einen Client mit der Apache-Bibliothek implementieren
gp 18.16.3 Der Seifen-Server
gp 18.17 Java-API für XML Messaging (JAXM)
gp 18.18 Java Message Service (JMS)
gp 18.18.1 OpenJMS
gp 18.18.2 Beispiel mit Konsument und Produzent im Publish-Subscribe-Modell


Galileo Computing

18.5 Das entfernte Objektdowntop

Die Methoden des Servers werden letztendlich vom Client über die Stellvertreter genutzt. Der Server muss unterschiedliche Vorgaben erfüllen: Er muss eine spezielle Klasse erweitern, einen Konstruktor anbieten und die entfernte Schnittstelle implementieren. Dann kann ein Server-Objekt angemeldet werden. Das Server-Objekt implementiert daher die Geschäftslogik und sieht wie folgt aus:

Listing 18.2 AdderImpl.java

import java.rmi.*;
import java.rmi.server.*;
public class AdderImpl extends UnicastRemoteObject implements Adder
{
  public AdderImpl() throws RemoteException
  {
  }
  public int add( int x, int y ) throws RemoteException
  {
    return x + y;
  }
}

Da die Klasse eine Implementierung der Schnittstelle ist, geben wir ihr die Endung Impl. (Das ist eine bekannten Namensgebung aber keine Pflicht.)


Galileo Computing

18.5.1 Der Bauplan für entfernte Objektedowntop

Zuerst fällt in der Implementierung auf, dass wir die Klasse UnicastRemoteObject erweitern. Sie liegt im Paket java.rmi.server und zeigt so die grobe Richtung für die Verwendung an.

public class AdderImpl extends UnicastRemoteObject implements Adder
{
   ...
}

Diese Klasse UnicastRemoteObject bietet Hilfe bei der Übertragung der Daten mittels Standard-TCP-Sockets an. Der Server kann so auf eingehende Anfragen reagieren und diese bearbeiten. Weiterhin zeigt UnicastRemoteObject an, dass ein Exemplar (nicht repliziert) unserer Klasse existieren soll.


Galileo Computing

18.5.2 Der Konstruktordowntop

Für den Konstruktor eines entfernten Objekts gelten zwei Eigenschaften: Wir müssen einen Standard-Konstruktor anbieten, und dieser muss ebenso wie die Methoden RemoteException anzeigen.

public AdderImpl() throws RemoteException
{
}

Der Standard-Konstruktor ist notwendig, da eine Unterklasse genau diesen aufrufen möchte. Unser Konstruktor muss nichts machen. Er ruft aber automatisch den Konstruktor der Oberklasse auf, also den von UnicastRemoteObject. Wir haben schon beschrieben, dass UnicastRemoteObject bei der Übertragung hilft; wenn ein entferntes Objekt konstruiert wird, dann bindet er diesen Dienst an einen anonymen Port und horcht auf einkommende Aufrufe. Wollten wir einen speziellen Port nutzen, müssten wir im Konstruktor unserer Unterklasse einen parametrisierten Konstruktor von UnicastRemoteObject aufrufen, der einen Port annimmt.

Vererbung nicht möglich - was dann?

Es kann passieren, dass eine entfernte Klasse schon von einer anderen Klasse erbt und wir wegen der fehlenden Mehrfachvererbung ein Problem bekommen. Wenn wir uns dafür entscheiden, keine Objekte über UnicastRemoteObject anzubieten, aber eine existierende Klasse trotzdem Anbieter sein möchte, so muss das Objekt im Konstruktor ein entferntes Objekt, welches Remote implementiert, mit UnicastRemoteObject.exportObject(Remote) anmelden.


Beispiel Der Server implementiert die Schnittstelle Adder und registriert sich selbst über exportObject() beim Namensdienst. (Was das ist, erfahren wir gleich etwas genauer.)

Listing 18.3 AdderImpl2.java

import java.rmi.*;
import java.rmi.server.*;

class AdderImpl2 implements Adder
{

  public AdderImpl2() throws RemoteException
  {
  }
  
  public int add( int x, int y ) throws RemoteException
  {
    return x + y;
  }
  
  public static void main( String args[] ) throws Exception
  {
    AdderImpl2 server = new AdderImpl2();
    UnicastRemoteObject.exportObject( server );
    Naming.rebind( "adder", server );
  }
}


class java.rmi.server.UnicastRemoteObject
extends RemoteServer

gp static RemoteStub exportObject( Remote obj )
Exportiert das entfernte Objekt und macht es empfänglich für hereinkommende Aufrufe. Es wird ein willkürlicher Port verwendet.
gp static Remote exportObject( Remote obj, int port )
Verhält sich wie exportObject(Remote), nur wird der angegebene Port und nicht der Standard-Port 1099 verwendet.

Hinweis Die Erweiterung von UnicastRemoteObject ist nur eine Abkürzung für den Weg über exportObject(). Die Methode wird aber ohnehin genommen, wie der Ausschnitt aus dem Quellcode für den Konstruktor zeigt.
protected UnicastRemoteObject() throws RemoteException
{
  this( 0 );
}
protected UnicastRemoteObject(int port) throws RemoteException
{
  this.port = port;
  exportObject( (Remote)this, port );
}


Galileo Computing

18.5.3 Implementierung der entfernten Methodentoptop

Im nächsten Schritt müssen die Methoden der Schnittstelle implementiert werden. Es steht frei, andere Methoden anzugeben, die nicht in der Schnittstelle vorgegeben sind, doch diese sind dann natürlich nicht nach außen sichtbar.

public int add( int x, int y ) throws RemoteException
{
  return x + y;
}

Die Argumente und Rückgabewerte können von jedem beliebigen Datentyp sein. Bei primitiven Datentypen werden spezielle read()- und write()-Folgen generiert. Objekte müssen die Schnittstelle Serializable implementieren (oder Remote sein). Dann werden die lokalen Objekte als Kopie übertragen. Über die Serialisierung werden alle nicht statischen und nicht transienten Attribute übermittelt. Ist der Parameter wiederum instanceof Remote, dann wird dieser Verweis als einfache Referenz übergeben. In Wirklichkeit ist die Referenz ein Verweis auf den Stellvertreter.





Copyright (c) Galileo Press GmbH 2004
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Galileo Computing]

Galileo Press GmbH, Gartenstraße 24, 53229 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de