Client/Server-Praktikum WS 2001/2002

Dozent: Spruth
Anfang
Aufgaben
Blatt 1
Blatt 2
Blatt 3
Blatt 4
Blatt 5
Blatt 6
Abgaben
Blatt 1
Blatt 2
Blatt 3
Blatt 4
Blatt 5
Blatt 6

Aufgabenblatt 1 - LDAP

Bitte lesen Sie die Einleitung.

Dann loggen Sie sich bitte auf den Rechner quak ein.

1. Aufgabe

Legen Sie ein Datenverzeichnis für den LDAP-Server an, falls ihr home-Verz. zu klein ist, geht das auch im /tmp - Verzeichnis.
Laden Sie sich eine slapd.conf herunter und passen sie die Pfade an.
Als nächstes benötigen Sie die LDIF - Daten, diese werden mit dem Befehl: /usr/sbin/ldif2ldbm -f slapd.conf -i data.ldif eingespielt. Die Zeitdauer hierfür messen Sie bitte entweder mit einem kleinen Shell- oder Perlskript.
Für alle die noch nie ein Shell oder Perlskript geschrieben haben ist hier ein Rahmenprogramm, das die Zeit misst. Einfach in die Anführungszeichen hinter "system" den auszuführenden Befehl eintragen, das Programm dann mit perl A1.pl starten. Die Ausgabe ist die Ausführungszeit in sek.
Zum Schluss lesen Sie die man - Pages zu slapd und starten Ihn auf einem Port zw. 1090 - 1099.( sollten sie mit ihren Kollegen absprechen!)

Achtung: Wenn Sie sich von einem Windows Rechner per ssh auf die Uni Rechner einloggen, achten Sie darauf, dass alle bearbeiteten Dateien im Unix Format auf Ihrem Account liegen.

Abgabe:
- Benötigte Zeit für LDIF
- Ausgabe aller Hotels in Esslingen :)

2. Aufgabe

Wie ihnen bestimmt aufgefallen ist, fehlt eine Beschreibung der Hotels. Diese werden wir nun mit ldapmodify hinzugefügen.
Lesen Sie die Dokumentation zu der ldapmodify durch und spoolen Sie die Daten aus description.ldif ein

Abgabe:

- Zeitdauer

3. Aufgabe

Holen Sie sich das Rahmenprogramm und lesen Sie sich in RFC 1823 die Doku zu ldap_search_s() durch.
Vervollständigen Sie das Programm, so dass es alle Hotels ausgibt, welche ein Bad besitzen und eine 7'er PLZ haben.

Abgabe:

- Sourcecode
- gemessene Zeit

4. Aufgabe

Killen sie Ihren slapd :)

Bemerkung:

Der Rechner quak ist relativ langsam und wird ausserdem noch zusätzlich durch diese Aufgabe belastet, deshalb sollten Sie u.U. eine Messung wiederholen, falls die Zeiten zu unplausibel sind. Abgabe bitte per Mail an Stefan Munz






Aufgabenblatt 2 - CORBA mit Java

Inhalt dieser Seite:

Was ist CORBA?
Das Vorgehen bei der Entwicklung mit CORBA
Die vom IDL-Compiler erzeugten Dateien
Unsere Beispiel-Anwendung
Ihre Aufgabe
 
 

Was ist CORBA?

Die Common Object Request Broker Architecture (CORBA) ist ein Standard zum Verteilen von Objekten über ein Netzwerk.
Er wurde von der Object Management Group (OMG), einem nicht profitorientierten Standardisierungsgremium mit mehr als 700 Mitgliedern (Softwareentwickler, Netzwerkbetreiber, Hardwareproduzenten und kommerzielle Anwender von Computersystemen, unter anderem SUN, IBM, ...) 1991 in der ersten Version definiert.
Ziel war, eine Middleware zu schaffen, welche eine orts-, plattform- und implementierungsunabhängige Kommunikation zwischen Applikationen erlaubt.
Ein Vermittlungsdienst (Object Request Broker = ORB) gewährleistet dabei das Zusammenarbeiten von Objekten über Rechnergrenzen hinweg.
Wirklich interessant geworden ist CORBA seit der Verabschiedung der Version 2.0 im Dezember 1994. Diese Version brachte das Kommunikationsprotokoll IIOP, welches die Kommunikation zwischen Object Request Brokern (ORB) verschiedener Hersteller und vor allem auch über das Internet ermöglicht.

CORBA zeichnet sich durch folgende Eigenschaften aus:

  • Objektorientierung.

  • Die grundlegenden Einheiten der Architektur sind Objekte.
     
  • Verteilungstransparenz.

  • CORBA-Programme greifen auf entfernte Objekte mit denselben Mechanismen zu, wie auf lokale Objekte. Der genaue Aufenthaltsort eines Objekts bleibt für seine Klienten in der Regel unbekannt.
     
  • Effizienz.

  • Die Architektur für den ORB ist von der OMG bewußt so gehalten, daß effiziente Implementationen möglich sind, die z.B. im Falle rein lokaler Kommunikation dem traditionellen Funktionsaufruf nur unwesentlich nachstehen.
     
  • Hardware-, Betriebssystem- und Sprachunabhängigkeit.

  • Die Komponenten eines CORBA-Programms können auf verschiedenen Betriebssystemen, Hardwarearchitekturen und mit verschiedenen Programmiersprachen realisiert werden.
     
  • Offenheit.

  • Über den ORB können Programme verschiedener Hersteller zusammenarbeiten. Der Anwender erhält dadurch die Freiheit, jede Komponente bei dem Anbieter kaufen zu können, der seinen individuellen Bedürfnissen am besten gerecht wird. Softwareentwickler erhalten die Chance, am Softwaremarkt von morgen teilzuhaben und Angebote großer Firmen mit spezialisierten Produkten zu ergänzen.
CORBA stellt also zum einen eine beachtliche Menge technologischen Know-hows und zum anderen einen selten erreichten Konsens innerhalb der Computerindustrie dar.

