Prof. Dr. Dr. h.c. M. Broy Lösungsblatt 11 Dr. H. Ehler, S. Wagner 23. Januar 2004 Übungen zu Softwaretechnik Aufgabe 16 Qualitätseigenschaften Broker-Pattern Beurteilen Sie das in Aufgabe 15 benutzte Broker-Pattern hinsichtlich seiner Qualitätseigenschaften. Funktionalität: Erlaubt sehr flexible Systemarchitektur Zuverlässigkeit: Problematisch ist, das der Broker selbst einen Single-Point-of- Failure darstellt, d.h. wenn der Broker ausfällt, fällt das ganze System aus. Benutzbarkeit: einfach und übersichtlich Effizienz: leichte Laufzeitverschlechterung, da zusätzliche Verarbeitung durch Broker Änderbarkeit und Übertragbarkeit: einfach möglich, da gute Kapselung Aufgabe 17 Implementierung / Middleware Das in Aufgabe 15 entworfene City Information System soll in implementiert werden. a) Entwickeln Sie eine Implementierung in Java (oder C++,...) unter der stark vereinfachenden Annahme, dass sich alle Objekte auf einem Rechner befinden werden und die Server alle gleichartig sind. Details wie Threads usw. müssen nicht ausprogrammiert werden. Stützen Sie sich dabei vor allem auf die Abläufe, die in den MSCs spezifiziert wurden. Eine sehr einfache Möglichkeit dies zu realisieren wäre eine Abbildung auf das WWW, da das zu entwickelnde System webbasiert ist. Man könnte die WWW- Infrastruktur selbst bereits als Broker-Pattern auffassen. Der WWW-Browser übernimmt die Rolle des Client und Client-Side Proxy. Der Broker ist dabei der Internet-Gateway und Namensservice und schliesslich die Server und Server-Side Proxies entsprechen HTTP-Servern. Um die Realisierung interessanter zu gestalten (und um zu vermeiden, dass die Benutzer sich URLs merken müssen), werden wir das Broker-Pattern aber anders anwenden. Die Rolle des Brokers wird der HTTP-Server, mit dem die Browser kommunizieren spielen, der wiederum andere Server benutzt, um Anfragen zu beantworten. Zuerst wollen wir eine einfache Implementierung der Nachrichten, spezialisiert in Anfragen (Request) und Antworten (Response) angeben. Ausserdem wird noch eine Klasse für die Addresse des Clients benötigt. public class Message { private String data; 1
public ClientAddress client; public Message(String data) { this.data = data; public String getdata() { return data; public boolean isrequest() { return (false); /* Message */ public class Request extends Message { private String data; public String service; public Request(String data) { super(data); public boolean isrequest { return (true); /* Request */ public class Response extends Message { private String data; public Response(String data) { super(data); public boolean isrequest() { return (false); /* Response */ public class ClientAddress { public String ipaddress; public String port; 2
Der Broker nimmt also HTTP-Anfragen entgegen, leitet die Anfrage weiter und reicht die Antwort zurück. Dazu sind natürlich mehrere Threads notwendig, um dies nebenläufig zu machen. Details dazu wurden aber weggelassen. public class Broker { private static Vector serverproxies; private static Bridge bridge; // private static Vector servers; public Broker() { bridge = new Bridge(this); serverproxies = new Vector(); clients = new Vector(); private void maineventloop() { // Kuemmert sich um Thread-Verwaltung private void updaterepository(serverproxy proxy) { // evtl. Test, ob schon vorhanden serverproxies.add(proxy); public String registerservice(serverproxy proxy, String service) { // evtl. Sicherheitsmechanismus updaterepository(proxy); return ("acknowledgment"); private ServerProxy findserver(request request) { // Server entsprechenden dem Request aus Vektor suchen return (proxy); private ClientAddress findclient(response response) { return (response.client); public void forwardrequest(request request) { ServerProxy server = findserver(request); server.callservice(request); // asynchron public void forwardresponse(response response) { Client client = findclient(response); // Response per HTTP an Client schicken 3
public static void main(string[] argv) { maineventloop(); /* Broker */ Der Broker benutzt eine Bridge, um mit möglichen anderen Brokern zu kommunizieren. Die Verwaltung der Referenzen zu anderen Bridges wurde weggelassen. public class Bridge { private Broker broker; private Vector bridges; public Bridge(Broker broker, Vector bridges) { this.broker = broker; this.bridges = bridges; private Message packdata(message message) { // Daten packen return (message); private Message unpackdata(message message) { // Daten entpacken return (message); private bridge findbridge(message message) { // Bridge entsprechend Client oder Dienst suchen return (bridge); public void forwardmessage(message message) { message = packdata(message); Bridge bridge = findbridge(message); bridge.transmitmessage(message); // asynchron public void transmitmessage(message message) { message = unpackdata(message); if (message.isrequest()) { broker.forwardrequest((request) message); // asynchron else { broker.forwardresponse((response) message); // asynchron /* Bridge */ 4
Die Server sind derzeit alle gleich strukturiert. In einer realen Implementierung müssten natürlich verschiedene Server abgeleitet werden, die verschiedene Dienste erbringen. public class Server { private static Broker broker; private static Vector serverproxies; public Server(Broker broker) { ServerSideProxy proxy = new ServerSideProxy(this, broker); Vector serverproxies = new Vector(); serverproxies.add(proxy); initialize(broker, serverproxies); private void initialize(broker broker, Vector serverproxies) { this.broker = broker; this.serverproxies = serverproxies; // Weitere Initialisierungen private void entermainloop() { // Thread-Verwaltung public Response runservice(request request) { // Request verarbeiten return (response); public static void main(string argv[]) { entermainloop(); /* Server */ Der Server benutzt einen Server-Proxy zur Kommunikation mit dem Broker. public class ServerSideProxy { private Broker broker; private Server server; public ServerSideProxy(Server server, Broker broker) { this.broker = broker; this.server = server; private Request unpackdata(request request) { 5
// Daten entpacken return (request); private Response packdata(response response) { // Daten packen return (response); public void callservice(request request) { request = unpackdata(request); Response response = server.runservice(request); response = packdata(response); broker.forwardresponse(response); // asynchron /* ServerSideProxy b) Skizzieren Sie, wie Sie die Implementierung aus a) in eine verteilte Umgebung mit einer Middelware wie CORBA (oder JavaRMI,...) übertragen würden. Zur Übertragung in ein verteiltes System müssen verschiedene Überlegungen angestellt werden: Identifizierung der aktiven Objekte, also Objekte mit eigenem Kontrollfluss. Dies wurde in a) bereits teilweise gemacht. Beispiele: Broker, Server Verteilung der Objekte auf die Netzwerkknoten. Beispiele: Broker auf Host fred.in.tum.de, Server auf barnie.in.tum.de Anbindung an Middleware, also bei CORBA müssen die Schnittstellen mittels der Interface Description Language (IDL) beschrieben werden. Daraus können Stubs und Skeletons generiert werden, die benutzt werden, um die entfernte Kommunikation zu ermöglichen. Festlegung weiterer Dienste, z.b. Namensdienst von CORBA vs. feste Namensgebung 6