Alcatraz: Unterschied zwischen den Versionen

Aus Callooh Wiki
Zur Navigation springen Zur Suche springen
Zeile 28: Zeile 28:
Clients versuchen sich, nachdem sie ein RegistryServer Object erhalten haben, sich über dieses zu registrieren.
Clients versuchen sich, nachdem sie ein RegistryServer Object erhalten haben, sich über dieses zu registrieren.
Dazu muss lokal vom Client ein Register Object erstellt werden, und diese in der RMI Registry (via Proxy) registriert werden.  
Dazu muss lokal vom Client ein Register Object erstellt werden, und diese in der RMI Registry (via Proxy) registriert werden.  
* vom Client wird eine Register-Request Methode aufgerufen, die als Parameter die rmi-URL des Register Objekts enthält. ('''TODO:''' eventunell diesen Schritt mit Registrierung vom Register Objekt verbinden)  
* vom Client wird eine Register-Request Methode aufgerufen, die als Parameter die rmi-URL des Register Objekts enthält. ('''TODO:''' eventunell diesen Schritt mit Registrierung vom Register Objekt verbinden, also die registerRequest Methode übernimmt statt der URL das Register Objekt)  
* dieser Request wird an den Koordinator weitergeleitet
* dieser Request wird an den Koordinator weitergeleitet
* der Koordinator prüft den Request nach folgenden Voraussetzungen:
* der Koordinator prüft den Request nach folgenden Voraussetzungen:

Version vom 5. März 2011, 15:37 Uhr

Architektur des Gesamtsystems

Server Struktur

Ein Server fungiert als Koordinator, der nach dem Bully Algorithmus gewählt wird.

Registrierungs-Anfragen können an jeden der Server ergehen, allerdings müssen diese an den Koordinator weitergeleitet werden. Nur der Koordinator entscheidet ob eine Registrierung erfolgreich ist, und propagiert in diesem Fall die erfolgte Registrierung an alle Server. Dies entspricht einem Primary Based Backup Protokoll.

RMI Registry

  • Jeder Server hat eine lokale Registry.
  • Jeder Server initialisiert ein RegistryServer Object und registriert es bei seiner lokalen Registry. In weiterer Folge wird dieses RegistryServer Objekt nur auf Anweisung des als Koordinator fungierenden Servers aktualisiert.
  • Jeder Server fungiert als Registry-Proxy für die Clients (siehe RMI Proxy)

RMI Proxy

Jeder Server fungiert als RMI Proxy für einen Client. Jeder bind-Request, der an einen der Registry-Proxies ergeht, wird an den Koordinator weitergeleitet, der eine eindeutige URL vergibt, und weiters diesen Request auf alle Server repliziert.

Die RMI-Proxy Funktionalität (bind-Methode) wird vom RegistryServer Objekt bereitgestellt.

Kontaktieren des Registry Servers

Clients haben eine Liste mit RMI-URLs via Konfigurations-Datei hinterlegt. Sobald ein Client gestartet wird, versucht er mit Naming.lookup() der Reihe nach über eine der URLs ein RegistryServer Object zu erhalten.

Spezifikation des Ablaufs zwischen Client und Registrierungsserver zum Starten des Spiels

2 Phasen: Registrierungsphase und Initialisierungs-Phase.

Voraussetzung für diese Phasen ist, dass die Registrierungsserver online sind, und das RegistryServer Object in der RMI Registry registriert haben.

Registrierungsphase

Clients versuchen sich, nachdem sie ein RegistryServer Object erhalten haben, sich über dieses zu registrieren. Dazu muss lokal vom Client ein Register Object erstellt werden, und diese in der RMI Registry (via Proxy) registriert werden.

  • vom Client wird eine Register-Request Methode aufgerufen, die als Parameter die rmi-URL des Register Objekts enthält. (TODO: eventunell diesen Schritt mit Registrierung vom Register Objekt verbinden, also die registerRequest Methode übernimmt statt der URL das Register Objekt)
  • dieser Request wird an den Koordinator weitergeleitet
  • der Koordinator prüft den Request nach folgenden Voraussetzungen:
    • ist der Name des Spielers noch frei ist
    • die Maximal-Anzahl der Spieler bereits erreicht
    • ist die Registrierungsphase bereits abgeschlossen
  • der Koordinator ruft die reject oder accept Methode des Registry Objects auf, und propagiert diese Entscheidung an die anderen Server


Die Registrierungsphase läuft ab wenn:

  • eine bestimmte Zeit vergangen ist
  • die maximale Spieranzahl erreicht ist

Sobald die Registrierungsphase abgelaufen ist, beginnt die Initialisierungs-Phase. Der Beginn diese Phase wird den Clients vom Koordinator (über einen Aufruf am Request Object) mitgeteilt, und an die anderen Server propagiert.