Begriffe und Abkürzungen:

  • ORB

  • Der Object Request Broker (ORB) ist der Kommunikationsbus zwischen CORBA-Objekten.
    Er bietet einen Mechanismus an, um Anfragen des Clients an die entsprechenden Objekt-Implementierungen weiterzuleiten, und zwar unabhänigig davon, an welchem Ort sich diese im Netzwerk befinden und unter welchem Betriebssystem sie dort laufen.
    Der Client braucht dabei nicht zu wissen, ob sich das Objekt auf dem gleichen Computer befindet oder auf einem Remotecomputer irgendwo im Netz sitzt. Er muß nur den Namen des Objekts oder die Objektreferenz kennen und wissen, wie man die Schnittstelle des Objekts benutzt.
    Der ORB kümmert sich um die Details: Das Lokalisieren des Objekts, die Weiterleitung des Aufrufs und das Zurückliefern des Resultats.
    Hinter einem einfachen Methodenaufruf des Clients verbirgt sich also eine komplexe Netzwerkkommunikation, die vom ORB gehandhabt wird:
    Eine Anfrage des Clients, bestehend aus dem Methodenaufruf und den Parametern, wird in einem binären Strom umgesetzt (marshaling) und über das Netzwerk an den Server geschickt. Die Informationen werden auf der Server-Seite wieder decodiert (unmarshaling) und die gewünschte Operation ausgeführt. Rückgabewerte werden auf die gleiche Weise wieder über den ORB an den Client gesendet.
    Zusammengefaßt hat der ORB die Aufgabe, die dem Aufruf des Clients entsprechende Objektimplementierung zu finden, sie -falls erforderlich- zu aktivieren, die Anfrage an das Objekt zu leiten und entsprechende Rückgabewerte wieder an den Client zurückzugeben.

    Abbildung entnommen aus: "INPRISE Corporation: VisiBroker for Java 3.0, Programmer's Guide".
     
  • Stubs und Skeletons

  • Stubs stellen für den Client die Schnittstellen zu den Server-Diensten (Objektmethoden) bereit.
    Aus der Sicht des Clients verhält sich der Stub wie ein Proxy-Objekt für ein entferntes Server-Objekt.
    Die Server-Objekte werden mit Hilfe von IDL definiert, ihre zugehörigen Client-Stubs vom einem IDL-Compiler generiert. Ein Stub beinhaltet Code für die Umsetzung der Methodenaufrufe mit ihren Parametern in einfache Nachrichtenströme, die an den Server gesendet werden. Die zugrundeliegenden Protokolle oder Dinge wie Datenanordnungen bleiben für den Client vollkommen transparent, der die Dienste als einfache Methodenaufrufe auffaßt.
    Skeletons stellen das Gegenstück zu den Client-Stubs dar. Sie stellen die statischen Schnittstellen für jeden vom Server unterstützten Dienst bereit. Sie beinhalten Code, um eingehende Nachrichten in normale Methodenaufrufe umzusetzen und diese auszuführen. Rückgabewerte werden wieder über die Skeletons in einem binärem Strom umgewandelt und an den Client zurückgeschickt.
    Wie die Stubs werden die Skeletons vom IDL-Compiler aus IDL-Interfaces generiert.
     
  • IDL

  • CORBA wurde so spezifiziert, daß es sprach- und betriebssystemunabhängig ist.
    Dazu ist eine einheitliche Schnittstellenbeschreibung der zu verteilenden CORBA-Objekte erforderlich. Diese Beschreibungssprache ist im CORBA-Standard als IDL (Interface Definition Language) definiert und an die Syntax von C/C++ angelehnt.
    Die Operationen und Attribute, die von einem Server der "Außenwelt" zur Verfügung gestellt werden sollen, werden zunächst in einem Interface mittels IDL beschrieben. Aus einem vollständig beschriebenen IDL-Interface werden dann mit einem IDL-Compiler Stub-Klassen für die Clients und Skeleton-Klassen für den Server in der jeweiligen Programmiersprache erzeugt.
    Ein IDL-Interface beschreibt dabei lediglich die Schnittstellen der zu veröffentlichenden Dienste und Komponenten des Servers. Es enthält keine Implementierungen. Dadurch wird ermöglicht, daß beispielsweise in Java erstellte Clients auf in C++ realisierte Server-Objekte zugreifen.
     
  • Interface Repository

  • Das Interface Repository ist eine vom ORB unterhaltene Online-Datenbank, die zu jeder Objekt-Klasse die Beschreibung ihrer Interfaces enthält.
     
  • Implementation Repository

  • Das Implementation Repository enthält Informationen zu allen Objekt-Instanzen. Jedes Objekt wird darin durch eine eindeutige Objektreferenz identifiziert.
    Da CORBA-Objekte keine laufenden Prozesse sein müssen, ermöglicht das Implementation Repository jederzeit die Aktivierung eines angesprochenen Objekts.
     
  • BOA

  • Der BOA (Basic Objekt Adapter) ist für die Verbindung der Server-Objekte mit dem ORB zuständig.
    Er hat die Aufgabe, Objekte im Implementation Repository zu registrieren und Objekte zu aktivieren und deaktivieren.
     
  • Objektreferenzen und IOR

  • Eine Objektreferenz ist eine Zeichenkette, die ein Objekt innerhalb eines verteilten CORBA-Systems eindeutig kennzeichnet.
    ORBs unterschiedlicher Hersteller übermitteln Objektreferenzen nach dem IOR-Standard (IOR = Interoperable Object Reference).
     
  • IIOP

  • Das IIOP (Internet Inter ORB Protocol) ist ein Netzwerkprotokoll für die Kommunikation zwischen ORBs.


Das Vorgehen bei der Entwicklung mit CORBA

Prinzipiell erfolgt die Entwicklung einer CORBA-Anwendung stets in den gleichen drei Schritten:
  1. IDL-Datei schreiben, d.h. die Schnittstelle der (Server-)Objekte spezifizieren, und mit dem IDL-Compiler kompilieren
  2. Server implementieren
  3. Client implementieren
Das von uns im Praktikum verwendete Produkt ist der VisiBroker for Java 3.0 von Visigenic.
Dieses Paket enthält unter anderem die CORBA-Klassen, den IDL-Compiler, sowie weitere für die Entwicklung und den Betrieb von CORBA-Anwendungen nötige Werkzeuge und Programme.
Die Online-Produktdokumentation (zwei Teile: "Programmers´s Guide" und "Reference") dazu finden Sie unter der URL http://www.borland.com/techpubs/visibroker/visibroker30/.
Sie bekommen unter dieser Adresse die Dokumentation wahlweise entweder als HTML-Dokument oder im PDF-Format.
Die folgende Kurz-Einleitung kann nicht die Beschäftigung mit dieser Dokumention (z.B.: "Programmers´s Guide", Kap. 1: "VisiBroker Basics", Kap. 2: "Getting started") ersetzen und soll Ihnen lediglich einen einfachen Einstieg verschaffen.

Bei der Programmierung gehen Sie nun also wie folgt vor:

  1. IDL-Datei schreiben, d.h. die Schnittstelle der (Server-)Objekte spezifizieren, und mit dem IDL-Compiler kompilieren

  2.  

     

    Nehmen wir an, Sie möchten eine Klasse "MeineKlasse" mit vier Methoden im Netz zur Verfügung stellen.
    Ihr IDL-Interface könnte dann in etwa so aussehen:
     

    module Test {
      interface MeineKlasse {
        void tunix();
        long tuwas(in float zahl);
        short tuwas2(inout long zahl);
        float tuwas3(out short zahl);
      };
    };
    Die Art eines jeden Parameters (in, inout, out) gibt dabei an, ob mit dem jeweiligen Parameter nur ein Wert an die Methode übergeben werden soll (in), oder ob über diesen Parameter auch ein Wert zurückgegeben wird (inout, out).

    Sie schreiben also die IDL-Datei und speichern sie z.B. unter dem Namen Test.idl ab. Anschließend compilieren Sie sie mit dem Kommando idl2java Test.idl -no_tie (die Option -no_tie bezweckt lediglich, daß der IDL-Compiler keine Dateien generiert, die wir in unserem Fall nicht benötigen).
    Nicht erschrecken: Der IDL-Compiler legt Ihnen nun ein Verzeichnis mit dem Namen Test an, in dem sich eine Unzahl von Dateien befindet, die sich von den ORB-Klassen ableiten und über weitere Vererbung die entsprechenden Methoden soweit anpassen, bis sie mit den IDL-Interfaces übereinstimmen. Für Java werden dabei sehr viele Dateien erzeugt, da Java keine Mehrfachvererbung unterstützt und außerdem nur eine Klasse pro Datei erlaubt ist.
    Je nach Compileroptionen und Art der Klasse werden so pro in der IDL-Datei definierter Klasse ca. fünf Dateien generiert, die alle zusammen das Package Test bilden.
    Wir werden weiter unten noch auf diese Dateien zurückkommen.
     

  3. Server (in Java) implementieren

  4.  

     

    Hier müssen Sie zunächst die Klasse mit den Methoden, die Sie bereitstellen möchten, implementieren.

    Außerdem müssen Sie das Objekt mittels des BOAs beim ORB anmelden und für einen Mechanismus sorgen, der das Objekt aktiviert.
    Im Falle von Visigenic wird die Aktivierung entweder bei Bedarf von einem extra gestarteten Prozess, dem "Object Activation Daemon (OAD)", automatisch erledigt, oder aber sie aktivieren das Objekt mit Hilfe des BOAs selbst und warten dann auf die Anfragen der Clients. Dies können Sie entweder in der main-Methode des Objekts oder aber (wie gleich in unserem Beispiel) in einem separaten Serverprogramm tun.

    Bei der Implementierung Ihrer Klasse erweitern sie per Vererbung die vom IDL-Compiler generierte Skeleton-Klasse (in unserem Beispiel _MeineKlasseImplBase.java).
    Nehmen wir an, sie nennen Ihre Implementation MeineKlasseImpl.java.

    Nun schreiben Sie das Serverprogramm MeinServer.java. Wichtige Kommandos hierbei sind:

    Test.MeineKlasse klasse = new MeineKlasseImpl("Klassen_Name");
    Diese Zeile erzeugt ein neues MeineKlasse-Objekt klasse.
    Wichtig: Durch die Benutzung des Konstruktors mit String-Argument erzeugen Sie ein sog. persistentes Objekt, welches von den Clients später anhand seines Namens (hier: "Klassen_Name") gefunden werden kann.
    Alternativ können sie auch ein namenloses transientes Objekt mit dem argumentlosen Konstruktor erzeugen:
    Test.MeineKlasse klasse = new MeineKlasseImpl();

    boa.obj_is_ready(klasse); (Methode eines org.omg.CORBA.BOA-Objekts boa)
    Hiermit wird das Objekt klasse ins Implementation Repository aufgenommen und vom BOA aktiviert.

    boa.impl_is_ready();
    Alle Objekte sind bereitgestellt, das Serverprogramm hat seine Aufgabe erledigt. Mit diesem Kommando wird das Serverprogramm -und mit Ihm das zur Verfügung gestellte Objekt- weiter am Leben erhalten. Dieses Kommando ist das letzte im Serverprogramm, dieses befindet sich nun in einer Warteschleife, nachfolgende Befehle werden nicht mehr ausgeführt.

    Genauer erklärt finden Sie dies im "Programmers´s Guide", Kap. 5: "Activating Objects".
     

  5. Client (in Java) implementieren

  6.  

     

    Die Methoden, mit denen der Client das von ihm gewünschte Objekt erhält, befinden sich in der vom IDL-Compiler generierten Klasse MeineKlasseHelper.java, und zwar im wesentlichen die Methoden narrow und bind.
    Von beiden gibt es mehrere Formen, die jeweils andere Argumente erwarten.
    Der grundlegende Unterschied zwischen narrow und bind ist, daß narrow die Objektreferenz benötigt, um das Objekt zu finden, bind hingegen findet es aufgrund seines Namens oder liefert einfach das erstbeste passende Objekt des gesuchten Typs zurück.
    In unserem Fall wäre also die richtige Wahl:
    Test.MeineKlasse klasse = Test.MeineKlasseHelper.bind(orb,"Klassen_Name");

    Genauer erklärt finden Sie dies im "Programmers´s Guide", Kap. 4: "Naming and Binding".

