Zurück zum Manuskript
// Datei: TelefonbuchServer.java // Autor: Werner Brecht // Datum: 25.07.2018 // Thema: Ein Telefonbuchserver, der einen Web-Browser als // Benutzerschnittstelle verwendet und per RMI zwei // Telefonbücher in den beiden Abteilungen Einkauf und // Vertrieb nebenläufig abfragt. // // In den beiden Abteilungen wird // (1) das Telefonbuch aus der ersten Übungsaufgabe // übernommen und die Name-Nummer-Liste an die // jeweilige Abteilung angepasst. // (2) ein Abteilungsserver implementiert, der die RMI- // Aufrufe bearbeitet und auf das jeweilige // Telefonbuch zugreift. // // Der Telefonbuchserver aus der zweiten Aufgabe wird um // die Methode verteileAbfrage() erweitert, die neben- // läufig (mit Threads) die RMI-Aufrufe startet. // // Eine Beschreibung der Arbeitsweise des Programms ist // beim Grobentwurf des Lösungsbeispiels zur dritten // Aufgabe zu finden. // // Beim Programmstart sind die Rechnernamen der beiden // Abteilungsserver als Params (e: Einkauf, v: Vertrieb) // anzugeben: // java TelefonbuchServer e=... v=... // Ihre Reihenfolge spielt keine Rolle. // ============================================================= import java.util.*; import java.io.*; import java.util.regex.*; import java.net.*; import java.rmi.*; class TelefonbuchServer { // Globale Variablen: Rechnernamen der Abteilungsserver // Registry-Ports der Abteilungsserver // Listen für die Ergebnisse der Threads, // die auf die Abteilungen zugreifen // ----------------------------------------------------------- static String abtHostE = null; // Abteilung Einkauf static int regPortE = 0; static String abtHostV = null; // Abteilung Vertrieb static int regPortV = 0; static ArrayList<String> thrE = new ArrayList<String>(); static ArrayList<String> thrV = new ArrayList<String>(); public static void main(String[] args) throws Exception { // Parameterauswertung // --------------------------------------------------------- if(args.length != 2) { System.out.println(); System.out.println("=================================="); System.out.println("Aufruf mit 2 Params: e=... v=..."); System.out.println(" Abteilungsserver angeben!"); System.out.println("=================================="); System.out.println(); System.exit(0); } if(! ( ( (args[0].startsWith("e") || args[0].startsWith("E")) & (args[1].startsWith("v") || args[1].startsWith("V")) ) || ( (args[0].startsWith("v") || args[0].startsWith("V")) & (args[1].startsWith("e") || args[1].startsWith("E")) ) ) ) { System.out.println(); System.out.println("================================="); System.out.println("Parameter sind falsch aufgebaut:"); System.out.println(" e=HostnameEink v=HostnameVertr"); System.out.println("================================="); System.out.println(); System.exit(0); } if(args[0].startsWith("e") || args[0].startsWith("E")) { abtHostE = args[0]; abtHostV = args[1]; } else { abtHostE = args[1]; abtHostV = args[0]; } if(abtHostE.startsWith("e")) abtHostE = abtHostE.replace("e=", ""); else abtHostE = abtHostE.replace("E=", ""); if(abtHostV.startsWith("v")) abtHostV = abtHostV.replace("v=", ""); else abtHostV = abtHostV.replace("V=", ""); // Registry-Ports festlegen: // Einkauf -> E -> 69 -> 60069 // Vertrieb -> V -> 86 -> 60086 // --------------------------------------------------------- regPortE = 60069; regPortV = 60086; // Laufen die Abteilungsserver? // Nein -> Abbruch // Ja -> Oben eintragen // --------------------------------------------------------- System.out.println(); System.out.println("Zentraler Telefonbuchserver ist aktiv"); System.out.println("-------------------------------------"); System.out.println(); System.out.println ("ACHTUNG: Der Server kann nur arbeiten,"); System.out.println (" wenn beide Abteilungsserver laufen!"); System.out.println(); System.out.println(" Ist dies der Fall?"); System.out.print(" Eingabe: (j/n)->"); BufferedReader br = new BufferedReader( new InputStreamReader(System.in)); String ein = br.readLine(); if(!(ein.equals("")||ein.equals("j")||ein.equals("J"))) { System.out.println(); System.out.println("=================================="); System.out.println("Bitte die Abteilungsserver starten"); System.out.println("und Programm erneut aufrufen!"); System.out.println("================================="); System.out.println(); System.exit(0); } // Ergebnisliste bereitstellen und ServerSocket am Port 9876 // erzeugen // --------------------------------------------------------- ArrayList<String> erg = new ArrayList<String>(); erg.add("Anfang"); String qs = "Anfang"; int serverport = 9876; ServerSocket ss = new ServerSocket(serverport); Socket cs = null; // Start des zentralen Telefonbuchservers // --------------------------------------------------------- String host = InetAddress.getLocalHost().getHostName(); System.out.println(); System.out.println("Abteilungen: Einkauf, Vertrieb"); System.out.println("Host : " + host); System.out.println("Port : " + serverport); System.out.println(); // GET-Requests des Browsers entgegennehmen und analysieren. // Ggf. Query String erzeugen und Suchvorgänge starten. // Ergebnis ausgeben. // --------------------------------------------------------- while(true) { if(erg.get(0).equals("Beendet")) break; if(! qs.equals("Favicon")) System.out.println("Warte auf Browser-Requests"); cs = ss.accept(); // Auf Browser Requests warten qs = vomBrowser(cs); if(qs.equals("Favicon")) { cs.close(); continue; } System.out.println("Query String vom Browser -> " + qs); erg = analyse(qs); zumBrowser(cs, erg); cs.close(); } ss.close(); } // main() // ============================================================= static String vomBrowser(Socket cs) throws Exception { // Aus dem Socket cs lesen, Query String ausblenden // --------------------------------------------------------- BufferedReader br = new BufferedReader( new InputStreamReader(cs.getInputStream())); String qs = br.readLine(); // Favicon-Requests ignorieren (kein Query String) // --------------------------------------------------------- if(qs.startsWith("GET /favicon.ico")) return "Favicon"; // Leitseite wird angefordert: qs=Anfang // --------------------------------------------------------- if(qs.startsWith("GET / H")) return "Anfang"; // Benutzer hat Beenden gewählt // --------------------------------------------------------- if(qs.contains("&ende=Beenden")) return "Ende"; // Query String ausblenden // --------------------------------------------------------- qs = qs.replace("GET ", ""); qs = qs.replace(" HTTP/1.1", ""); qs = qs.replace("/?", ""); return qs; } // vomBrowser() // ============================================================= static ArrayList<String> analyse(String qs) throws Exception { // Query String qs kann sein (* = mögliche Benutzereingabe): // Anfang // Ende // name=*&nummer=* (ev. nur 1 *) // // Ergebnisliste und Hilfsvariablen anlegen // --------------------------------------------------------- ArrayList<String> ksuErg = new ArrayList<String>(); // Query Strings, die das Telefonbuch nicht ansprechen // (1) Dialogbeginn // --------------------------------------------------------- if(qs.equals("Anfang")) { ksuErg.add("Anfang"); return ksuErg; } // (2) Dialogende // --------------------------------------------------------- if(qs.equals("Ende")) { ksuErg = verteileAbfrage(qs); return ksuErg; } // (3) Leere Eingaben // --------------------------------------------------------- if(qs.equals("name=&nummer=")) { ksuErg.add("Leere Eingabe"); return ksuErg; } // Die URL-Kodierung rückgängig machen. // Das Programm ist unter Windows-7 entwickelt worden. // --------------------------------------------------------- qs = URLDecoder.decode(qs, "ISO-8859-1"); // (4) Syntaktisch falsche Eingaben // Fehler mit & bzw. mit = // --------------------------------------------------------- String regex = "^[^&]*&[^&]*$"; if(! qs.matches(regex)) { ksuErg.add("Syntaxfehler"); return ksuErg; } regex = "^[^=]+=[^=]+=[^=]*$"; if(! qs.matches(regex)) { ksuErg.add("Syntaxfehler"); return ksuErg; } // Der Query String ist korrekt aufgebaut und nicht leer, // aber noch nicht in der Form für das Telefonbuch: // name=*&nummer=* (ev. nur 1 *) // Er wird umgewandelt und per RMI an die Abteilungsserver // übergeben. // --------------------------------------------------------- String[] token = null; String name = null; // zu suchender Name String nummer = null; // zu suchende Nummer String kqs = null; // Korrekt aufgebauter Query String token = qs.split("&"); name = token[0].replace("name=", ""); nummer = token[1].replace("nummer=", ""); kqs = name + "&" + nummer; // Kumilierte Suchergebnislisten // --------------------------------------------------------- ksuErg = verteileAbfrage(kqs); return ksuErg; } // analyse() // ============================================================= static ArrayList<String> verteileAbfrage(String kqs) throws Exception { class VerteilerThread extends Thread { String abteilung = null; String kqs = null; VerteilerThread(String abt, String kqs) { this.abteilung = abt; this.kqs = kqs; } public void run() { String kennung = "rmi://"; RmiDekl dekl = null; try { if(abteilung.equals("Einkauf")) { kennung = kennung + TelefonbuchServer.abtHostE + ":" + TelefonbuchServer.regPortE + "/RmiAbfrage"; dekl = (RmiDekl)Naming.lookup(kennung); if(kqs.equals("Ende")) dekl.beende(); else TelefonbuchServer.thrE = dekl.frageTbuch(kqs); } else { kennung = kennung + TelefonbuchServer.abtHostV + ":" + TelefonbuchServer.regPortV + "/RmiAbfrage"; dekl = (RmiDekl)Naming.lookup(kennung); if(kqs.equals("Ende")) dekl.beende(); else TelefonbuchServer.thrV = dekl.frageTbuch(kqs); } } catch(Exception e) {} } // run() } // Lokale Klasse ArrayList<String> ksuErg = new ArrayList<String>(); VerteilerThread vtE = new VerteilerThread("Einkauf", kqs); VerteilerThread vtV = new VerteilerThread("Vertrieb", kqs); vtE.start(); vtV.start(); vtE.join(); vtV.join(); if(kqs.equals("Ende")) ksuErg.add("Beendet"); else { for(String s : thrE) ksuErg.add(s+"&Einkauf"); for(String s : thrV) ksuErg.add(s+"&Vertrieb"); ksuErg.add("Suche"); } return ksuErg; } // verteileAbfrage() // ============================================================= static void zumBrowser(Socket cs, ArrayList<String> erg) throws Exception { int len = erg.size(); if(len == 1) { String art = erg.get(0); // Fälle, bei denen keine Suche gestartet wurde // --------------------------------------------------------- if(art.equals("Anfang")) { schreibeKopf(cs); schreibeForm(cs); return; } if(art.equals("Beendet")) { schreibeKopf(cs); schreibeEnde(cs); return; } if(art.equals("Leere Eingabe")) { schreibeKopf(cs); schreibeLeer(cs); schreibeForm(cs); return; } if(art.startsWith("Syntaxfehler")) { schreibeKopf(cs); schreibeSyntax(cs); schreibeForm(cs); return; } } // Suche wurde gestartet: Finde (ev. leer bis auf Suche) // Meier&4711&Einkauf // ... // Suche // --------------------------------------------------------- schreibeKopf(cs); if(len == 1) schreibeOhne(cs); else schreibeErg(cs, erg, len); schreibeForm(cs); } // zumBrowser() // ============================================================= // HTTP-Kopf und Anfang der HTML-Seite in den Socket schreiben // ----------------------------------------------------------- static void schreibeKopf(Socket cs) throws Exception { PrintWriter pw = new PrintWriter(cs.getOutputStream()); pw.println("HTTP/1.1 200 OK"); pw.println("Content-Type: text/html"); pw.println(); pw.println("<html>"); pw.println("<body>"); pw.flush(); } // schreibeKopf() // ============================================================= // HTML-Form und Seitenende in den Socket schreiben // ----------------------------------------------------------- static void schreibeForm(Socket cs) throws Exception { PrintWriter pw = new PrintWriter(cs.getOutputStream()); pw.println("<h2 align=center>Telefonbuchabfrage</h2>"); pw.println("<h3>Sie können nach einem Namen oder nach " +"einer Nummer<br>oder (nebenläufig) nach " +"beidem suchen.<br>In Ihren Eingaben darf kein &" +" und kein = vorkommen!</h3>"); String host = InetAddress.getLocalHost().getHostName(); int port = cs.getLocalPort(); String url = "http://"+host+":"+port; pw.println("<form method=get action=\"" + url + "\">"); pw.println("<table>"); pw.println("<tr>"); pw.println("<td>Name:</td>"); pw.println("<td><input name=name></td>"); pw.println("<td></td>"); pw.println("</tr>"); pw.println("<tr>"); pw.println("<td>Nummer:</td>"); pw.println("<td><input name=nummer></td>"); pw.println("<td></td>"); pw.println("</tr>"); pw.println("<tr>"); pw.println("<td><input type=submit value=Abschicken></td>"); pw.println("<td><input type=reset></td>"); pw.println("<td><input type=submit name=ende value=Beenden></td>"); pw.println("</tr>"); pw.println("</table>"); pw.println("</form>"); pw.println("</body>"); pw.println("</html>"); pw.flush(); } // schreibeForm() // ============================================================= // HTML-Endeseite in den Socket schreiben // ----------------------------------------------------------- static void schreibeEnde(Socket cs) throws Exception { PrintWriter pw = new PrintWriter(cs.getOutputStream()); pw.println("<h2>Ende der Telefonbuchabfrage</h2>"); pw.println("<h2>Auf Wiedersehen!</h2>"); pw.println("</body>"); pw.println("</html>"); pw.flush(); } // schreibeEnde() // ============================================================= // Schreiben bei leeren Eingaben // ----------------------------------------------------------- static void schreibeLeer(Socket cs) throws Exception { PrintWriter pw = new PrintWriter(cs.getOutputStream()); pw.println("<h2>Ihre Eingaben waren leer!</h2>"); pw.println("<h2>   Bitte wiederholen!</h2>"); pw.println("<h2>====================================</h2>"); pw.println("<br>"); pw.flush(); } // schreibeLeer() // ============================================================= // Schreiben bei Syntaxfehler // ----------------------------------------------------------- static void schreibeSyntax(Socket cs) throws Exception { PrintWriter pw = new PrintWriter(cs.getOutputStream()); pw.println("<h2>Ihre Eingaben waren fehlerhaft!</h2>"); pw.println("<h2>Bitte kein & und kein = eingeben!</h2>"); pw.println("<h2>====================================</h2>"); pw.println("<br>"); pw.flush(); } // schreibeSyntax() // ============================================================= // Schreiben bei leerem Ergebnis // ----------------------------------------------------------- static void schreibeOhne(Socket cs) throws Exception { PrintWriter pw = new PrintWriter(cs.getOutputStream()); pw.println("<h2>Ihre Suche hatte leider keine Treffer!</h2>"); pw.println("<h2></h2>"); pw.println("<h2>====================================</h2>"); pw.println("<br>"); pw.flush(); } // schreibeOhne() // ============================================================= // Schreiben bei nicht leerem Ergebnis // Meier&4711&Einkauf // ----------------------------------------------------------- static void schreibeErg(Socket cs, ArrayList<String> erg, int len) throws Exception { String[] token = null; PrintWriter pw = new PrintWriter(cs.getOutputStream()); pw.println("<h2>Ihre Suche hat folgendes Ergebnis:</h2>"); pw.println("<h2></h2>"); len--; pw.println("<table>"); pw.println("<tr><th>Name</th><th>Nummer</th>" + "<th>Abteilung</th></tr>"); for(int i=0; i<len; i++) { token = erg.get(i).split("&"); pw.println("<tr><td>" + token[0] + "</td>"); pw.println(" <td>" + token[1] + "</td>"); pw.println(" <td>" + token[2] + "</td></tr>"); } pw.println("</table>"); pw.println("<h2>====================================</h2>"); pw.flush(); } // schreibeErg() } // class

Zurück zum Manuskript