Höhere Programmierkonzepte Praktikum IV Verteilte

Werbung
Höhere Programmierkonzepte
Praktikum IV
Verteilte Programmierung
Prof. Dr. Nikolaus Wulff
11. – 20. Dez 2012
1
Verteilte Dienste mit RMI
Ziel diesen Praktikums ist es, die Bibliothek aus Praktikum III als verteilten
Dienst anzubieten. Die Schnittstelle java.rmi.Remote kennzeichnet beliebige, verteilbare Java RMI Objekte, die per TCP/IP im Intra- und oder Internet erreichbar sind. Der Quelltext (1) definiert eine generische Schnittstelle,
die sich der RMI Architektur bedient.
package de.lab4inf.lab4;
/∗∗
∗ Common interface for an arbitrary, generic remote service.
∗
∗ @param <T> task to accomplish
∗ @param <A> arguments for the task
∗ @param <R> return object from the task
∗/
public interface Service<T,A,R> extends java.rmi.Remote {
/∗∗
∗ Every service has it ’s unique name.
∗ @return name of service
∗ @throws RemoteException in case of an error
∗/
String getName() throws java.rmi.RemoteException;
/∗∗
∗ Execute the given task within the service .
∗ @param task T to execute
∗ @param args arguments A of the task
∗ @return the result R calculated with T and A.
∗ @throws RemoteException in case of an error
∗/
R execute(T task,A ... args) throws java.rmi.RemoteException;
}
Listing 1: Generische Java Schnittstelle für einen beliebigen RMI Service.
1
package de.lab4inf.lab4;
import java.rmi.∗;
/∗∗
∗ Simple client of the EchoService.
∗/
public class EchoClient {
public static void main(String[] args) throws Exception {
Service<String,String,String> service;
String t ,a,r , url = ”//localhost/EchoService”;
service = (Service<String,String,String>) Naming.lookup(url);
t = ”hello world”;
a = ”top secret”;
System.out.printf(”service .execute(%s,%s) \n”,t,a);
r = service.execute(t,a);
System.out.printf(”returned: %s \n”,r);
}
}
Listing 2: Ein einfacher Client für den EchoService.
Java Klassen, welche die Serviceschnittstelle (1) implementieren, können
mittels Java RMI im TCP/IP Netzwerk erreich- und aufrufbar sein.
Im Quelltext (3) des Anhangs finden Sie eine einfache Implementierung eines EchoService, der sich beim Start seiner main-Funktion bei der
RMI Registry mit dem Aufruf Naming.rebind registriert und auf einkommende Anfragen wartet. Der EchoService erwartet als Task T und Argument A eine Zeichenkette, die er leicht modifiziert an den Aufrufenden
als Ausgabe R zurückliefert. Obiger Quelltext (2) zeigt einen Klienten des
EchoService, der per RMI versucht auf die Serviceschnittstelle zuzugreifen.
Per Naming.lookup erhält der Klient von der RMI Registry eine Referenz auf
einen Service und kann dessen execute Methode aufrufen.
Beachten Sie, wie der EchoService zugleich die Service-Schnittstelle
implementiert und die java.rmi.server.UnicastRemoteObject Basisklasse erweitert. Letzteres erlaubt es den Service innerhalb der main-Funktion bei
der RMI Registry unter Port 1099 anzumelden und im Netz per TCP/IP
zur Verfügung zu stellen. Basisfunktionalität eines RemoteServers wird ohne größeren Programmieraufwand durch Vererbung bereitgestellt.
Aufgabe
Aufgabe ist es nun den Differenzierer und den Integrierer des letzten Praktikums als zwei verteilte Services erreichbar zu machen, so dass diese in
unterschiedlichen Prozessräumen aufrufbar sind.
Nach Vorlage des EchoService werden der DifferentiatorService
und der IntegratorService entwickelt. Diese ”umwickeln” als Wrapper
die schon existierenden Differentiator und Integrator Klassen und ma2
chen sie remote-fähig, ohne das Differentiator und Integrator oder die
C/C++ Bibliothek verändert werden müssen.
1. Erstellen Sie den EchoService und den EchoClient und führen Sie
diese in der Reihenfolge EchoService, EchoClient in zwei getrennten
Konsolen auf Ihrem Rechner aus.
2. Sobald Server und Client zufriedenstellend laufen schreiben Sie nach
der Vorlage des EchoClient einen JUnitTest, um den Service automatisiert zu testen.
3. Nachdem der JUnit Test läuft nehmen Sie ein Refactoring vor. Zerlegen Sie den Test in eine abstrakte Basisklasse und einen konkreten
Anteil für den EchoServiceTest. D.h. faktorisieren Sie die Anteile,
die sich nicht direkt auf den EchoService beziehen in einen abstract
class BasicServiceTest<T,R,A> JUnit Test. Diese generische Basisklasse – mit den selben Generics T,R,A wie der Service – dient als
Elternklasse für die weiteren zu erstellenden Testklassen.
4. Erst wenn das Echo-Beispiel per RMI läuft, lohnt es sich an die Bereitstellung und Entwicklung weiterer Services zu denken. Erstellen
Sie den DifferentiatorService, der den Differentiator des letzten Praktikums kapselt und auf Verlangen ausführt und testen Sie ihn
durch Erweiterung des BasicServiceTest<T,R,A> mit einer entsprechend typisierten DifferentiatorServiceTest Klasse.
5. Erstellen Sie einen Service IntegratorService, der den Integrator
des letzten Praktikums kapselt und auf Verlangen ausführt und schreiben Sie auch hierzu einen passenden IntegratorServiceTest.
Tip
Denken Sie daran, bei den Tests wieder den Systempfad für die JNI Bibliothek mit anzugeben.
Die Bindung des EchoService ist <T,R,A>=<String,String,String>
entsprechend gelten für den Differentiator- und den IntegratorService
<T,R,A>=<Function,Double,Double>, so dass sowohl die Function als auch
die Argumente vom Type double übergeben werden können.
Voraussetzung für die Übergabe von Argumenten per RMI ist, dass diese
Java Primitive sind oder aber die java.io.Serializable Schnittstelle implementieren, d.h. die Funktionen müßen serialisierbar deklariert sein.
3
package de.lab4inf.lab4;
import java.rmi.registry.∗;
/∗∗
∗ Echo RMI Service.
∗/
public class EchoService extends java.rmi.server.UnicastRemoteObject
implements Service<String, String, String> {
/∗∗
∗ Sole RMI constructor.
∗/
public EchoService() throws java.rmi.RemoteException {}
/∗ (non−Javadoc)
∗ @see de.lab4inf . lab4 . Service#getName()
∗/
@Override
public String getName() throws java.rmi.RemoteException {
return ”EchoService”;
}
/∗ (non−Javadoc)
∗ @see de.lab4inf . lab4 . Service#execute(java.lang.Object, A[])
∗/
@Override
public String execute(String task, String ... args)
throws java.rmi.RemoteException {
return String.format(”Echo => %s [%s]”,task,args[0]);
}
}
/∗∗
∗ Start and register the service .
∗/
public static void main(String[] args) throws Exception {
String url = ”//localhost/EchoService”;
Registry registry = LocateRegistry.createRegistry(1099);
EchoService service = new EchoService();
Naming.rebind(url, service) ;
System.out.printf(”Service %s registered\n”,url) ;
}
Listing 3: Ein einfacher EchoService verteilt per RMI.
4
Herunterladen