Sie haben nun also folgende Dateien vorliegen, die Sie mit dem Compile-Kommando javac *.java compilieren können:
MeinServer.java, MeineKlasseImpl.java und MeinClient.java, sowie das generierte Verzeichnis Test.
Auf dem Serverrechner benötigen Sie MeinServer.java, MeineKlasseImpl.java und das Verzeichnis Test, auf den Clientrechnern MeinClient.java und das Verzeichnis Test.

Die VisiBroker-Dokumentation enthält hierzu ein sehr übersichtliches Beispiel, das die Vorgehensweise verdeutlicht.
 
 

Die vom IDL-Compiler erzeugten Dateien:

  • MeineKlasse.java

  • Enthält das Interface Ihrer Klasse.
     
  • MeineKlasseHelper.java

  • Diese abstrakte Klasse enthält nützliche Methoden, um das damit verbundene Objekt zu handhaben.
    Für Objekte wie structures, enumerations, und unions hält die Helperklasse Methoden zum Schreiben und Lesen bereit. Außerdem bietet sie Methoden wie narrow und bind (s.o.).
     
  • MeineKlasseHolder.java

  • Die Übergabe von out- und inout-Parametern erfolgt über die Holderklasse.
     
  • _st_MeineKlasse.java

  • Die Stub-Klasse.
     
  • _MeineKlasseImplBase.java

  • Die Skeleton-Klasse.
     
  • _example_MeineKlasse.java

  • Beispiel, wie Ihre Objekt-Implementierung aussehen könnte.
Genauer erklärt finden Sie dies in "Reference", Kap. 4: "Generated Classes".
 
 

Unsere Beispiel-Anwendung

Das Programm, mit dem Sie sich in den nächsten drei Aufgaben beschäftigen werden, ist ein Vier-Gewinnt-Spiel, mit dem Sie über Rechnergrenzen hinweg gegeneinander oder gegen einen Computergegner spielen können.
 
 

Prinzipieller Aufbau des "VierGewint"-Systems:

  1. Partie-Manager und Spielpartien

  2. Der Partiemanager hat die Aufgabe, die laufenden Spielpartien zu verwalten. Er startet bei Bedarf neue Spielpartien und weist diese den Clients zu, die spielen wollen.
    Jede Spielpartie enthält die Spiellogik und ein Spielfeld, so daß immer zwei Clients in einer Spielpartie gegeneinander spielen.
     
  3. Computerspieler

  4. Der Computerspieler liefert auf Anfrage des Clients den besten Zug für eine bestimmte Spielsituation zurück.
     
  5. Client

  6. Der Client beantragt entweder beim Partie-Manager eine neue Spielpartie und wartet auf einen Gegner, oder er steigt als Gegner in einer vorhandenen Partie ein, die er sich vom Partie-Manager holt.
    Während des Spiels übermittelt er seine Spielzüge an die Spielpartie und stellt das Spielfeld dar. Die zu übermittelnden Spielzüge nimmt er entweder über die Tastatur vom Benutzer entgegen, oder aber er fragt den Computerspieler nach dem im Moment besten Zug.

Für unsere Aufgabe vereinfachen wir diesen prinzipiellen Aufbau folgendermaßen:
Der Partie-Manager und ein Computerspieler laufen auf einem Rechner, es gibt also nur einen Server.
 
 

Die Verzeichnisstruktur unserer Anwendung

Alle Dateien, die Sie zur Praktikumsaufgabe benötigen, erhalten Sie weiter unten als Zip-Datei.
Wenn Sie diese entpacken, werden folgende Verzeichnisse mit den darin enthaltenen Dateien angelegt:
Aufgabe1
 |  VierGewinnt.idl
 |  vbroker.csh
 |
 +---ClientAufg1
 |       Client.java
 |
 +---ServerAufg1
         PartieManagerImpl.java
         Partie4GewinntImpl.java
         Meister.java
         Server.java
 

Die einzelnen Dateien:

  • VierGewinnt.idl

  •  

     

    Das IDL-Interface, in dem einige Konstanten, der Spielfeld-Variablentyp und die Interfaces unserer Objekte definiert werden.
     

  • vbroker.csh

  •  

     

    Mit dieser Datei werden die benötigten Umgebungsvariablen gesetzt.
     

  • PartieManagerImpl.java

  •  

     

    Das Partie-Manager-Objekt. Wird auf dem Serverrechner zur Verfügung gestellt und verwaltet die Spielpartien.

    Die öffentlichen Methoden:

    public Partie4gewinnt spielen(String name)
    Diese Methode wird vom Client aufgerufen, wenn er eine Partie spielen will. Gibt es schon eine Partie des Namens name, die auf einen Gegner wartet, so wird diese zurückgeliefert, ansonsten instanziiert der Partie-Manager ein neues Spielpartie-Objekt und liefert dieses zurück.

    public String auflisten()
    Liefert in einem String die Namen aller Spielpartien (getrennt durch CRLF) zurück, die im Moment auf einen Gegner warten.
     

  • Partie4gewinntImpl.java

  •  

     

    Das Spielpartie-Objekt. Wird vom Partie-Manager instanziiert und enthält die Spiellogik sowie das Spielfeld in Form eines Arrays.

    Die öffentlichen Methoden:

    public short init(org.omg.CORBA.IntHolder clientTicket)
    Wird von jedem der beiden Spieler zu Beginn aufgerufen. Liefert dem aufrufenden Client seine Spielernummer (1 oder 2) zurück.
    Außerdem erhält jeder Spieler über einen out-Parameter ein "Ticket", d.h., eine Zufallszahl, mit der er sich in Zukunft bei der Übermittlung von Spielzügen ausweist.
    Das Spiel kann beginnen, sobald init zweimal aufgerufen wurde, d.h., sobald zwei Spieler vorhanden sind.

    public short status(int clientTicket)
    Liefert dem Spieler, der sich über sein Ticket ausweisen muß, Informationen zum Spielverlauf, z.B. ob er an der Reihe ist oder ob das Spiel schon zu Ende ist.

    public short ziehen(int clientTicket, short spalte)
    Wirft einen Spielstein in die mit spalte angegebene Spalte des Spielfelds.
    Liefert den Status nach dem Spielzug oder einen Fehlerstatus bei ungültigen Zügen zurück.

    public short[][] holeSpielfeld()
    Liefert das aktuelle Spielfeld zurück.
     

  • MeisterImpl.java

  •  

     

    Das Computerspieler-Objekt.

    Die öffentlichen Methoden:

    public short besterZug(short spieler, short[][] feld)
    Untersucht das Spielfeld feld und liefert den besten Zug für den Spieler zurück, dessen Nummer in spieler übergegeben wird.

    public void spielstaerke(int maxZeitMillis)
    Legt die Spielstärke des Computerspielers fest. Als Eingabe wird die Zeit erwartet, die der Computerspieler zum Überlegen brauchen darf (genauer: Der Computerspieler überlegt insgesamt genau maxZeitMillis * 7/3).
     

  • Client.java

  •  

     

    Das Clientprogramm.

    Die main-Methode sucht zunächst einen Partie-Manager und zeigt dann folgendes Menü:

    1) Partie spielen
    2) Computergegner starten (Java)
    4) Computerbedenkzeit einstellen
    5) Partien auflisten
    7) Ende

    (Fehlende Nummern werden in den folgenden Aufgaben ergänzt.)

    Beim Anwählen der Menüpunkte passiert folgendes:

    1) und 2):
    Die private Methode private static void spielen(String partieName, int spielerTyp) wird aufgerufen.
    Diese Methode erwartet als Argumente den Namen der Partie, die gespielt werden soll, sowie einen Spielertyp, der besagt, ob der Client während des Spiels die Spielzüge der Tastatur entnehmen oder ob er in jeder Runde den Computerspieler nach dem besten Zug fragen soll.
    Beim Aufruf von spielen passiert folgendes:
    1. Bei Bedarf (Spielertyp > 1) sucht der Client einen Computerspieler und stellt mittels dessen spielstaerke-Methode die unter Menüpunkt 4) gewählte Spielstärke ein.
    2. Der Client ruft die Methode spielen des Partie-Managers auf und erhält von diesem ein Spielpartie-Objekt.
    3. Der Client ruft die init-Methode der Spielpartie auf und erhält so Spielernummer und Ticket.
    4. Innerhalb einer Schleife wird der Status der Spielpartie abgefragt und -wenn der Client an der Reihe ist- ein Spielzug ausgeführt.

    4):
    In einer Variable wird die gewählte Spielstärke gespeichert. In der spielen-Methode wird diese Variable -beim Spiel mittels Computerspieler- ausgewertet.

    5):
    Die auflisten-Methode des Partie-Managers wird aufgerufen und der zurückgelieferte String ausgegeben.
     

  • Server.java

  •  

     

    Wir wissen, daß jedes Objekt ins Implementation Repository eingetragen werden muß und daß für die Aktivierung der Objekte gesorgt werden muß.
    Da wir der Einfachheit halber Partie-Manager und Computerspieler auf einem Rechner laufen lassen, erledigen wir dies für beide Objekte in einem einzigen Serverprogramm.
    Dieses Programm initialisiert den ORB und den BOA, instanziiert die beiden Objekte und aktiviert sie mit Hilfe des BOAs und wartet dann auf eingehende Anfragen.


