// Datei: TelefonbuchServer.java
// Autor: Werner Brecht
// Datum: 24.07.2018
// Thema: Ein Telefonbuchserver, der einen Web-Browser als
// Benutzerschnittstelle verwendet.
//
// Der Server hat eine Socketschnittstelle und eine
// Analysemethode.
//
// Die Socketschnittstelle besteht aus den beiden
// Methoden vomBrowser() und zumBrowser(). Die
// Analysemethode heißt analyse().
//
// Eine Beschreibung der Arbeitsweise des Servers findet
// sich im Grobentwurf des Lösungsbeispiels zur
// Aufgabe 2.
// =============================================================
import java.util.*;
import java.io.*;
import java.util.regex.*;
import java.net.*;
class TelefonbuchServer {
public static void main(String[] unused) throws Exception {
// Ergebnisliste bereitstellen und ServerSocket am Port 9876
// erzeugen.
// ---------------------------------------------------------
ArrayList<String> erg = new ArrayList<String>();
erg.add("Anfang");
String qs = null;
int serverport = 9876;
ServerSocket ss = new ServerSocket(serverport);
Socket cs = null;
// Serverstart
// ---------------------------------------------------------
String host = InetAddress.getLocalHost().getHostName();
System.out.println("\nTelefonbuchserver auf Host " + host +
" am Port "+serverport);
// GET-Requests des Browsers entgegennehmen und analysieren.
// Ggf. Query String erzeugen und Suchvorgänge starten.
// Ergebnis ausgeben.
// ---------------------------------------------------------
while(true) {
if(erg.get(0).equals("Ende")) break;
if(! erg.get(0).equals("Favicon")) {
System.out.println("Warte auf Request");
}
cs = ss.accept(); // Auf Browser Requests warten
qs = vomBrowser(cs);
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();
if(! qs.contains("/favicon.ico"))
System.out.println("vom Browser->"+qs);
qs = qs.replace("GET ", "");
qs = qs.replace(" HTTP/1.1", "");
if(qs.equals("/")) return qs;
if(qs.equals("/favicon.ico")) return qs;
qs = qs.replace("/?", "");
return qs;
} // vomBrowser()
// =============================================================
static ArrayList<String> analyse(String qs) throws Exception {
// Ergebnisliste und Hilfsvariablen anlegen
// ---------------------------------------------------------
ArrayList<String> erg = new ArrayList<String>();
String regex = null;
String[] token = null;
String name = null; // Eingegebener Name
String nummer = null; // Eingegebene Nummer
String kqs = null; // Korrekt aufgebauter Query String
// Query Strings, die das Telefonbuch nicht ansprechen
// (1) Dialogbeginn
// ---------------------------------------------------------
if(qs.equals("/")) {
erg.add("Anfang");
return erg;
}
// (2) Dialogende
// ---------------------------------------------------------
if(qs.endsWith("&ende=Beenden")) {
erg.add("Ende");
return erg;
}
// (3) Favicon
// ---------------------------------------------------------
if(qs.equals("/favicon.ico")) {
erg.add("Favicon");
return erg;
}
// (4) Leere Eingaben
// ---------------------------------------------------------
if(qs.equals("name=&nummer=")) {
erg.add("Leere Eingabe");
return erg;
}
// URL-Kodierung rückgängig machen.
// Das Programm ist unter Windows-7 entwickelt worden
// ---------------------------------------------------------
qs = URLDecoder.decode(qs, "ISO-8859-1");
// (5) Syntaktisch falsche Eingaben
// (5.1) Fehler mit &
// ---------------------------------------------------------
regex = "^[^&]*&[^&]*$";
if(! qs.matches(regex)) {
erg.add("Syntaxfehler");
return erg;
}
// (5) Syntaktisch falsche Eingaben
// (5.2) Fehler mit =
// ---------------------------------------------------------
token = qs.split("&");
name = token[0].replace("name=", "");
nummer = token[1].replace("nummer=", "");
if(name.contains("=") || nummer.contains("=")) {
erg.add("Syntaxfehler");
return erg;
}
// Der Query String ist korrekt aufgebaut. Jetzt werden das
// Telefonbuch erzeugt, die dortigen Ergebnislisten gelöscht
// und die Suche gestartet.
// ---------------------------------------------------------
Telefonbuch tb = new Telefonbuch();
tb.suErgNa.clear();
tb.suErgNu.clear();
kqs = name + "&" + nummer;
erg = tb.tBuchAbfrage(kqs);
erg.add("Suche");
return erg;
} // analyse()
// =============================================================
static void zumBrowser(Socket cs, ArrayList<String> erg)
throws Exception {
String art = erg.get(0);
if(art.equals("Favicon")) return;
// Fälle, bei denen keine Suche gestartet wurde
// ---------------------------------------------------------
if(art.equals("Anfang")) {
schreibeKopf(cs);
schreibeForm(cs);
return;
}
if(art.equals("Ende")) {
schreibeKopf(cs);
schreibeEnde(cs);
return;
}
if(art.equals("Leere Eingabe")) {
schreibeKopf(cs);
schreibeLeer(cs);
schreibeForm(cs);
return;
}
if(art.equals("Syntaxfehler")) {
schreibeKopf(cs);
schreibeSyntax(cs);
schreibeForm(cs);
return;
}
// Suche wurde gestartet
// ---------------------------------------------------------
int len = erg.size();
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
// -----------------------------------------------------------
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></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></tr>");
}
pw.println("</table>");
pw.println("<h2>====================================</h2>");
pw.flush();
} // schreibeErg()
} // class