TagExtraInfo Methode getVariableInfo(TagData) Liefert Informationen über Skript−Variable an den JSP− Compiler. TagData−Parameter enthält die in der JSP−Seite angegebenen Attribute des Tags. <x:bar id="sample"> <p>Typ der Variablen: <%= sample.getClass().getName() %>.</p> </x:bar> getAttributes(), getAttribute(), getId() boolean isValid(TagData data) Prüfung der Attribute zur Übersetzungszeit Web−Anwendungen mit Java 501 Skript−Variablen: generierter Code JSP−Compiler ruft getVariableInfo(TagData) auf und generiert Deklaration und Initialisierung. _jspx_th_bar_bar_0.doInitBody(); do { java.security.Signature sample = null; sample = (java.security.Signature) pageContext.findAttribute("sample"); out.write("Bar"); } while (_jspx_th_bar_bar_0.doAfterBody() == BodyTag.EVAL_BODY_AGAIN); Web−Anwendungen mit Java 502 Skriptvariable im TLD definieren Statt über TagExtraInfo lassen sich Skriptvariable statisch im TLD definieren. Beispiel <tag> <name>foo</name> <tag−class>de.rainer_klute.Foo</tag−class> <variable> <name−from−attribute>bar−id</name−from−attribute> <variable−class>java.lang.String</variable−class> <scope>NESTED</scope> </variable> <attribute> <name>bar−id</name> <required>true</required> </attribute> </tag> Web−Anwendungen mit Java 503 URIs und TLDs Zum Finden des TLD zwei Zuordnungen erforderlich JSP−Seite: Präfix → URI Deployment descriptor: URI → TLD Implizite Zuordnung vermeidet zweiten Schritt TLD spezifiziert »seinen« URI in einem Element <uri>. JSP−Container untersucht alle TLDs und »weiß« danach, welcher URI welchem TLD entspricht. Explizite Zuordnungen haben Vorrang. JSP−Container kann weitere implizite Zuordnungen treffen. Weitere Details siehe JSP−Spezifikation Web−Anwendungen mit Java 504 Gut verpackt: Tag libs »aus der Dose« Vorgefertigte Tag libs unmittelbar nutzen Möglich durch implizite Zuordnungen Gruppe zusammengehörender Aktionen in JAR−Datei verpackt TLDs in META−INF spezifizieren URI (<uri>−Element) TLD besitzen Endung .tld, z.B. META−INF/foo.tld, META− INF/bar.tld usw. Spezifizierte Klassen werden im Classpath gesucht. Bedienungsanleitung JAR−Datei nach WEB−INF/lib der Web−Anwendung kopieren (JAR−Datei gehört dadurch zum Classpath) Web−Anwendungen mit Java 505 Listener Listener werden über Anwendungsereignisse informiert. Siehe Servlet−Kapitel JSP erlaubt Angabe von Listener−Klassen im TLD Vorteil: Eine einzige JAR−Datei bündelt Listener Tag handler TLD Web−Anwendungen mit Java 506 Validierung Tag lib kann JSP−Seite validieren. Im TLD Element <validator> angeben. Beispiel: <validator> <validator−class> de.rainer_klute.plz.Validator </validator−class> <init−param> <param−name>foo</param−name> <param−value>bar</param−value> </init−param> </validator> Validator−Klasse implementiert Interface javax.servlet.jsp.tagext.TagLibraryValidator Web−Anwendungen mit Java 507 TagLibraryValidator void setInitParameters(java.util.Map map) Setzt die Init−Parameter Aufruf durch JSP−Compiler ValidationMessage[] validate(String prefix, String uri, PageData page) Validiert eine JSP−Seite Aufruf durch JSP−Compiler Attribute von Aktionen lassen sich durch TagExtraInfo.isValid() prüfen. Web−Anwendungen mit Java 508 TagLibraryValidator java.util.Map getInitParameters() Liefert die Init−Parameter void release() Freigeben der Ressourcen der Validator−Klasse Aufruf durch JSP−Compiler Web−Anwendungen mit Java 509 PageData JSP−Compiler übergibt PageData−Objekt an die validate()−Methode. PageData.getInputStream() liefert InputStream. InputStream enthält XML−Ansicht der JSP−Seite. <%−Notation durch XML−Äquivalente ersetzt Include−Direktiven aufgelöst → vollständige Seite XML−Elemente möglicherweise mit jsp:id−Attributen Für die Validierung ist ein XML−Parser hilfreich. Ergebnis der Validierung: Array von ValidationMessage−Objekten Web−Anwendungen mit Java 510 ValidationMessage Informiert über Fehler bei der Validierung Validator erzeugt ValidationMessage Konstruktor: ValidationMessage(String id, String message) id: Wert von jsp:id, falls vorhanden message: Text der Fehlermeldung Methoden (vom JSP−Compiler aufgerufen) String getId() String getMessage() Web−Anwendungen mit Java 511 TryCatchFinally Hilfs−Interface für Tag handler, die z.B. Ressourcen verwalten und nach Fehlern freigeben müssen public class MyTagHandler extends BodyTagSupport implements TryCatchFinally Methode doCatch(Throwable t) Wird von JSP−Seite bei Fehler zwischen doStart() und doEnd() aufgerufen. Methode doFinally() Wird von JSP−Seite immer nach doEnd() aufgerufen. Web−Anwendungen mit Java 512 Aufruf bei TryCatchFinally h = ... // Tag handler h.setPageContext(pc); h.setParent(null); h.setFoo("bar"); ... try { doStartTag(); ... doEndTag(); } catch (Throwable t) { h.doCatch(t); // Exception bearbeiten } finally { h.doFinally(); // Immer ausführen } Web−Anwendungen mit Java 513 Noch einmal: Tag Library Descriptor Aufbau etwas ausführlicher, siehe aber Details in der JavaServer Pages 1.2 Specification Wurzelelement: taglib <?xml version="1.0" encoding="ISO−8859−1"?> <!DOCTYPE taglib PUBLIC "−//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "http://java.sun.com/dtd/web−jsptaglibrary_1_2.dtd"> <taglib xmlns="http://java.sun.com/JSP/TagLibraryDescriptor"> ... </taglib> DTD definiert das Inhaltsmodell von taglib: DTD verstehen <!ELEMENT taglib (tlib−version, jsp− version, short−name, uri?, display− name?, small−icon?, large−icon?, description?, validator?, listener*, tag+)> <!ELEMENT (...)> definiert ein Element und legt seinen Inhalt (Kind−Elemente) fest. tlib−version, jsp−version: Definiert Reihenfolge Hier: Genau ein tlib−version−Element gefolgt von genau einem jsp−version−Element uri?: ein optionales uri−Element (0 <= n <= 1) Web−Anwendungen mit Java 515 DTD verstehen listener*: optionale listener−Elemente (0 <= n) tag+: Mindestens ein tag−Element (1 <= n) foo | bar: Entweder ein foo−Element oder ein bar− Element (...): übliche Klammerregelung Web−Anwendungen mit Java 516 TLD−Element »taglib« tlib−version: Versionsnummer der Tag library jsp−version: Versionsnummer der JSP−Spezifikation short−name: Kurzname der Taglib, der z.B. als Präfix genutzt werden kann uri: eindeutiger URI der Taglib display−name: »Lesbarer« Name der Taglib Web−Anwendungen mit Java 517 TLD−Element »taglib« small−icon: Name einer GIF− oder JPEG−Datei mit 16x16−Icon. Datei liegt relativ zum TLD und endet mit .gif oder .jpg large−icon: Name eines 32x32−Icons description: Beschreibung der Taglib validator: Validator−Spezifikation listener: Listener−Spezifikation tag: Spezifikation des/der Tags Web−Anwendungen mit Java 518 TLD−Element »validator« <!ELEMENT validator (validator−class, init−param*, description?)> Der Validator prüft die syntaktische Richtigkeit einer JSP−Seite. validator−class: Name der Validatorklasse init−param: Initialisierungsparameter description: Beschreibung Web−Anwendungen mit Java 519 Element »init−param« <!ELEMENT init−param (param−name, param−value, description?)> Spezifiziert ein Name−/Wert−Paar param−name: Name des Parameters param−value: Wert des Parameters description: Beschreibung Web−Anwendungen mit Java 520 TLD−Element »listener« <!ELEMENT listener (listener−class)> Wird bei Applikationsereignissen benachrichtigt Details siehe Servlet−Kapitel und Servlet−Spezifikation listener−class: Name der Listener−Klasse Web−Anwendungen mit Java 521 TLD−Element »tag« <!ELEMENT tag (name, tag−class, tei− class?, body−content?, display−name?, small−icon?, large−icon?, description?, variable*, attribute*,example?)> Spezifiziert ein Element (»Tag«) der Taglib name: Name des Elements tag−class: Tag−Klasse tei−class: TagExtraInfo−Klasse display−name: »Lesbarer« Name des Tags description: Beschreibung des Tags Web−Anwendungen mit Java 522 TLD−Element »tag« small−icon: 16x16−Icon large−icon: 32x32−Icon body−content: Beschreibt den Body näher JSP: Body enthält JSP−Elemente oder ist leer (Voreinstellung). tagdependent: Body enthält tag−spezifischen Inhalt, z.B. SQL−Anweisungen oder ist leer. empty: Body muß leer sein. variable: Spezifikation einer Skriptvariablen attribute: Spezifikation eines Attributs example: Beispiel für die Verwendung des Tags Web−Anwendungen mit Java 523 TLD−Element »variable« <!ELEMENT variable ( (name−given | name− from−attribute), variable−class?, declare?, scope?, description?)> Beschreibt eine Skriptvariable. name−given: Name der Variablen name−from−attribute: Name der Variablen ergibt sich aus dem Namen dieses Attributs variable−class: Klassenname der Variablen. Voreinstellung: java.lang.String declare: Gibt an, ob die Variable hier deklariert wird. Voreinstellung: true Web−Anwendungen mit Java 524 TLD−Element »variable« scope: Geltungsbereich der Skriptvariable NESTED: vom Start−Tag bis zum Ende−Tag (Voreinstellung) AT_BEGIN: vom Start−Tag bis zum Ende der Seite AT_END: vom Start−Tag bis zum Ende der Seite description: Beschreibung der Variablen Web−Anwendungen mit Java 525 TLD−Element »attribute« <!ELEMENT attribute (name, required?, rtexprvalue?, type?, description?)> Spezifiziert ein Attribut name: Name des Attributs required: Muß Attribut angegeben werden? Werte: true | false | yes | no (Voreinstellung: false) Web−Anwendungen mit Java 526 TLD−Element »attribute« rtexprvalue: Ausdrücke zur Laufzeit zulässig? Werte: true | false | yes | no (Voreinstellung: false) type: Klasse des Attributs. Bei statischen Attributen immer java.lang.String description: Beschreibung der Variablen Web−Anwendungen mit Java 527 Java 2 Enterprise Edition (J2EE) Java 2 Enterprise Edition (J2EE) Web−Anwendungen mit Java 528 Zwei−Schichten−Architektur Bisherige Anwendungen: Zwei−Schichten−Architektur Anwendungslogik und Präsentation in derselben JVM Skalierbarkeit schwierig JSPs/Servlets + weitere Klassen Datenbank Web−Anwendungen mit Java Anwendungslogik, Präsentation Daten 529 Mehrschichten−Architektur J2EE trennt Präsentation und Anwendungslogik. Geschäftsobjekte als Enterprise Java Beans (EJBs) EJBs laufen verteilt in EJB−Containern. JSPs/Servlets + weitere Klassen EJBs Anwendungslogik Datenbank Web−Anwendungen mit Java Präsentation Daten 530 Architektur Web−Anwendung HTTP/ SSL Servlet / JSP JDBC Web−Container Web−Browser Web−Anwendungen mit Java 531 Servlet / JSP Web−Anwendungen mit Java Appl. Client EJB JDBC HTTP/ SSL Application Client Container Applet EJB−Container Web−Container Applet− Container Architektur J2EE−Anwendung 532 J2EE−Standarddienste In jedem J2EE−Container verfügbar Application Server Herstellerunabhängig HTTP, HTTPS Java Naming and Directory Interface (JNDI) JavaBeans Activation Framework (JAF) Java Message Service (JMS) JDBC Java Transaction API (JTA) Java Authentication and Authorization Service (JAAS) RMI−IIOP Java IDL Java API for XML Parsing (JAXP) JavaMail J2EE Connector Architecture Web−Anwendungen mit Java 533 Architektur J2EE−Anwendung (II) Applet−Container Web−Anwendungen mit Java 534 JAF JDBC Java Mail JAXP JTA JAAS JMS Connectors JAF JDBC Java Mail JAXP JTA JAAS EJB JMS Servlet / JSP JDBC Appl. Client JAXP EJB−Container JAAS Web−Container JMS Application Client Container Connectors Applet Serialisierung Serialisierung Web−Anwendungen mit Java 535 Serialisierung: Anforderungen Persistente Objekte Anwendung speichert Objekte permanent. Späterer Lauf der Anwendung lädt gespeicherte Objekte. Verteilte Objekte Objekte von einer JVM zur anderen übertragen (→RMI) Speichern / Übertragen aller Objekte, die vom Ausgangsobjekt aus erreichbar sind Erweiterbar Künftige Versionen der Klasse unterstützen Einfach Web−Anwendungen mit Java 536 Serialisierung: Beispiel Serialisierung: Objekt(e) speichern Deserialisierung: Objekt(e) laden Beispiel: List list; Set set; /* List und Set mit Daten füllen */ FileOutputStream fos = new FileOutputStream("datei.ser"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(list); oos.writeObject(set); oos.close(); FileInputStream fis = new FileInputStream("datei.ser"); ObjectInputStream ois = new ObjectInputStream(fis); list = (List) ois.readObject(); set = (Set) ois.readObject(); fis.close(); Web−Anwendungen mit Java 537 Serialisierung: Alternativen Voreingestellte Serialisierung (De−)Serialisieren aller Felder des Objekts Ausnahmen: statische und transiente Felder Klasse implementiert Interface Serializable. Marker−Interface, keine Implementierung von Methoden nötig Klassendefinierte Serialisierung (De−)Serialisieren ausgewählter Felder Felder müssen nicht denen der Klasse entsprechen. Weiterentwicklung der Klasse Klasse implementiert Serializable und spezifiziert Felder. Web−Anwendungen mit Java 538 Serialisierung: Alternativen Externalisierung Klasse nutzt die Serialisierungsmechanismen nicht. Klasse ist selbst für korrektes Schreiben und Lesen der externalisierten Daten verantwortlich. Klasse implementiert Interface Externalizable. public void writeExternal(ObjectOutput out) throws IOException public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException Web−Anwendungen mit Java 539 Weiterentwicklung von Klassen Neue Version einer Klasse ersetzt alte Version Alte Klasse verwaltet einen DM−Betrag Neue Klasse verwaltet Euro Anforderung: automatische Umstellung Deserialisierung eines alten Objekts mit readObject() liefert InvalidClassException. Jede Klasse enthält eine Seriennummer. Neue Seriennummer bei signifikanten Änderungen Neues oder gelöschtes Feld, neue oder gelöschte Methode, geänderte Signatur einer Methode usw. Nicht: Änderung im Methodenrumpf Web−Anwendungen mit Java 540 Beispiel: Sum.java package de.rainer_klute.serialization; import java.io.*; /** * <p>Maintains a currency value (in DM).</p> */ public class Sum implements Serializable { private float sum; public Sum() { sum = 0.0f; } Web−Anwendungen mit Java 541 Beispiel: Sum.java float getSum() { return sum; } void add(float d) { sum += d; } } Web−Anwendungen mit Java 542 Beispiel: Summing1.java Sum sum; final String FILENAME = "sum.ser"; if (new File(FILENAME).exists()) { FileInputStream fis = new FileInputStream(FILENAME); ObjectInputStream ois = new ObjectInputStream(fis); sum = (Sum) ois.readObject(); fis.close(); } else sum = new Sum(); sum.add(Float.parseFloat(args[0])); FileOutputStream fos = new FileOutputStream(FILENAME); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(sum); oos.close(); System.out.println("Sum is now " + sum.getSum() + " DM."); Web−Anwendungen mit Java 543 Änderungsstrategie Inkompatible Klassen kompatibel machen Seriennummer der alten Klasse ermitteln serialver de.rainer_klute.serialization.Sum de.rainer_klute.serialization.Sum: static final long serialVersionUID = 3834243616784878964L; Ausgabe des Kommandos serialver als Deklaration in die neue Klasse übernehmen Deserialisierung anpassen: Alte Objekte erkennen Alte Werte in neues Objekt einlesen Web−Anwendungen mit Java 544 Beispiel: Sum.java (neue Version) package de.rainer_klute.serialization; import java.io.*; /** * <p>Maintains a currency value. An old version of this * class could cope with DM only and kept it in a field * named "sum". The new version supports Euro instead of * DM. Conversion of old serialized objects happens * automatically when the old object is deserialized.</p> */ public class Sum implements Serializable { static final long serialVersionUID = 3834243616784878964L; private float sumEuro; Web−Anwendungen mit Java 545 Beispiel: Sum.java (neue Version) public Sum() { sumEuro = 0.0F; } float getSum() { return sumEuro; } void add(float d) { sumEuro += d; } Web−Anwendungen mit Java 546 Beispiel: Sum.java (neue Version) } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { ObjectInputStream.GetField gf = in.readFields(); ObjectStreamClass osc = gf.getObjectStreamClass(); ObjectStreamField field = osc.getField("sumEuro"); if (field != null) { System.out.println("New class version"); sumEuro = gf.get("sumEuro", 0f); } else { System.out.println("Old class version"); float f = gf.get("sum", 0f); System.out.print(f + " DM "); f = Math.round(f / 195.583f) / 100f; System.out.println("converted to " + f + " EUR."); sumEuro = f; } } Web−Anwendungen mit Java 547 Alte und neue Klasse unterscheiden Unterscheidungskriterium: Feldnamen oder −typen in alter und neuer Klasse Hier: feststellen, ob Feld "sum" oder "sumEuro" in serialisiertem Objekt vorhanden Besser: eigene Versionsnummer der Klasse in Feldnamen kodieren int classVersion_42; Mit ObjectStreamClass−Methode ObjectStreamField[] getFields() herausfinden, welches Feld mit »classVersion_« beginnt Rest des Feldnamens ist die Versionsnummer. Web−Anwendungen mit Java 548 Remote Method Invocation (RMI) Remote Method Invocation (RMI) Web−Anwendungen mit Java 549 Remote Method Invocation (RMI) Zusammenarbeit zwischen verschiedenen JVM Objekt in entfernter JVM (Remote−Objekt) referenzieren Methoden des entfernten Objekts aufrufen Objekt von einer JVM zur anderen übertragen Objekt muß serialisierbar sein. Web−Anwendungen mit Java 550