Die Java-Klassen sind zusammengefaßt in den Packages ClientAufg1 und ServerAufg1. Ein drittes Package VierGewinnt wird beim Compilieren der IDL-Datei generiert.
Die Package-Dokumentationen zu allen drei Packages finden Sie HIER.
 
 

Ihre Aufgabe:

  1. IDL-Datei vervollständigen

  2.  

     

    Ergänzen Sie die Datei VierGewinnt.idl um die Interfaces der Objekte, die per CORBA im Netz bereitgestellt werden sollen.
    Hinweis: Bis auf einen einzigen sind alle Parameter vom Typ in. Lediglich die init-Methode des Spielpartie-Objekts hat einen out-Parameter.

    Compilieren sie anschließend die IDL-Datei mit dem Kommando idl2java VierGewinnt.idl -no_tie.
     

  3. Server vervollständigen

  4.  

     

    Die Datei Server.java ist bisher lediglich ein Gerüst. Machen Sie daraus ein funktionsfähiges Programm, das die oben erläuterten Aufgaben erledigt.
     

  5. Client vervollständigen

  6.  

     

    In Client.java müssen die Methoden
    private static PartieManager holeManager() und
    private static Meister holeMeister(int typ)
    vervollständigt werden.
    Diese Methoden dienen dazu, dem Client den vom Serverprogramm per CORBA bereitgestellten Partie-Manager bzw. Computerspieler zu finden.
    Aufgerufen wird holeManager zu Beginn der main-Methode, holeMeister am Anfang der spielen-Methode des Clients.
     

  7. Anwendung starten

  8.  

     

    Bringen Sie die Anwendung zum Laufen!

