Universität Augsburg, Institut für Informatik Prof. Dr. W. Kießling Dr. A. Huhn, M. Endres, T. Preisinger SS 2008 15. Mai. 2008 Übungsblatt 5 & 6 Suchmaschinen Hinweis: Durch einen Bug in der empfohlenen Eclipse-Version kann es beim Deploy-Vorgang zu einer NullPointerException kommen. Ein Update über Help→Software Updates sorgt für Abhilfe. Aufgabe 1: Servlets und Datenbanken In dieser Aufgabe soll ein Servlet entstehen, mit dessen Hilfe eine Datenbank durchsucht wird. Der Verbindungsaufbau zu einer Datenbank wird bei JEE im Allgemeinen vom Server erledigt. Eine Datenbank wird allgemein durch eine XML-Konfigurationsdatei als Data Source deklariert und kann dann über einen festgelegten Namen erreicht werden. Eine Verbindung zur StandardDatenbank bauen Sie wie folgt auf: javax.naming.InitialContext context = new InitialContext(); javax.xml.DataSource ds = (DataSource) context.lookup("java:/DefaultDS"); java.sql.Connection conn = ds.getConnection(); Dabei ist java:/DefaultDS der JNDI-Name der Resource (JNDI steht für Java Naming and Directory Interface). Die JBoss-Standard-Datenbank ist HSQL. Definitionen aller Tabellen und -Inhalte sind in der Datei server\default\data\hypersonic\localdb.script als SQL-Statements aufgeführt. Ergänzen Sie diese um die Einträge aus der Datei food_db.sql (siehe Übungs-Seite im Web) und machen Sie sich mit der Struktur der Nahrungsmittel-Datenbank vertraut. Kopieren Sie die neuen CREATE MEMORY TABLE Statements unter die bereits vorhandenen. Die INSERT-Statements können Sie am Ende der localdb.script einfügen. 1. Implementieren Sie eine Web-Anwendung, mit der die Nahrungsmittel-Datenbank durchsucht werden kann. • Es sollen die Tabellen für die Nahrungsmittel-Typen FAST FOODS, SNACKS, SWEETS und BEVERAGES durchsucht werden können. Für jeden Suchvorgang soll die Tabelle frei wählbar sein oder alle Tabellen durchsucht werden können. • Pro Nährstoff-Kategorie soll Minimum und Maximum der gewünschten Ergebnisse per Formular wählbar sein. • Die Anzeige der Ergebnisse soll in Tabellenform erfolgen. 2. Der JNDI-Name der verwendeten Datenbank soll dem Servlet als Konfigurations-Parameter übergeben werden. 3. Eine sehr viel umfangreichere Version der Datenbank finden Sie auf dem Oracle Server, den Sie aus DBS 1 bereits kennen. Die JDBC-URL des Servers lautet: jdbc:oracle:thin:@info-dbis-srv1.informatik.uni-augsburg.de:1521:dbs1 Konfigurieren Sie eine Verbindung zu diesem Server als Data Source in JBoss. Den OracleTreiber finden Sie auf der Übungsseite, als Benutzername und Passwort verwenden Sie suma. Kopieren Sie ihn in das Verzeichnis server\default\lib Ihrer JBoss-Installation. 1 Im JBoss-Verzeichnis finden Sie unter docs\examples\jca\oracle-ds.xml eine Vorlage. Um eine neue Data Source anzulegen, müssen Sie diese Datei entsprechend anpassen und in das deploy-Verzeichnis kopieren. Vergleichen Sie die Datei mit hsqldb-ds.xml (im Deploy-Verzeichnis) und folgern Sie den korrekten JNDI-Namen der Oracle-Datenbank. 4. Mehr als 20 Ergebnisse auf einer Seite sind unübersichtlich. Implementieren Sie eine Möglichkeit, immer 20 Ergebnisse pro Seite anzuzeigen und zu weiteren Seiten des Ergebnisses (und wieder zurück) zu springen. 5. Mit Hilfe des Views USER_TABLES finden Sie weitere Tabellen. Ändern Sie ihre Anwendung, so dass dynamisch alle Tabellen durchsucht werden können. 6. Ist Ihre Anwendung vor SQL Injection geschützt? Finden Sie heraus, was der Begriff bedeutet und prüfen Sie Ihre Anwendung mit der lokalen Datenbank. Machen Sie vorher eine Sicherungskopie der Datei localdb.script. Aufgabe 2: Java Server Pages Java Server Pages sind eine Weiterentwicklung von Servlets, die vor allem in Fällen verwendet werden, bei denen die HTML-Anteile einer dynamisch erzeugten Seite viel größer sind als die Java-Code-Anteile. Eine JSP-Seite wird vom Applikationsserver in ein Servlet kompiliert und dann ausgeführt. Java-Code steht dabei innerhalb von speziellen Tags. Das folgende Beispiel zeigt eine einfache JSP-Seite: 1 2 3 4 5 6 <html><head><title>JSP-Beispiel</title></head><body> <% String name = request.getParameter("usr"); %> Hallo <%= name %>. Wie geht’s? </body></html> Das Anfangs-Tag in Zeile 2 und das End-Tag in Zeile 4 umschließen beliebigen Java-Code. In solchen Tags definierte Variablen sind in der gesamten JSP-Seite sichtbar. Weitere für das Verständnis der Aufgabe nötige Details finden Sie im Web, z. B. in der Wikipedia. Eclipse bietet innerhalb eines Dynamic Web Projects Unterstützung für die JSP-Programmierung. 1. Erzeugen Sie eine JSP-Seite wie im Beispiel und legen Sie diese in ein ZIP-Archiv mit der Endung WAR. Die JSP-Datei liegt im obersten Verzeichnis des Archivs. Deployen Sie das Archiv auf dem JBoss. Die Seite erreichen Sie unter der folgenden URL: http://localhost:8080/archivname-ohne-endung/dateiname.jsp 2. Schreiben Sie eine JSP-Seite, die dem Benutzer ein Formular anzeigt, in das er seinen Namen eintragen kann. Dieser Name soll die ganze Session über erhalten bleiben. 3. Ist der Benutzername bekannt, soll angezeigt werden, wie oft der Benutzer bereits einen Refresh auf die Seite gemacht hat: Hallo Xyz, Du bist jetzt zum 5. Mal auf dieser Seite. Danach sollen zwei Links auf die aktuelle Seite folgen, wobei einer die Seite neu lädt und der andere die aktuelle Session beendet (z. B. durch Aufruf der Seite mit einem bestimmten Parameter). 4. Die Zählung der Seitenaufrufe eines Benutzers soll nicht auf eine Session beschränkt bleiben, sondern zusätzlich über die ganze Laufzeit des Servers mitgezählt werden. Beide Zahlen sollen beim Seitenaufruf ausgegeben werden. 2 Aufgabe 3: Enterprise Java Beans - Session Beans Enterprise Java Beans sind ein Programmierkonzept, um komponentenbasierte Software zu schreiben. Dabei unterscheidet man zwei Arten von Beans: • stateless (zustandslose) Beans, die bei jedem Aufruf gleich reagieren • stateful (zustandsbehaftete) Beans, die einen internen Zustand besitzen Wir werden beide Arten implementieren und mit einem Client darauf zugreifen. 1. Erstellen Sie ein neues EJB-Projekt. Der Ziel-Server ist JBoss, für den auch die DefaultKonfiguration gewählt werden soll. Im letzten Fenster setzen Sie einen Haken vor Generate Deployment Descriptor. 2. Erzeugen Sie jetzt ein neues EJB Session Bean. Wir beginnen mit einem Stateless-Bean namens Calculator im Paket beans. Das Bean soll die folgenden Methoden haben: • public int sum(int a, int b) - gibt die Summe von a und b zurück • public int mult(int a, int b) - gibt das Produkt von a und b zurück Tragen Sie die Methoden dazu sowohl in der Bean-Klasse CalculatorBean als auch im Bean-Interface Calculator ein. Das Interface legt fest, welche Methoden ein Client sehen kann. Über Run as→Run on Server wird das Bean auf dem Server deployed und kann verwendet werden. Die Erfolgsmeldung des Servers lautet: STARTED EJB: bean.CalculatorBean ejbName: CalculatorBean 3. Nun soll ein Programm entstehen, das auf das Bean zugreift. Erstellen Sie ein neues JavaProjekt, dem Sie die Libraries jbossall-client.jar und jboss-ejb3.jar aus dem JBoss-Unterverzeichnis client hinzufügen. Bei den referenzierten Projekten tragen Sie das EJB-Projekt ein. Die Konfigurationsdaten speichern Sie in der Datei jndi.properties: java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces java.naming.provider.url=localhost:1099 Die Konfiguration und der Aufruf eines Beans laufen dann wie folgt ab: java.util.Properties props = new Properties(); props.load(new java.io.FileInputStream("jndi.properties")); javax.nameing.InitialContext ctx = new InitialContext(props); beans.Calculator calc = (Calculator) ctx.lookup("CalculatorBean/remote"); 4. Stateful Beans haben Attribute, deren Wert während einer Session mit einem Client gespeichert bleibt. Ein solches soll jetzt entstehen und die folgenden Methoden anbieten: • • • • public public public public int int int int setMin(int min) - setze das Attribut min neu setMax(int max) - setze das Attribut max neu random() - gib eine Zufallszahl zwischen min und max zurück getCount() - gib die Anzahl der Aufrufe von random zurück Testen Sie das Bean ebenfalls mit einem Client. 3 Aufgabe 4: Persistenz mit Enterprise Java Mit Hilfe von Java Persistence sollen Benutzerdaten in einer Datenbank abgelegt werden. Ein Benutzer hat die Eigenschaften id (eine Zahl), Name und Vorname. Die Java Persistence API muss wissen, welche Datenbank verwendet wird. Sie braucht dazu eine Beschreibungsdatei namens persistence.xml mit folgendem Inhalt, die sich im Verzeichnis META-INF des EJB-Projekts befindet: <persistence> <persistence-unit name="defaultManager"> <jta-data-source>java:/DefaultDS</jta-data-source> </persistence-unit> </persistence> Dabei ist java:/DefaultDS der Name der Datenquelle (vgl. Aufgabe 1). defaultManager ist der von der Datei definierte Persistenz-Service. Die Verwaltung der persistenten Instanzen soll über ein Stateful-Bean ablaufen. Dabei sollen die folgenden Methoden definiert werden: • User addUser(int id, String n, String v) - erzeuge einen Benutzer • User findUser(int id) - liefere den Benutzer mit der gegebenen id zurück • List<User> getUsers() - gib eine Liste aller Benutzer zurück; der Query-String dazu lautet: ”SELECT u FROM User u” • public void dropUser(int id) - lösche den Benutzer mit der gegebenen id Das Bean erhält die Fähigkeit zur persistenten Sicherung von Objekten durch eine Instanzvariable: @javax.persistence.PersistenceContext(name="defaultManager") javax.persistence.EntityManager em; Der defaultManager ist aus persistence.xml bekannt. • Implementieren Sie eine entsprechende Klasse für die Benutzer. Die Signatur der Klasse beginnt mit: public @javax.persistence.Entity class User implements java.io.Serializable Der Ausdruck @javax.persistence.Entity ist ein Zeichen für den Application Server, dass ein Klasse von persistenten Objekten vorliegt. Geben Sie der Klasse einen parameterlosen Konstruktor und Getter/Setter für alle Attribute. Das Attribut id muss durch die Annotation @javax.persistence.Id als Primärschlüssel ausgewiesen werden. • In der Datenbank muss eine Tabelle für die Benutzer-Objekte existieren, die alle Attribute aufnehmen kann. Attribut- und Spaltennamen müssen übereinstimmen. Legen Sie eine solche Tabelle in der JBoss-Standard-Datenbank an. • Schreiben Sie das Bean zur Verwaltung der Instanzen. • Schreiben Sie einen Client (vgl. vorherige Aufgabe), der Benutzer anlegen, anzeigen und löschen kann. • Das Zurückschreiben geänderter Werte erfolgt nicht automatisch. Ergänzen Sie das SessionBean um eine Methode, um den DB-Eintrag für einen User updaten zu können. Der DBEintrag kann mit Hilfe der Methode merge(Object obj) des EntityManagers auf den aktuellen Stand gebracht werden. 4 Aufgabe 5: Web-Anwendungen mit Seam Auf der Übungsseite finden Sie die Datei seam.zip zum Download. Darin enthalten ist die Seam-Anwendung numberguess.ear. Deployen Sie diese auf Ihrem Application Server. Die URL zur Anwendung lautet http://localhost:8080/numberguess/. In der Anwendung müssen Sie eine vom Server ”gedachte” Zahl erraten. 1. Bringen Sie die Anwendung auf Ihrem Application Server zum Laufen. 2. In der einzigen Java-Klasse der Anwendung gibt es das Attribut maxGuesses. Es wird durch einen Eintrag in der Datei META-INF\components.xml im Archiv numberguess.war initialisiert. Ändern Sie die Anwendung so ab, dass die Anzahl der Versuche mitgezählt wird und das Spiel beim Überschreiten abgebrochen wird. Fügen Sie dazu analog zu win.jspx eine Datei lose.jspx hinzu. 3. Bei weniger als 6 Lösungsmöglichkeiten (also ein entsprechend kleines Interval zwischen den angezeigten Grenzen) soll die Eingabe über ein Drop-Down-Menü erfolgen. Informieren Sie sich dazu über die Begriffe selectOneMenu und selectItems als Java Server Faces HTML Tags. Achten Sie stets auf den Namespace (der durch den Buchstaben vor JSF-Tags ausgedrückt wird). Informationen zur JSP Expression Language, mit der Sie Bedingungen formulieren können, finden Sie ebenfalls im Internet. Am Ende der Hauptseite der Anwendung sehen Sie bereits, wie einzelne Elemente der Seite in Abhängigkeit von einer Bedingung anzeigt werden. Aufgabe 6: Adressverwaltung mit Java Persistence Mit Hilfe der nun bekannten Technologien EJBs, Java Persistence und JSP/Servlets soll nun eine Benutzerverwaltung entstehen. Entwickeln Sie dies als EJB-Komponente(n) mit den folgenden Eigenschaften: • Eine Adresse besteht aus den folgenden Eigenschaften: – – – – Name Vorname Telefon eMail • Über ein HTML-Formular soll beim Start der Anwendung eine Benutzerliste angezeigt werden. • Beim Klick auf einen bestimmten Benutzer soll eine Seite zur Bearbeitung der Eigenschaften dieses Benutzers angezeigt werden. • Neue Benutzer sollen angelegt und bestehende gelöscht werden können. • Die Anwendung soll dem Schichtenmodell entsprechen: – JSP/Servlets zum Anzeigen von Daten, Formularen und Ergebnissen – Session Beans für die Anwendungslogik – Java Persistence für die Datenhaltung 5