Post on 17-Apr-2020
Projekt WS05/06 – SS06
Erstellung eines Unterwasser Ökosystems
- Das Feindesign -
Projektteilnehmer: Jens Böckel
Richard Woldert Fanny Ziegler
Marco Becherer Roman Sauber
Kornelia Markovic Daniel Weber
Versionierung Wann wurde geändert?
Version-nummer
Wer hat geändert?
Was wurde verändert?
23.03.2006 1 MB Dokument angelegt, Fisch/Aquarium/View-Controller/ P2P
24.03.2006 1.1 MB Texte von View-Controller eingefügt 25.03.2006 1.2 MB Texte und Bilder der Fische, P2P, Aquarium
eingefügt 25.03.2006 1.3 MB Abbildungsnummerierung eingefügt 25.03.2006 1.4 MB Abbildungsverzeichnis eingefügt 25.03.2006 1.5 MB Dokument mit Inhaltsverzeichnis (hoffentlich)
abgeschlossen 25.03.2006 1.6 MB Änderungsvorschläge von RS eingefügt. Erweitertes
Fisch-Klassendiagramm und Beschreibung der Attribute.
Inhaltsverzeichnis
1 Feindesign der Fische......................................................................................................... 5 2 Design des Aquarium......................................................................................................... 9
2.1 Beschreibung des Klassendiagrammes ...................................................................... 9 2.2 Beschreibung der Methoden..................................................................................... 12
3 Design View und Controller ............................................................................................ 18 3.1 Der Controller .......................................................................................................... 18 3.2 Die View .................................................................................................................. 19
4 Design Peer-To-Peer ........................................................................................................ 21 4.1 Design des P2P-Client.............................................................................................. 21 4.2 Design P2P-Server ................................................................................................... 28
5 Abbildungsverzeichnis ..................................................................................................... 31
5
1 Feindesign der Fische
Abbildung 1.1 Klassendiagramm der Fische
Im Feindesign werden die Komponenten des Ökosystems durch UML Diagramme dargestellt. Das
Feindesign der Fische wird durch ein Klassendiagramm und zwei Sequenzdiagramme beschrieben.
Im Klassendiagramm der Fische wird die Klasse Fisch mit den Attributen und Funktionen
dargestellt. Die Funktionen „update“, „sense“, „act“ und „refresh“ werden in jedem Takt
aufgerufen.
6
Eine kurze Erklärung der Attribute und ihrer Funktionen:
a) id
Die id stellt eine eindeutige Identifikation sicher. Sie wird inkrementell aus der ClientID gebildet.
b) name
Hat keine spezielle Funktion, dient lediglich der Information des Benutzer.
c) species
Die Art des Fisches als String.
d) fisch-eating
Eine boolesche Variable, die kennzeichnet, ob es sich um einen Fleisch fressenden Fisch handelt oder nicht.
e) sex
Das Geschlecht des Fisches
f) maxSpeed
Maximale Geschwindigkeit, die der Fisch schwimmen kann, z.B. bei der Flucht. Bei „normalem“ Schwimmen durch das Aquarium schwimmt der Fisch nicht mit maximaler Geschwindigkeit, sondern langsamer, da das weniger Energie verbraucht.
g) visualRange
Die Sichtweit ist bei allen Fischen wegen sportlicher Fairness gleich. Dieses Attribut muss durch probieren und beobachten herausgefunden werden, wie es optimal ist.
h) size
Damit wird verhindert dass ein kleiner Fisch einen großen Fisch frist. Auf der anderen Seite kann über dieses Attribut das wachsen und altern der Fische realisiert werden.
i) energy
Der Engergiestand, der Einfluss auf das Verhalten der Fische, lt.Entscheidungsbaum, hat.
j) alive
Eine boolesche Variable zum verlassen der Endlos-Schleife, wenn der Fisch stirbt.
7
Die Klasse Fisch implementiert zwei Interfaces:
Runnable
Damit wird die Java-Multithreading-Funktionalität genutzt um die einzelnen Objektinstanzen der Fische in einem eigenen Thread ausführen zu können.
Serializable
Damit wird das Objekt „Fisch“ von einem Aquarium zum anderen transportiert, indem es serialisiert wird und als Bytecode mit all seinen Zustandsdaten und seiner Grafik durch die P2P-Schicht zwischen den Clients übermittelt wird. Hierfür müssen die Methoden „writeObject“ und „readObject“ implementiert werden.
Abbildung 1.2 Sequenzdiagramm der Paarung Im Sequenzdiagramm Paarung wird der Ablauf des Paarungsverhaltens dargestellt. Es können nur
Fisch Männchen zum Paaren aufrufen und es können sich nur Fische der gleichen Art paaren. Die
Fisch Weibchen können die Paarung annehmen oder ablehnen. Nach der Paarung wird vom
Aquarium im nächsten Takt ein Fisch Kind erzeugt. Um ständiges Paaren zu verhindern sinkt der
Energiestand der Fische unter einem bestimmten Level.
8
Daraufhin begeben sich die Fische auf Nahrungssuche. Gegenseitiges auffressen bei gleichartigen
Fischen ist ausgeschlossen.
Abbildung 1.3 Fressen oder gefressen werden ...
Im Sequenzdiagramm „Fressen und gefressen werden“ wird das Verhalten der Fische beim Fressen
beschrieben. Oberste Priorität eines Fisches ist es bei einem bestimmten Energiestand nach
Nahrung zu suchen. Durch die Methode „sense“ kann der Fisch seine Umgebung wahrnehmen. Das
Aquarium sendet Ihm Informationen bis zu einer gewissen Entfernung. Falls ein Fisch sich im
Sichtfeld des „Jägers“ befindet versucht der Jäger dem Opfer sich zu nähern. Das vermeintliche
Opfer kann flüchten. Ob die Flucht gelingt hängt von den jeweiligen Eigenschaften der Fische ab.
Wenn der jagende Fisch das Opfer eingeholt hat, bekommt das Aquarium dies mit und entfernt im
nächsten Takt das Opfer aus dem Aquarium.
9
2 Design des Aquarium
2.1 Beschreibung des Klassendiagrammes Schnittstellenklassen
Die zentrale Klasse Aquarium implementiert drei Interfaces, die die Schnittstellen zu den jeweiligen
Paketen darstellen: P2PAquarium_IF, welches vom Paket P2P benutzt werden soll;
ControllerAquarium_IF, welches vom Controller eingebunden werden soll; FishAquarium_IF,
welches von der Fish-Komponente genutzt werden soll. Somit erhält jedes Paket seine eigene Sicht
auf das Aquarium und erhält Zugriff auf die für dieses Paket relevanten Methoden.
Klasse Aquarium
Diese Klasse ist das Herzstück der Aquarium-Komponente. Sie implementiert das Interface
Runnable, damit Java Multithreading genutzt werden kann. Ausserdem ist sie als Singleton
konzipiert, d.h. im gesamten Programm gibt es nur eine Instanz der Klasse Aquarium. Intern besteht
die Klasse aus einer Liste von Fischen, die sich in diesem Aquarium befinden: myFishList.
Ausserdem besitzt sie die Methode sendFish(), die von Aquarien untereinander genutzt wird, um
Fische zu transferieren.
Klassen FishList und PositionedFish
Sie besteht aus einem Array von Instanzen der Klasse PositionedFish. Die Methode statistic() stellt
eine Fisch-Statistik auf, die dann der GUI zur Verfügung steht.
PositionedFish erweitert die Fish-Klasse um die Position im jeweiligen Aquarium (x,y-
Koordinatensystem). Dazu kann mit der Methode setNewPos( int xPos, int yPos) die Position
gesetzt, bzw. geändert werden.
Klasse VectorFish
Diese Klasse wird benötigt, um die absoluten Koordinaten eines Fisches, mit denen die Klasse
Aquarium intern arbeitet, in einen Bewegungsvektor umzurechnen. Dieser ist dann relativ zu dem
10
Fisch, der sense() aufruft.
Klasse Mover
Diese Klasse wird von der Klasse Aquarium benutzt, um das Array myFishList zu aktualisieren,
d.h. die Position von Fischen im Aquarium zu ändern (calculateNewPosition()); dazu rechnet die
Klasse den Richtungsvektor der Fish-Klasse in absolute Koordinaten um.
Die Methode randomPosition() wird beim Einsetzen eines neuen Fisches benötigt.
calculateChildrenPosition( int count) liefert zufällige Positionen für die count erzeugten Kinder
zurück.
11
Abbildung 2.1 Klassendiagramm Aquarium
12
2.2 Beschreibung der Methoden
k) Pseudocode init()
• erzeuge FishList
• kreieren neuer Fisch-Objekte (benutze Konfig-Datei)
• füge Fische in FishList ein
• starte Thread pro Fisch
Abbildung 2.2 Sequenzdiagramm Methode init()
13
l) Pseudocode sense()
Abbildung 2.3 Sequenzdiagramm Methode sense()
• duchsuche FishList nach Fischen in Sichtweite
• gefundene Fische in das FishArray packen und FishArray zurückliefern
14
m) Pseudocode refresh()
if( alle Fische haben refresh() aufgerufen) then
view.notify()
clearMarks()
else
markiere Fish als “refreshed”
Abbildung 2.4 Sequenzdiagramm refresh()
15
n) Pseudocode receiveInfo()
Abbildung 2.5 Sequenzdiagramm Methode receiveInfo()
• aktualisiere Info über Nachbarbereich (Nachbaraquarium) in FishList
o) Pseudocode sendInfo()
Abbildung 2.6 Sequenzdiagramm Methode sendInfo()
• return FishList
16
p) Pseudocode receiveFish()
Abbildung 2.7 Sequenzdiagramm Methode receiveFish()
• instanziiere Fish-Objekt
• füge es in FishList ein
• starte Fisch-Thread
17
q) Pseudocode createChildren()
Abbildung 2.8 Sequenzdiagramm Methode createChildren()
• kreiere neue Fisch-Objekte
• füge neue Fische in FishList ein
• starte jeden Fisch in eigenem Thread
18
3 Design View und Controller
3.1 Der Controller
Abbildung 3.1 Klassendiagramm Controller
Der Controller hängt sich in die Klasse AquariumGUI ein und übernimmt die Anzeige der
Menüleiste. Die Kernaufgabe des Controllers liegt in der Verarbeitung der Benutzereingaben, die
entweder per Maus oder per Tastatur erfolgen. Dazu implementiert der Controller die Interfaces
MouseListener, WindowListener (zum schliessen des Fensters) und ActionListener.
Die Darstellung des Menüs übernimmt die Klasse AquariumMenue mit weiteren Swing Klassen.
19
3.2 Die View
Das Package View enthält die Starter Klasse des Aquariumprogramms. Das Programm wird wie in
Java üblich über die statische main Methode gestartet.
Die Starter Klasse startet zunächst das Aquarium dann den Controller und anschließend dann die
AquariumGUI (View). Der Hintergrund dieser Reihenfolge ist, dass der Controller für die
AquariumGUI verfügbar sein muss, wenn diese gestartet werden soll. Der AquariumGUI wird eine
Referenz auf das Aquarium übergeben, damit sie sich die Daten das „Models“ holen kann.
Die AquariumGUI erweitert die Java Swing Klasse JFrame, mit deren Hilfe sie ein Window Fenster
anzeigen kann. Das Menü des JFrames wird durch den Controller dargestellt. Die tatsächliche
Anzeige des Aquariums übernimmt die Klasse AquariumView, die von der Klasse JPanel abgeleitet
ist. Der Hintergrund des Aquariums wird durch die Klasse BackgroundView, ebenfalls von JPanel
abgeleitet, dargestellt. Die Anordnung der Panels übernimmt die AquariumGUI. In JFrames ist es
möglich, JPanels in sogenannten Layer (Schichten) übereinander anzuordnen. Damit muss nur das
Panel AquariumView aktualisiert werden und nicht der ganze Bildschirm.
Die kleinen Anzeigen der Nachbarclients erledigt die Klasse LitteAquariumOverview, die
wiederum zwei kleine Panels beherbergt, in denen jeweils die Übersicht des linken, bzw. rechten
Nachbarn angezeigt wird .
Die Hilfe des Programms und die Anzeige der kompletten Ringstruktur werden in zwei getrennten
JFrames geöffnet. Das Hilfefenster stellt einfach eine Webseite dar. Dazu sind einige Klassen aus
dem swing Paket als Unterstützung notwendig, die sind aber für eine bessere Übersicht nicht im
Klassendiagramm aufgenommen.
Im „Ringfenster“ werden die Clients im Ringverbund dargestellt. Der dahinter steckende Code ist
der gleiche wie beim P2PServer.
20
Abbildung 3.2 Klassendiagramm View
21
4 Design Peer-To-Peer
4.1 Design des P2P-Client
Abbildung 4.1 Sequenzdiagramm P2P-Client
22 Abbildung 4.2 Klassendiagramm P2P-Client
23
Alle Klassen implementieren die Schnittstelle Runnable, um nebenläufig in je einem Thread laufen
zu können. Das Kernstück der P2P-Schicht ist die Klasse P2PClient. Sie ist u.a. zuständig für das
Starten der Jxta-Platform, das Überprüfen der Nachbarschaftsbeziehungen, das Entgegennehmen
der Fische vom Aquarium bzw. Weiterleiten von ankommenden Fischen an das Aquarium. Alle
anderen Klassen sind für den Empfang und Versand von Nachrichten von/zu den jeweiligen
Nachbarn zuständig.
Über die Klasse „ObjectOutPipeChannel“ werden die Fische an den entsprechenden Nachbar
versendet. Das Gegenstück dazu – die Klasse „ObjectInPipeChannel“ ist für den Empfang der
Fische verantwortlich. Nachrichten bezüglich der Nachbarschaftsbeziehungen erledigen die Klassen
„NeighbourOutPipeChannel“ für das Versenden bzw. „NeighbourInPipeChannel“ für den Empfang
solcher Nachrichten.
Über die NeigbourChannels wird auch das Monitoring durchgeführt. Das heißt, es wird in
regelmäßigen Abständen überprüft, ob der jeweilige Nachbar noch da ist, oder ob er ausgefallen ist.
Bei einem Ausfall kommen die Klassen „BackupOutPipeChannel“ und „BackupInPipeChannel“
zum Zuge.
24
Abbildung 4.3 Sequenzdiagramm - setNeighbours(x)
In obigem Sequenzdiagramm hat Peer2 sich neu der Aquarium-Gruppe angeschlossen. Er löst bei
bereits in der Gruppe registrierten Peers ein DiscoveryEvent aus. Peer1 bekommt von Peer2 nun ein
solches DiscoveryEvent welches u.a. die PeerID von Peer2 enthält. Peer1 prüft daraufhin anhand
der PeerID ob er ein Nachbar von Peer2 ist (siehe Grobdesign). Ist dies der Fall, so sendet er Peer2
über den NeighbourOutPipeChannel eine Nachricht mit seiner eigenen PeerID und noch ob er bei
Peer2 linker oder rechter Nachbar ist. Peer2 setzt daraufhin Peer1 als neuen Nachbar, und sendet
ebenfalls eine Nachricht mit PeerID und der Nachbarschaftsbeziehung an Peer1. Peer1 setzt nach
erhalt der Nachricht Peer2 als neuen Nachbar.
25
Abbildung 4.4 Sequenzdiagramm - sendFish()
Das Aquarium ruft die Methode sendObject(x,x) des P2PClient auf mit dem zu übergebenen Fisch
als Argument. Der P2PClient verpackt den Fisch in eine Nachricht, welche er über den
ObjectOutPipeChannel dem entsprechenden Nachbar sendet.
Abbildung 4.5 Sequenzdiagramm Methode receiveFisch()
Das Ankommen von Fischen geschieht folgendermaßen. Kommt ein Fisch bei einem P2PClient an,
so löst dies bei ObjectInPipeChannel des P2PClient ein Event aus, welches die Nachricht entgegen
nimmt. Der ObjectInPipeChannel wiederum ruft die Methode receiveFish des P2PClients auf,
welcher dann den Fisch an das Aquarium weiterleitet.
26
Abbildung 4.6 Sequenzdiagramm – logout()
In dem oben abgebildeten Sequenzdiagramm besteht der P2P-Ring aus 3 Peers – dies sind Peer1,
Peer2 und Peer3. Peer1 hat als linken Nachbar Peer2 und als rechten Nachbar Peer3. Peer1 meldet
sich korrekt ab und sendet Peer2 die ID von Peer3 als neuen rechten Nachbar. Dieser setzt Peer3
anhand der ID als neuen rechten Nachbar. Peer3 bekommt von Peer1 die ID von Peer2 als neuen
linken Nachbar. Dieser setzt Peer2 als neuen linken Nachbar. Somit bleibt der Ring geschlossen.
Abbildung 4.7 Sequenzdiagramm BackupPipe
27
In diesem Szenario hat Peer2 als linken Nachbar Peer1 und Peer3 als rechten Nachbar. Durch
Monitoring hat Peer1 erkannt, dass Peer2 ausgefallen ist. Peer1 öffnet daraufhin die BackupOutPipe
und sendet über diese eine Nachricht mit seiner eigenen PeerID an den rechten Nachbarn des
ausgefallenen Clients. Die Nachricht kommt bei Peer3 auf dem BackupInputPipeChannel an, löst
ein PipeMsgEvent aus und setzt über Methodenaufruf bei P2PClient Peer1 als neuen linken
Nachbar. Peer3 sendet daraufhin eine Nachricht über den NeighbourOutPipeChannel an den
NeighbourInPipeChannel von Peer1 und wird dort über Methodenaufruf bei Peer1 als neuer rechter
Nachbar gesetzt. Somit ist die Ringstruktur wieder geschlossen.
28
4.2 Design P2P-Server
Der P2PServer ist wie die Clients Mitglied der Gruppe. Allerdings ist er nicht dem P2P-Ring
angehörig sondern beobachtet lediglich die Ringstruktur, welche in Form eines Applets abgerufen
werden kann. Damit auch die Anwendung der Clients diese Ringstruktur abbilden kann, bietet der
Server diese Struktur verpackt in einer Datei den Clients an.
Abbildung 4.8 Klassendiagramm P2P-Server
29
Die Clients können kann diese Datei abrufen und in der gleichen Art wie der Server diesen Ring
darstellen
Abbildung 4.9 Sequenzdiagramm Methode registerListener()
Der P2PServer muss sich zunächst der Gruppe „Aquarium“ anschließen. Danach registriert er sich
bei einem RendezvousService. Über den RendezVousService kann der P2PServer u.a. alle derzeit
der Gruppe „Aquarium“ angehörenden Clients herausbekommen.
Abbildung 4.10: Sequenzdiagramm Methode pollP2PRing()
Über den Methodenaufruf getConnectedPeers() bekommt der P2PServer eine Liste aller in diesem
Moment mit der Gruppe „Aquarium“ verbundenen Clients. Aus dieser Liste generiert der
P2PServer eine Datei, die allen Clients angeboten wird, damit diese aus dieser Datei die
30
Ringstruktur nachbilden können. Der Server aktualisiert die Ringstruktur der GUI anhand der
aktualisierten Liste.
31
5 Abbildungsverzeichnis
Abbildung 1.1 Klassendiagramm der Fische .......................................................................................5 Abbildung 1.2 Sequenzdiagramm der Paarung....................................................................................7 Abbildung 1.3 Fressen oder gefressen werden ... ................................................................................8 Abbildung 2.1 Klassendiagramm Aquarium .....................................................................................11 Abbildung 2.2 Sequenzdiagramm Methode init()..............................................................................12 Abbildung 2.3 Sequenzdiagramm Methode sense() ..........................................................................13 Abbildung 2.4 Sequenzdiagramm refresh() .......................................................................................14 Abbildung 2.5 Sequenzdiagramm Methode receiveInfo().................................................................15 Abbildung 2.6 Sequenzdiagramm Methode sendInfo() .....................................................................15 Abbildung 2.7 Sequenzdiagramm Methode receiveFish()................................................................16 Abbildung 2.8 Sequenzdiagramm Methode createChildren() ...........................................................17 Abbildung 3.1 Klassendiagramm Controller .....................................................................................18 Abbildung 3.2 Klassendiagramm View.............................................................................................20 Abbildung 4.1 Sequenzdiagramm P2P-Client ...................................................................................21 Abbildung 4.2 Klassendiagramm P2P-Client ....................................................................................22 Abbildung 4.3 Sequenzdiagramm - setNeighbours(x).......................................................................24 Abbildung 4.4 Sequenzdiagramm - sendFish()..................................................................................25 Abbildung 4.5 Sequenzdiagramm Methode receiveFisch()...............................................................25 Abbildung 4.6 Sequenzdiagramm – logout() .....................................................................................26 Abbildung 4.7 Sequenzdiagramm BackupPipe .................................................................................26 Abbildung 4.9 Sequenzdiagramm Methode registerListener()..........................................................29 Abbildung 4.10: Sequenzdiagramm Methode pollP2PRing() ...........................................................29