Lab

1

Middleware Platforms

Introduction to Java RMI


Systems Architecture Group

Ablieferungstermin und erreichbare Punktzahl für diese Aufgabe, sowie Voraussetzungen für die Prüfungszulassung entnehmen Sie bitte http://sar.informatik.hu-berlin.de.

In dieser Aufgabe soll das Beispiel zu Java RMI aus der Vorlesung praktisch umgesetzt werden. Hintergrund der Aufgabe ist der Aktienmarkt. Die zu entwickelnde Anwendung gliedert sich in zwei Teile: einen Klient und einen Server.

Realisierung des Servers

Der Server stellt nur eine Funktion zur Verfügung: die Ermittlung des aktuellen Kurses zu einer gegebenen Aktie (identifiziert durch deren Symbol).

Erster Schritt in der Entwicklung der Server-Anwendung ist die Definition eines Interfaces für das entfernte Objekt entsprechend der Java RMI Konventionen:

  • Das Interface muss von java.rmi.Remote abgeleitet sein.
  • Es führt alle Methoden auf, die entfernt aufrufbar sein sollen.
  • Alle Methoden müssen mit throws java.rmi.RemoteException deklariert sein.

Das folgende Interface ist eine mögliche Variante.

package simpleStocks;
 
import java.rmi.Remote;
import java.rmi.RemoteException;
 
public interface StockMarket extends Remote {
      float get_price( String symbol ) throws RemoteException;
}

Nächster Schritt ist die Implementierung der entfernten Methoden. Dazu wird eine Klasse StockMarketImpl verwendet, die von der Klasse UnicastRemoteObject erbt und das Interface StockMarket implementiert. Für das gewählte Beispiel ist nur die entfernte Methode get_price zu realisieren, die zu einem Symbol den entsprechenden Aktienkurs zurückliefert. Eine mögliche Implementierung könnte wie folgt aussehen.

package simpleStocks;
 
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
 
public class StockMarketImpl
extends UnicastRemoteObject
implements StockMarket {
     
      public StockMarketImpl() throws RemoteException {
            super();
      }
     
      public float get_price( String symbol ) throws RemoteException {
            /* 'magical' computation of 'some' stock price */
            float price = 0;
            for( int i = 0; i < symbol.length(); i++ ){
                  price += (int) symbol.charAt( i );
            }
            price /= 5;
            return price;
      }
}

Im Anschluss daran kann mit dem Compiler rmic der benötigte Stub-Code erzeugt werden:

 $ rmic -keep -classpath .  simpleStocks.StockMarketImpl

Als letzten Schritt für der Implementierung des Servers wird ein Objekt der Klasse StockMarketImpl erzeugt und im Namensdienst (lokal, auf dem Server-Rechner) registriert:

package simpleStocks;
 
import java.rmi.Naming;
import java.rmi.RMISecurityManager;
 
public class StockMarketServer {
     
      public static void main(String[] args) throws Exception {
            StockMarketImpl stockMarketImpl = new StockMarketImpl();
            try {
                  Naming.rebind( "NASDAQ", stockMarketImpl );
            }
      catch( Exception e ) {
                  System.out.println( e );
      }
      }
}

Zum Starten des Servers muss zuvor die RMI Registry gestartet werden:

 $ rmiregistry

Nun kann der Server selbst gestartet werden:

 $ java simpleStocks.StockMarketServer

Realisierung des Klienten

Das soeben geschaffene entfernte Objekt kann nun in Klient-Anwendungen benutzt werden. Dazu wird eine Referenz des entfernten Objekts über den Namensdienst bezogen und in den Typ des zuvor entwickelten Interfaces umgewandelt. Nun kann mit der Referenz wie mit einem lokalen Objekt gearbeitet werden:

package simpleStocks;
 
import java.rmi.Naming;
import java.rmi.RMISecurityManager;
 
public class StockMarketClient {
 
      public static void main(String[] args) throws Exception {
            StockMarket market =
                  (StockMarket)Naming.lookup("rmi://localhost/NASDAQ");
            System.out.println( "The price of MY COMPANY is "
                        + market.get_price("MY_COMPANY") );
      }
}

