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