Hinweise:
  • Sie müssen nur die drei eben erwähnten Dateien verändern, in den übrigen Dateien gibt es nichts zu tun.

  •  
  • In den Dateien sind die Stellen, an denen sich Ihre Aufgaben befinden, folgendermaßen markiert:

  • // HIER BEGINNT IHRE AUFGABE
    // HIER ENDET IHRE AUFGABE
     
  • Die Zip-Datei mit den benötigten Dateien finden Sie HIER.

  •  
  • Bearbeiten Sie die Aufgabe auf einem SOLARIS-Rechner, z.B. remote auf  murphy, carijo, linus, tim, etc.

  •  
  • Zuerst müssen noch einige Umgebungsvariablen gesetzt werden.

  • Führen Sie dazu (nach dem Entpacken der Zip-Datei) das Kommando source vbroker.csh im Verzeichnis Aufgabe1 aus. Vorher sollten sie die Datei allerdings anpassen: Suchen Sie sich einen Port zwischen 14001 und 14999 aus und ändern Sie dementsprechend die Zeile
    setenv OSAGENT_PORT 15000
    ab. Damit verhindern Sie, daß Ihre Clients die Objekte Ihrer Praktikumskollegen ansprechen.
    Achten Sie darauf, daß die Umgebungsvariablen auch wirklich in jedem Bildschirmfenster gesetzt sind, welches Sie bei der Aufgabe benutzen.
     
  • Im Bildschirmfenster, in dem ein Computerspieler laufen soll (also dort, wo sie das Serverprogramm starten), muß eine weitere Umgebungsvariable gesetzt werden. Geben Sie dort vorher das Kommando

  • setenv THREADS_FLAG native
    ein. Andernfalls mißachtet der Computerspieler das ihm zum Nachdenken gesetzte Zeitlimit.
     
  • Bevor Sie ihre class-Dateien ausführen können, müssen Sie auf dem Server-Rechner das Kommando osagent (als Hintergrundprozeß) starten. Dieses unterstützt den BOA.

  •  
  • Ihre class-Dateien starten Sie mit dem Kommando vbj.

  •  
  • Beachten Sie beim Compilieren und Ausführen der Dateien, daß die Klassen in Packages organisiert sind.

  • Compilieren Sie also vom Verzeichnis Aufgabe1 aus, z.B. mit dem Kommando javac ServerAufg1/*.java.
    Ebenso starten Sie die Programme vom Verzeichnis Aufgabe1 aus, z.B. mit dem Kommando vbj ClientAufg1.Client.
     
  • Achten Sie nach dem Beenden der Programme und beim Ausloggen darauf, daß Sie all Ihre Prozesse beendet haben (auch die Hintergrundprozesse).

  •  
  • Denken Sie auch an die anderen User, die auf Ihrem Rechner eingeloggt sind und verursachen Sie nicht durch langes Spielen gegen den Computerspieler eine unnötig hohe Prozessorlast!




Diese[r Teil (also Teil zu Blatt 2) der] HTML-Seite an sich sowie die Zusammenstellung dieser Programme und Dokumentationen sind urheberrechtlich geschützt.
© 1999 Michael Dom und Wolfgang Westje
Alle Rechte vorbehalten.


Betreuung der Aufgabe : Stefan Munz

Abgabe der Lösungen per E-Mail an Stefan Munz

Unter dieser Mailadresse können Sie auch jederzeit Fragen zum Thema stellen.

Als Abgabe werden funktionierende Versionen der drei zu vervollständigenden Dateien erwartet.






Aufgabenblatt 3 - CORBA mit Java 2: CORBAservices: Naming Service


Übersicht:


Was sind CORBAservices?

CORBAservices sind eine Sammlung von Diensten auf Systemebene, die CORBA-Objekte um mehrere nützliche Eigenschaften ergänzen bzw. den Umgang mit Gruppen von Objekten erleichtern. Während das einfache Objekt nur vom Applikationsprogrammierer gegebene Eigenschaften aufweist, kann man mit Hilfe der CORBAservices allgemeine Objekteigenschaften (objekt- und implementierungsunabhängig) hinzufügen.

Die CORBAservices sind eine Abstraktionsebene höher als der CORBA Object Bus anzusiedeln, sie bieten einfache Schnittstellen, um mit CORBA-Objekten umgehen zu können. Sie geben so dem Applikations- bzw. Komponentenprogrammierer Werkzeuge in die Hand, die er sonst zum Teil selbst erstellen müsste, und beschleunigen so die Programmentwicklung.

Folgende Grafik zeigt eine Einordnung der Services in die Hierarchie der Komponentenprogrammierung unter CORBA:

Objekthierarchie
Business Objekte sind in diesem Zusammenhang Top-level-Objekte, die sich idealerweise wie Objekte in der realen Welt verhalten und vollkommen von technischen Details abstrahiert sind.

Die CORBAservices sind reine CORBA-Objekte und ihre Schnittstellen vollständig in IDL geschrieben. Die Spezifikation ist in CORBAservices: Common Object Services Specification festgelegt.
Die CORBA-Implementierungen der verschiedenen Anbieter enthalten nicht immer alle hier vorgestellten Services.

Momentan sind folgende 15 CORBAservices spezifiziert:

  1. Naming Service:

  2. erlaubt es, Objekte ähnlich wie Dateien in einem Dateisystem mit Namen zu versehen und sie anhand dieser Namen wiederzufinden.
  3. Event Service:

  4. stellt einen Nachrichtenkanal zur Verfügung, an den sich Nachrichtenkonsumenten und -lieferanten dynamisch anschließen und Nachrichten empfangen bzw. verschicken können.
  5. Life Cycle Service:

  6. bietet die Möglichkeit, Gruppen von Objekten zu erstellen, zu löschen, zu kopieren und zu bewegen.
  7. Persistent Object Service:

  8. gestattet, Objekte in einem persistenten Zustand zu halten.
  9. Transaction Service:

  10. steuert Transaktionen zwischen Objekten.
  11. Concurrency Control Service:

  12. koordiniert den gleichzeitigen Zugriff mehrerer Objekte auf gemeinsame Ressourcen.
  13. Relationship Service:

  14. macht es möglich, Objekten dynamisch Rollen zuzuweisen und Beziehungen zwischen Objekten zu definieren, um Graphen von Objekten zu erstellen, die beliebig durchlaufen werden können.
  15. Externalization Service:

  16. bietet einen allgemeinen Weg an, Daten aus einem bzw in ein Objekt zu ex- oder importieren.
  17. Query Service:

  18. erlaubt Objekten Anfragen an eine Sammlung von Objekten zu stellen; basiert auf SQL bzw. OQL.
  19. Licensing Service:

  20. überwacht, ob Objekte konform der Lizenz des Herstellers benutzt werden.
  21. Property Service:

  22. kann dynamisch Objekte mit Eigenschaften ("named values") assoziieren und diese manipulieren.
  23. Time Service:

  24. stellt Methoden zur zeitlich Synchronisation und Zeitmessung zur Verfügung, sowie die Möglichkeit mit zeitgesteuerten Ereignissen zu arbeiten.
  25. Security Service:

  26. schafft eine umfassende Sicherheitsumgebung die u.a. Identifizierung und Authentifizierung, Authorisierung und Zugriffskontrolle sowie sichere Kommunikation beinhaltet.
  27. Object Trader Service:

  28. stellt eine Art "Gelbe Seiten" für Objekte und ihre Dienste dar. Er erlaubt es Objekten, ihre Dienste bekannt zu machen und anderen Objekten dynamisch nach diesen Diensten zu suchen.
  29. Object Collection Service:

  30. macht es möglich, Objekte in allgemeiner Weise in Sammlungen wie z.B. Listen, Mengen oder Bäumen einzugliedern und diese zu manipulieren.
Der Großteil dieser Dienste vereinfachen den Umgang mit Gruppen von Objekten, nämlich Object Collection Service, Trader Service, Query Service, Relationship Service, Life Cycle Service, Event Service, Naming Service, Property Service.

Der Rest fügt zu Objekten Funktionalität hinzu, die im professionellen Gebrauch in einer verteilten Umgebung benötigt werden. Hierzu zählen Security Service, Time Service, Concurrency Control Service, Transaction Service, Externalization Service, Licensing Service, Persistent Object Service.

Der Hauptnachteil der CORBAservices besteht meiner Meinung darin, daß sie, da sie vollkommen auf der CORB Architektur beruhen, auf eine sehr effiziente Implementierung des ORBs angewiesen sind, um eine ausreichende Skalierbarkeit zu gewährleisten.

Für einen Überblick über die CORBAservices ist das Buch Instant CORBA, (Wiley 1997) von Orfali / Harkey / Edwards sehr gut geeignet.


Was ist der Naming Service?

Der Naming Service dient dazu, Namen an Objekte zu binden, um Objekte sich gegenseitig anhand ihres Namens finden zu lassen. Eine Namensbindung wird immer relativ zu einem Namenskontext definiert, dem Äquivalent zum Verzeichnis im Dateisystem, indem sie eindeutig sein muß. Ein Namenskontext kann auch an einen Namen gebunden werden, so ist es möglich eine Namenshierarchie aufzubauen:

Naming Graph

Man kann dasselbe Objekt mit mehreren Namen zu versehen, ähnlich wie mit "links" unter dem Unix-Dateisystem. Im Gegensatz zu Dateisystemen gibt es beim Naming Service aber keinen Wurzelkontext auf dem alle Namensbindungen beruhen und somit auch keine absoluten Namensbindungen.

Um den Typ eines Objektes nicht wie bei Dateien syntaktisch in den Namen einzubauen zu müssen(".txt"), besteht ein Name beim Naming Service aus einer oder mehreren NameComponent-Strukturen, die sich aus einer "ID" (dem "Namen") und dem "kind"-Attribut (dem "Typ") zusammensetzen. Beide Felder sind Strings und beliebig wählbar.

Beispiele:

(folgende Notation der Namen mit Klammern und Anführungszeichen ist willkürlich; die Schreibweise als JAVA-code  wird später beschrieben)

Name des Manager-Objekts im [{"4 gewinnt","Verzeichnis"}] Namenskontext:
[{"Partiemanager", "Verzeichnis"},{"Manager","Objekt"}]

Name des JAVAMeister-Objekts im [{"Computergegner","Verzeichnis"}] Namenskontext: [{"JAVAMeister","Objekt"}]

Das Ziel beim Entwurf des Naming Service war, ihn einfach und allgemein zu halten und nur so viel Funktionen zu integrieren wie nötig sind, um einen Namensbaum/-hierarchie entstehen zu lassen.
Dadurch kann man viele bestehende Namensdienste und Dateisysteme transparent in den Naming Service kapseln.

Wie programmiert man den Naming Service?

Dieser Abschnitt beschränkt sich auf die Programmierung der Namensbindung und ihre Auflösung.

Für eine vollständige Referenz kann man die OMG Naming Service Specification und die Dokumentation zum VisiBroker Naming- und Event Service hinzuziehen. In der Dokumentation zur JDK1.2 CORBA Implementierung befindet sich eine Einführung in den Naming Service, sowie ein dokumentiertes Beispiel , welches sich für diese Aufgabe besser eignet, als das des VisiBroker.
 

1.

Starten des Naming Service:

tnameserv -ORBInitialPort <Port>
 

Aufruf des Servers:

lokal:         java ServerAufg2.Server -ORBInitialPort <Port>
remote:  java ServerAufg2.Server -ORBInitialPort <tnameserv-Port> -ORBInitialHost <tnameserv-Hostname>
 

Aufruf des Clients:

lokal:         java ClientAufg2.Client -ORBInitialPort <Port>
remote:  java ClientAufg2.Client -ORBInitialPort <tnameserv-Port> -ORBInitialHost <tnameserv-Hostname>
 

Aufruf des JAVAMeister2:

lokal:         java ServerAufg2.Meister2 -ORBInitialPort <Port>
remote:  java ServerAufg2.Meister2 -ORBInitialPort <tnameserv-Port> -ORBInitialHost <tnameserv-Hostname>
 

2. Holen des Grundkontexts (root context)

Zuerst sollte man das Package org.omg.CosNaming importieren.

Innerhalb des Clients bzw. Servers erhält man eine Referenz auf den Grundkontext mit der Methode resolve_initial_references("NameService") der Klasse org.omg.CORBA.ORB.
Diese allgemeine Objektreferenz muß noch auf einen NameContext eingeengt werden.

3. Definieren eines Namens

Ein Name wird durch ein Array der Klasse NameComponent dargestellt:
NameComponent[] simpleName={new NameComponent("westje", "Verzeichnis")};
Er kann dabei entweder als ein einfacher Name (wie oben), der ein Objekt innerhalb des jetzigen NameContext bezeichnet, definiert werden oder als ein zusammengesetzter Name der noch einen Pfad beinhaltet, zusammengestellt werden:
NameComponent[] compoundName={new NameComponent("home","Verzeichnis"), new NameComponent("westje","Verzeichnis")};
Wenn man sich unterhalb des NameContext [{home,Verzeichnis}] befindet und den Namen compoundName verwendet bekommt man dasselbe Objekt, wie wenn man sich im NameContext [{home,Verzeichnis}] befindet und den Namen simpleName verwendet.

4. Binden eines NameContext

Sei ctx der aktuelle NameContext und name der Name des neuen Kontexts. Mit

NamingContext new_ctx = ctx.new_context();
ctx.rebind_context(name,new_ctx);

bindet man den NameContext new_ctx an den NameContext ctx.

5. Binden eines Objekts

Mit

ctx.rebind(name, obj);

bindet man das Objekt obj unter dem Namen name an den Kontext ctx.

6. Auflösen eines Namens

Um das eine Referenz auf das Objekt obj unter dem Namen name im Kontext ctx zu erhalten, benötigt man die Methode resolve der Klasse org.omg.CosNaming.NameContext:

org.omg.CORBA.Object obj = ctx.resolve(name);

Dieses Objekt muß dann noch auf den passenden Typ "eingeengt" werden.


Was ist die Aufgabe?

Die Aufgabe besteht darin, den Client und den Server des Vier-Gewinnt-Projekts aus der letzten Aufgabe um den Naming Service zu erweitern.

Die Objekte, die im Server dem ORB zur Verwaltung übergeben werden, sollen nun zusätzlich unter den Namen, unter denen sie in der obigen Grafik eingetragen sind, dem Naming Service bekannt gemacht werden. Zu dem JAVAMeister und dem Partiemanager aus der letzten Aufgabe kommt nun noch der JAVAMeister2 hinzu.
Anhand der Einbindung des JAVAMeister2 kann man sehr gut die integrierende Funktion des Naming Service erkennen, der auch zu Objekten auf anderen Rechnern / Betriebssystemen / ORBs eine einheitliche Schnittstelle bietet.

Im Client sollen in den Methoden holeMeister(int typ) und holeManager() die jeweiligen Objekte anhand ihres Namens identifiziert und in das Programm eingebunden werden.
Bei der Methode holeMeister(int typ) soll anhand des Typs (COMPUTER_JAVA oder COMPUTER_JAVA2) der JAVAMeister oder der JAVAMeister2 eingebunden werden.

Die Zeilen, in denen Code eingefügt werden soll, sind durch Kommentare gekennzeichnet.

Hinweise:

     
     
  • Der Server muss aktiv sein !  Benutze am Ende von Server.java und Meister2.java:
    Thread.currentThread().join();


  • Es müssen die Dateien Client.java , Server.java , Meister2.java und VierGewinnt.idl erweitert werden.

  • Es kann die IDL Datei der letzten Aufgabe benutzt werden.
  • Der OSAGENT wird nicht mehr gebraucht.

  •  
  • Es muß der IDLTOJAVA Compiler von JAVA 1.2 verwendet werden.

  • (Die SOLARIS Version ist im Zip-File. Die NT Version kann man bei SUN downloaden.)
  • Die Programme laufen, wie schon bei der letzten Aufgabe, unter Solaris.

  • Für diese Aufgabe benötigt man keine besonderen Umgebungsvariablen.
    Es wird nicht mehr der VISIBROKER verwendet sondern der ORB von JAVA 1.2 .
     
  • Achten Sie bitte darauf, daß Sie alle Prozesse beenden bevor sie die Rechner verlassen, auch die Hintergrundprozesse.

  •  
  • Zum Austesten stehen die Utilities Entbindung (entbindet alles unterhalb des root context) und NamensLister (listet alle Namen unterhalb des root context auf) zur Verfügung. Man startet sie im Verzeichnis in dem das Zip-File entpackt wurde mit:

  • java Util.NamensLister -ORBInitialPort <Port> bzw.
    java Util.Entbindung -ORBInitialPort <Port>
     
  • Die benötigten Rahmenprogramme und Utilities können hier als zip-file heruntergeladen werden.

Abgabe der Lösungen per E-Mail an Stefan Munz

Unter dieser Mailadresse können Sie auch jederzeit Fragen zum Thema stellen.
 
 

Viel Erfolg!

-------------------------------------------------------------------------------------------
Diese[r Teil (also Text zu Blatt 3) der ] Webseite, die zugehörigen Programme und Abbildungen sowie ihre Zusammenstellung sind urheberrechtlich geschützt.
(c) 1999 Michael Dom ,Wolfgang Westje - geändert von Torsten Zey
Alle Rechte vorbehalten.
 

Blatt 4: Servlets


Zweck der beiden unten vorgestellten Aufgaben ist, daß Ihr erste Erfahrungen mit der Programmierung von Servlets sammelt. In den folgenden Paragraphen findet Ihr das nötige technische Hintergrundwissen für die Programmierung der Aufgaben.

Eine allgemeine (nicht technische) Einführung über Servlets findet Ihr hier.


Inhalt:


Was sind Servlets?

Java Servlets sind spezielle Java-Programme, deren Zweck die Erweiterung der Funktionalität eines Servers ist. Diese Programme laufen serverseitig, auf einer Java Virtual Machine (JVM) auf dem Server. Der Client (Webbrowser) braucht Java nicht zu unterstützen. Eine populäre Beispielanwendung für Servlets ist die Anbindung eines Servers an eine Datenbank.

Zur Kommunikation zwischen Servlet und Server wurde eine plattformunabhängige Schnittstelle definiert, die Java Servlet API. Ein einmal programmiertes Servlet kann also prinzipiell auf jedem Server laufen, der diese API unterstützt.

Die Java Servlet API besteht aus folgenden packages:

  • javax.servlet: Enthält Klassen für die Implementierung von generischen (protokollunabhängigen) Servlets.
  • javax.servlet.http: Enthält Klassen für die Implementierung von Servlets, welche das HTTP-Protokoll benutzen (HttpServlets).

HttpServlets

Kurzeinführung in das HTTP-Protokoll: Das HTTP-Protokoll ist ein einfaches, verbindungsloses Protokoll. Verbindungslos bedeutet, daß zwischen Client (Webbrowser) und Server keine permanente, sondern nur eine temporäre Verbindung besteht.

Wenn der Client etwas vom Server will, schickt er eine sogenannte request an den Server. Eine request enthält einen HTTP-Befehl, die sog. method, welche angibt, was der Server tun soll. Nachdem der Server den Befehl verarbeitet hat, antwortet er mit einer response.

Die meistbenutzten HTTP-Befehle sind die Kommandos GET und POST. Etwas einfach formuliert dient das GET Kommando dazu, Daten vom Server zu bekommen, während POST benutzt wird, um Daten an den Server zu senden.

HttpServlets erstellen: Ein HttpServlet erhält man, indem man die Klasse HttpServlet aus dem package javax.servlet.http erweitert. Ein HttpServlet erhält requests von einem Webserver (s. Grafik unten) und schickt responses zurück. Die wichtigsten Methoden dieser Klasse sind:

  • doGet(HttpServletRequest, HttpServletResponse): Verarbeiten von GET requests.
  • doPost(HttpServletRequest, HttpServletResponse): Verarbeiten von POST requests (also requests, die Daten an das Servlet senden).
  • init(ServletConfig): Wird einmal aufgerufen, wenn das Servlet vom Server geladen wird. Hier kann man Befehle zur Initialisierung des Servlets plazieren (z.B. Daten aus einer Datenbank holen, die sich während der Laufzeit nicht ändern).
  • destroy(): Wird einmal aufgerufen, wenn das Servlet vom Server aus dem Speicher entfernt wird.

Hinweis: In den Aufgaben werdet Ihr nur doGet() bzw. doPost() benötigen.

Wichtig ist zu wissen, daß jedes Servlet-Objekt vom Server nur einmal erzeugt (instanziert) wird, und danach mehrere Threads des Servers (eins pro request) u.U. gleichzeitig auf dieses Objekt zugreifen. Falls also member-Variablen (Klassenvariablen) des Servlets verändert werden, ist es notwendig, die jeweiligen Methoden als synchronized zu deklarieren, um die Konsistenz der Daten zu gewährleisten. Lokale Variablen, die nur innerhalb von doGet() bzw. doPost() Methoden existieren, sind davon natürlich nicht betroffen.

HTTP-Servlet handling GET and POST requests


Soviel zu Servlets im allgemeinen. Ziel der zweiten Aufgabe auf diesem Blatt ist es, das HttpSession Objekt kennenzulernen und ein Servlet zu schreiben, welches mit einem (fertigen) Applet kommuniziert.


Die HttpSession

Die HttpSession ist eines der interessantesten Objekte der Servlet API. Mit Hilfe dieses Objekts ist es möglich, Daten einem unbekannten Benutzer eindeutig zuzuordnen und über mehrere Schritte zu bearbeiten (Anwendungsbeispiel: Warenkorb). Dazu wird dem Benutzer ein Cookie mit der ID seiner Session geschickt. Die Daten der HttpSession bleiben jedoch auf dem Server. Wenn der Benutzer sich wieder meldet, wird über den Wert des Cookies auf die richtige Session zugegriffen.

All das passiert automatisch und transparent. Als Programmierer muß man sich lediglich um das holen bzw. erzeugen eines Session-Objekts kümmern, sowie um das Schreiben und Lesen der dort gespeicherten Werte. Dies macht das Benutzen von Sessions sehr einfach und attraktiv. Nützliche Methoden in diesem Zusammenhang sind die getSession(boolean) Methode der HttpServletRequest und die verschiedenen Methoden des HttpSession Objekts.


Infos zur Applet <-> Servlet Kommunikation

HttpServlets können nicht nur mit Webbrowsern kommunizieren, sondern auch mit Java Applets, welche im Webbrowser laufen. Zu diesem Zweck stellt das Applet eine Verbindung zum Servlet her. Es gibt mehrere Möglichkeiten, diese Verbindung herzustellen:

  1. Die einfachste Möglichkeit ist, eine HTTP-Verbindung zu benutzen und Daten als Parameter der GET bzw. POST requests an das Servlet zu senden. Dies ist ziemlich einfach, weil HTTP-Verbindungen über das Objekt java.net.URLConnection aufgebaut werden können. Falls Ihr sehen wollt, wie dies konkret geht, könnt Ihr Euch die Datei HttpMessage.java (bei den Rahmenprogrammen) ansehen, die auch von unserem MasterMind Applet benutzt wird.

    Vorteile dieser Methode sind: die einfache Programmierung (Kommunikation über das HTTP-Protokoll) und sie funktioniert auch durch Firewalls hindurch. Es ist auch möglich, damit Java-Objekte zu verschicken, falls diese serializable sind. Nachteil ist, daß die Verbindung jedes Mal vom Applet hergestellt werden muß, da sie nicht dauerhaft ist. U.a. deshalb ist diese Methode auch nicht gerade besonders effizient.

  2. Eine andere Möglichkeit ist die altbewährte Socket-Verbindung. Nachdem das Applet mit dem Servlet verbunden ist, ist bidirektionale, dauerhafte und effiziente Kommunikation möglich. Sowohl einfache Daten, als auch Objekte können verschickt werden. Nachteile: Sie funktioniert nicht durch Firewalls, ist komplizierter zu programmieren (besonders auf der Servlet-Seite), und man muß sein eigenes Kommunikationsprotokoll entwerfen.

  3. Als dritte Möglichkeit kommt die Benutzung der RMI (Remote Method Invocation) Schnittstelle in Frage. Vorteile: Elegant, weil keine requests/responses, sondern nur Methodenaufrufe benutzt werden und objektorientiert. Das Servlet kann Methoden des Applets aufrufen. Funktioniert auch durch Firewalls (aber noch nicht so gut). Nachteile: Kompliziert zu programmieren, da spezielle Stub und Skeleton Klassen notwendig sind. Außerdem ist eine RMI-NamingRegistry notwendig, um Referenzen auf die Objekte zu bekommen. Nicht alle Browser unterstützen defaultmäßig RMI (Stand Ende 98). Außerdem kann das Servlet dann nur mit Java-Clients interagieren.


Das MasterMind Spiel

In der zweiten Aufgabe werden wir uns mit einem Applet-Servlet Paar befassen, mit dem man MasterMind spielen kann. Falls Ihr das Spiel nicht kennt, wird es deshalb hier kurz vorgestellt:

Ziel ist es, einen nichtbekannten, fünfstelligen Zahlencode zu finden (der Spielcode). Dazu kann man beliebig oft einen Spielcode-Kandidaten eingeben. Als Antwort erhält man die Anzahl der Ziffern, die an richtiger Stelle sind und die Anzahl der Ziffern, die zwar im Spielcode enthalten, aber an falscher Stelle sind. Hat man 5 Zahlen an richtiger Stelle, so hat man gewonnen.


Bevor Ihr beginnt:

Im Praktikum benutzen wir Apache als Webserver, gekoppelt mit dem WebSphere Applikationsserver von IBM, welcher die Servlets ausführt. Angebunden ist eine SQL-Datenbank (DB2), in der die Produkte eines fiktiven Pizza-Lieferdienstes abgelegt sind. Im Rahmen der ersten Aufgabe werdet Ihr einige Produktbeschreibungen aus der Datenbank holen. Um dies so einfach wie möglich zu gestalten, gibt es ein package namens pizzasvc.db, das Klassen enthält, welche die Datenbank auf Objekte abbilden. Mehr dazu in der Aufgabenstellung.

3-Tier Modell (Client, Web/App-Server, DB)
[Das 3-Schichten Modell]


Braucht man extra Klassen? (Ja)

Da die Servlets die Java Servlet API benutzen, braucht Ihr die entsprechenden .jar Dateien. Diese findet Ihr auf quak.informatik.uni-tuebingen.de unter /usr/opt/home/cspuser/classes.tar.gz. Die Datei enthält auch das package pizzasvc.db. Ihr solltet ein Verzeichnis in eurem Account erstellen und das .tar.gz Archiv dort entpacken.

Dann müßt Ihr noch die CLASSPATH Variable auf die .jar Dateien setzen. Im Beispiel unten befinden sich die Dateien im Verzeichnis myClasses. Der Befehl muß natürlich in eine Zeile geschrieben werden.

export CLASSPATH=.:/usr/lib/java/lib/classes.zip:
/home/your_id/myClasses/ibmwebas.jar:
/home/your_id/myClasses/jst.jar:
/home/your_id/myClasses/jsdk.jar:
/home/your_id/myClasses/xml4j.jar:
/home/your_id/myClasses/databeans.jar:
/home/your_id/myClasses/


Gibt es Rahmenprogramme? (Ja)

Die Rahmenprogramme für Aufgabe 1 findet Ihr hier und für Aufgabe 2 hier.


Welches JDK kann benutzt werden?

Ihr solltet das IBM JDK 1.1.7B für Linux benutzen. Dies gibt es auf dem Rechner quak.informatik.uni-tuebingen.de.


Wo muß man die Lösungen ablegen, damit der Server sie findet?

  • Die .class Dateien Eurer Servlets legt Ihr auf quak, in das Verzeichnis /usr/opt/IBMWebAS/servlets/aufgaben/user_id, wobei user_id Eure login ID ist (das Verzeichnis user_id müßt ihr erst noch anlegen).
  • Eure Servlets müssen dem package aufgaben.user_id angehören, sonst findet der Server sie nicht!
  • Eure .html Dateien legt Ihr ebenfalls auf quak in das Verzeichnis /usr/opt/home/cspuser/public_html/user_id (auch hier müßt ihr das Verzeichnis user_id erst noch anlegen).

Wie kann man die .html-Dateien/Servlets aufrufen?

  • Damit das ganze funktioniert, müßt Ihr eine HTML-Einstiegsseite in das oben genannte user_id Verzeichnis legen und diese mit http://quak.informatik.uni-tuebingen.de/~cspuser/user_id/htmlSeite aufrufen.
  • Von dieser Einstiegsseite aus und in den folgenden Seiten/Servlets könnt Ihr dann den relativen Pfad /~cspuser/user_id/Seite benutzen, um .html Seiten aufzurufen.
  • Um Servlets von der Einstiegsseite aufzurufen, müßt Ihr den Pfad /servlet/aufgaben/user_id/dateiname (ohne .class) benutzen.

Aufgabe 1

In dieser Aufgabe sollt Ihr ein Servlet erstellen, welches anhand des gesendeten Werts aus dem Formular in der .html Seite Aufg1.html eine Datenbankabfrage startet und eine .html Seite mit der Liste der Produkte erzeugt. Erweitert dazu das Rahmenprogramm Aufg1Servlet.java.

Folgende Teilschritte sind notwendig:

  1. Die Datei Aufg1.html so anpassen, daß Euer Servlet aufgerufen wird und diese in das HTML-Verzeichnis legen, wie oben beschrieben.
  2. Nun könnt Ihr mit der Programmierung des Servlets fortfahren. Hier sind folgende Schritte notwendig:
    • Den Wert auslesen. Den Namen erfahrt Ihr in der .html Seite Aufg1.html.
    • Die Datenbank abfragen: Dazu müßt Ihr die dem Wert entsprechende Produkt-Kategorie aus einer Liste holen. Dann müßt Ihr diese Produkt-Kategorie an die Produkt-Liste übermitteln und die Datenbankabfrage starten. Die dazu benötigten Objekte sind schon im Rahmenprogramm definiert.
    • Den Cache abschalten und die Antwort generieren.
  3. Nach dem Kompilieren des Servlets die .class Datei im Verzeichnis für Servlets ablegen (siehe oben) und die .html Seite aufrufen, um es zu testen.

Tips: Schaut Euch zuerst das Rahmenprogramm an. Dann schaut Euch die Dokumentation der Servlet API an, insbesondere für die Objekte HttpServlet, HttpServletRequest und HttpServletResponse. Für die Datenbankabfrage schaut in der Dokumentation des package pizzasvc.db nach. Links sind unten angegeben.


Aufgabe 2

Zu tun ist folgendes: Es gibt ein Applet, welches eine einfache GUI für ein MasterMind Spiel zur Verfügung stellt. Das Generieren der Spielcodes und das Überprüfen der Spielcode-Kandidaten übernimmt ein Servlet. Das Applet kommuniziert mit dem Servlet über ein einfaches Kommunikationsprotokoll, um dessen Dienste zu benutzen. Die Nachrichten des Protokolls werden vom Applet als Parameter an die request angehängt, mit der das Servlet aufgerufen wird.

Eure Aufgabe ist es, das Protokoll auf der Seite des Servlets zu implementieren. Im folgenden sind die zwei Nachrichten des Protokolls beschrieben und was für jede zu tun ist. Eine detaillierte Auflistung der notwendigen Einzelschritte findet Ihr als Kommentare im Rahmenprogramm mmServlet.java, welches Ihr auch bearbeiten sollt.

Nachricht 1: Parameter "action" mit Wert "code":

In diesem Fall soll das Servlet eine neue Session erstellen (falls noch keine für diesen Kommunikationspartner erzeugt wurde). Es soll einen neuen Spielcode erzeugen (mit createCode()) und diesen in die Session schreiben. Außerdem soll es die Anzahl der gemachten Spielzüge (Versuche) auf 0 setzen und in die Session schreiben.

Nachricht 2: Parameter "action" mit Wert "validate" und Parameter "code" mit Wert: ein möglicher Code (Code-Kandidat).

In dem Fall soll das Servlet:
  1. Den Spielcode aus der Session holen.
  2. Den Code-Kandidaten aus dem request-Parameter "code" holen.
  3. Die Anzahl der gemachten Versuche aus der Session holen, um eins erhöhen und wieder in die Session schreiben.
  4. Spielcode und Code-Kandidaten vergleichen und das Ergebnis an das Servlet zurückschicken. Das Ergebnis hat folgendes Format: "<Anzahl_gemachte_Spielzüge>,<Zahlen an richtiger Stelle>,<Zahlen im Code, aber an falscher Stelle>". Für den Vergleich die mitgelieferte Methode validateCode(..., ...) benutzen.
Zusätzlich müßt Ihr:
  1. Das package Eures Servlets anpassen (aufgaben.userID).
  2. Das Applet mmApplet.java anpassen, so daß Euer Servlet aufgerufen wird (Datei mmApplet.java, String SERVLET_LOC).
  3. Möglicherweise die Seite mmind.html anpassen, so daß Euer Applet aufgerufen wird.
  4. Die entsprechenden Dateien in Eure Verzeichnisse legen: mmind.html, mmApplet.class und HttpMessage.class Dateien in das HTML-Verzeichnis und das Servlet ins Servlet-Verzeichnis.
Tips:
  1. Die einfachste Art, den Wert der Parameter aus der request zu lesen (ist aber deprecated), ist die Methode request.getParameter(parameter_Name), welche ein Object zurückgibt (Type-Cast notwendig).
  2. Um das Servlet zu testen müßt Ihr das mitgelieferte Applet benutzen. Wichtig: Vorher Cookies im Browser aktivieren !!
  3. ---------- WICHTIGE ÄNDERUNG ----------
    Zum Debuggen könnt Ihr nach System.err schreiben und dann im Verzeichnis /var/log in der Datei httpd.error_log nachschauen (auf dem Rechner quak). Die Strings solltet Ihr noch mit Eurer User-ID markieren, weil alle Servlets dort reinschreiben, und dann am besten grep benutzen. Einige Exceptions der WebSphere gehen auch in /opt/IBMWebAS/logs/servlet/servletservice/error_log.
    --------------------------------------------

Hinweise

Abgabe: Die .java Dateien der Servlets per email an Stefan Munz schicken. Außerdem solltet Ihr hinzufügen, unter welcher User-ID Ihr die Dateien abgelegt habt.

Links auf Dokumentation:

Falls Ihr noch mehr Informationen über Servlet-Programmierung benötigt, ist folgendes Dokument sehr zu empfehlen:

WebSphere Application Server Guide, v. 1.0 (PDF):
- Kapitel 3, Servlet Programmierung


Letzte Aktualisierung [des Aufgabentextes]: Oktober 2000, © Copyright 1999-2000 Elias Volanakis.
Alle Rechte vorbehalten.


Überarbeitung von Marc Beyerle.

 

Aufgabenblatt 5 - OS/390 Teil 1

Hier sind zwei Tutorials zu bearbeiten, die im pdf-Format vorliegen. Daher gibt es an dieser Stelle leider keinen Aufgabentext.

Die Aufgaben zur OS/390 werden komplett auf der Multiprise an der Uni Leipzig gemacht. Um sich auf der 390 einloggen zu können, benötigen Sie einen Account, den Sie entweder im Raum 022-024 beim Präsenztermin abholen oder per email bei mir anfordern.

Für diese Aufgabe sollen Sie 2 Tutorials nachvollziehen. Die Links für die beiden Tutorials sind:
http://www.ti-leipzig.de/os390/paul/nils/tutor1.pdf
http://www.ti-leipzig.de/os390/paul/nils/tutor2.pdf

Die Abgabe bitte trotz gegenteiliger Behauptung in den Tutorials per Mail an Stefan Munz
Der Inhalt der Abgabe ist in den Tutorials beschrieben.

Zusätzliche Informationen finden Sie unter: http://www.ti-leipzig.de/os390/paul/index.html
bzw.:http://www.ti-leipzig.de/os390/paul/lehre.html

Folgenden Hinweis erhielten wir:
Da auf der Leipziger 390 Speicherplatzmangel herrscht, löscht bitte alle eure nicht mehr benötigten DataSets und legt außerdem neue DataSets nur noch mit kleineren Größen an (10 + 5 KB nicht 2 + 1 MB). Wer dafür Hilfe oder genauere Infos braucht wende sich bitte an mich.

Bitte meldet euch auch kurz, wenn Ihr nicht mehr benötigte DataSets gelöscht habt, da ich das sonst tun muss.

 
 
© Sebastian Seyrich und Judith Bentele November2001
Letze Änderung: 05. Dezember 2001
Impressum und Datenschutz