Aufgabenstellung

  1. Erstellen Sie alle Quelldateien und übersetzen Sie diese wie beschrieben. Überprüfen Sie, dass das Programm tatsächlich abgearbeitet werden kann. Schauen Sie sich danach den Inhalt der vom rmic generierten Java-Dateien an und versuchen Sie deren Aufbau und Funktion zu ergründen.
     
  2. Führen Sie den Klienten und den Server auf jeweils verschiedenen Rechnern aus. Kopieren Sie dazu alle Quelltexte und generierten Dateien auf beide Rechner (Klient und Server). Stellen Sie anschließend fest, welche dieser Dateien tatsächlich benötigt werden, damit das Programm richtig funktioniert. Bearbeiten Sie diese Frage, jeweils für den Klienten und für den Server, indem Sie alle nicht benötigten Dateien löschen.
     
  3. In der Vorlesung wurde Ihnen gesagt, dass bei einem entfernten Methodenaufruf die Argumente vom Klienten zum Server übertragen werden; es wurde Ihnen aber nicht gesagt, ob diese, falls sie vom Server verändert wurden, anschließend wieder zum Klienten zurück übertragen werden. Klären Sie diese Frage durch ein einfaches Experiment auf.
     
  4. Überlegen Sie sich ein Experiment zur Beantwortung folgender Frage: Gibt es einen signifikanten Unterschied bei der Ausführungszeit des ersten Aufrufs eines entfernten Objekts und nachfolgenden Aufrufen desselben entfernten Objekts (z.B. wegen eines beim ersten mal erfolgenden TCP-Verbindungsaufbaus zwischen Klient und Server)? Wie erklären Sie sich ihre Beobachtungen?

    Hinweis: Die Schwierigkeit liegt bei dieser Aufgabe darin, sich eine Methodik zu überlegen, um die extrem kurzen Laufzeiten des entfernten Aufrufs approximativ, aber genau genug, bestimmen zu können, um obigen Vergleich durchführen zu können.
     

  5. Java gestattet die Übertragung von Java-Objekten über das Netzwerk. Anstatt eine Vielzahl von entfernten Methodeaufrufen an einem entfernten Objekt auszuführen, könnte man auch dieses Objekt (als Kopie) zum Klienten übertragen, um dort die (vielen) Aufrufe lokal auszuführen.
     
    1. Erweitern Sie das Interface Ihres Remote Objects um eine Methode, die dem aufrufenden Klienten eine lokale Kopie des serverseitigen Objekts bereitstellt, die Sie dann lokal benutzen können. Bei der Realisierung werden Sie auf ein prinzipielles Problem stoßen. Worin besteht es? Lösen Sie es!
       
    2. Überlegen Sie, unter welchen Umständen ein solches "mobiles Objekt" dem "entfernten Objekt" vorzuziehen wäre? Denken Sie an Parameter wie: Netzwerksituation, Anzahl der Aufrufe, Anzahl der gleichzeitig arbeitenden Klienten, Komplexität der Parameter/Ergebnistypen.
       

Abgabe

Benutzen Sie für die Beantwortung der Aufgaben eine HTML Datei mit dem Namen index.html. Begründen Sie die von Ihnen getroffenen Entscheidungen und beschreiben Sie aufgetretene Besonderheiten und Probleme in dieser Datei. Abzugeben sind weiterhin die Quelltexte der Lösung und ein Ant Skript mit dem Namen build.xml, das die Quellen mit den gängigen Werkzeugen automatisiert übersetzt. Bitte reichen Sie die geforderten Dateien in ein ZIP Archiv gepackt ein. 

Testen Sie Ihre Lösung mit der Unit-Test-Bibliothek jUnit (www.junit.org). Schreiben Sie dazu eine Klasse StockQuoterTest, die die Anwendung anhand von verschiedenen Unit-Tests testet. Sie können als Grundlage das folgende Fragment verwenden. Ergänzen Sie das Ant Skript um ein Target test, dass die von Ihnen entworfenen Testfälle automatisiert durchführt.

package simpleStocks;
import junit.framework.TestCase;
 
 
public class StockMarketTest extends TestCase {
  StockMarket _market = null;
 
  public static void main(String[] args) {
    junit.textui.TestRunner.run(StockMarketTest.class);
  }
 
  public StockMarketTest(String name) {
    super(name);
  }
 
  protected void setUp() throws Exception {
    //_market = (StockMarket)Naming.lookup(...);
  }
 
  protected void tearDown() throws Exception {
    _market = null;
  }
 
  public void test1() throws Exception {
  }
}

Hinweise

Ressourcen


Legal disclaimer. .  © 2024 Humboldt-Universität zu Berlin, Computer Science Department, Systems Architecture Group.Contact: sar@informatik.hu-berlin.de .