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:
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
- 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.
- 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.
- 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.
- Ü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.
- 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.
- 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!
- Ü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
|