Initialisierungs-Phase

  • Clients initialisieren ein AlcatrazClient Objekt, und registrieren dieses über den RMI-Proxy.
  • Clients übergeben diese URL an das RegistryServer Objekt (TODO: eventuell obigen Schritt und diesen in eine Methode zusammenfassen)
  • Clients erhalten URL's der AlcatrazClient Objekte ihrer Mitspieler (TODO: Testen ob nicht auch Übergabe von AlcatrazClient Referenzen möglich wäre) über eine Methode des Register Objekts, die vom Server aufgerufen wird, sobald alle URL's aller Mitspieler registriert sind.
  • Mit dem übertragen dieser URL's endet die Aufgabe des Servers, und das Spiel beginnt.
  • Clients initialisieren ein at.falb.games.alcatraz.api Object (local), rufen init() auf, registrieren die (remote)AlactrazClients der Mitspieler via addMoveListener, und rufen start() auf.

Spezifikation des Ablaufs zwischen Client und Client zum Austausch der Züge

Dem lokalen at.falb.games.alcatraz.api.Alcatraz Objekt werden Listener Objekte (remote AlcatrazClient Objekte) der anderen Spieler mit der addMoveListener Methode hinzugefügt.

Wird die moveDone Methode (remote, d.h. von einem anderen Client) aufgerufen, muss die (lokale) doMove Methode am lokalen Alcatraz Objekt aufgerufen werden, damit auch am GUI der Zug des Players sichtbar wird.

TODO: Was soll passieren wenn einer der Clients eine Zeit lang nix tut? - eventuell Methode void playerLeftGame(Player player) vorsehen, die aufgerufen werden kann. Jeder setzt Timer nach seinem Zug, und wenn eine Zeit lang die moveDone Methode vom nächsten Player nicht aufgerufen wurden, wird die playerLeftGame() Methode auf allen (remote) AlcatrazClient Objekte aufgerufen

Spezifikation der Mechanismen um Serverausfälle tolerieren zu können

  • RMI Registry ist redundant
  • RegistryServer Object ist redundant. Registrierungen eines Clients werden über ein mit Spread implementiertes Primary Backup Protokoll redundant gehalten.
  • Koordinator mittels Election nach Bully Algorithmus

TODO: abklären ob rmiregistry eventuell geclone't werden kann - dann könnten ausgefallene server einen restore machen. falls das nicht geht ist ein ausgefallener server für immer weg !!

Remote Interface-Definition des Registrierungsservers (inkl. typisierten Methodenparametern)

RegistryServer

  • String bind(java.RMI.Remote remote)
  • void registerRequest(URL url)
  • void setGameClient(URL url)

Register

  • String getPlayerName()
  • void accept()
  • void deny()
  • void startInitPhase()
  • void startGame(URL[] urls)

Remote Interface-Definition des Game Clients (inkl. typisierten Methodenparametern)

AlcatrazClient:

  • void gameWon(Player player)
  • void moveDone(Player player, Prisoner prisoner, int rowOrCol, int row, int col)


Code

public interface BindProxyInterface extends java.rmi.Remote {

	String bind(java.rmi.Remote t, String ObjectName)
		throws java.rmi.RemoteException, java.net.MalformedURLException;
}


import java.rmi.Naming;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.RemoteException;

public class BindProxy extends UnicastRemoteObject implements BindProxyInterface {
 
	public BindProxy() throws java.rmi.RemoteException { 
		super();
	}
	
	public String bind(java.rmi.Remote t, String ObjectName)
		throws java.rmi.RemoteException, java.net.MalformedURLException {
		
		Naming.rebind("rmi://localhost:1099/" + ObjectName, t);
		return "rmi://localhost:1099/" + ObjectName;
	}
}


import java.rmi.Naming;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.RemoteException;

class BindServer  {
	
	public static void main(String args[]) {
	
		try {
			BindProxy b = new BindProxy();
			Naming.rebind("rmi://localhost:1099/BindProxy", b);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}


import java.rmi.Naming;
import java.rmi.NotBoundException;

public class BindClient {

	private final static String ObjectName = "testi";
	
	public static void main(String args[]) {
		BindProxyInterface b = null;
		try {
			b = (BindProxyInterface)Naming.lookup("rmi://localhost:1099/BindProxy");
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		if (b==null) return;
		
		String url = null;
		try {
			TestObject o = new TestObject(692);
			url = b.bind(o, ObjectName);
			System.out.println("proxy hat url registriert unter: " + url);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		if (url==null) {
			System.out.println("URL is null!!");
			return;
		}
		
		TestInterface o = null;
		try {
			o = (TestInterface)Naming.lookup(url);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		if (o==null) {
			System.out.println("testobject is null!!");
		} else {
			try {
				System.out.println("id ist "  + o.getId());
			} catch (java.rmi.RemoteException e) {
				e.printStackTrace();
			}
		}
		return;
	}

}

Links

Alcatraz Javadoc