Gliederung 1. Software-Komponenten: Grundlegende Begriffe 2. Systematischer Entwicklungsprozess für Komponenten-Software mit UML 3. Java-Komponenten-Technologien 3.1 JavaBeans-Technologie 3.2 Web-Komponenten mit Java 3.3 Enterprise JavaBeans-Technologie 4. Komponentenspezifikation 5. Komponententechnologien im Vergleich 5.1 Microsoft COM/DCOM/COM+ 5.2 CORBA Component Model 5.3 Vergleich der Komponentenstandards 6. Zusammenfassung und Ausblick Kapitel 3 Java-Komponenten-Technologien 3.3 Enterprise JavaBeans-Technologie EJB-Architektur Session Beans Wiederholung; Rollen in der EJB-Entwicklung Entity Beans Transaktionsbehandlung, Sicherheit Message-Driven Beans Seite 1
Zweck der EJB-Technologie: Aufgabenteilung "Vertrag" (programming contract) für den Hersteller der Server- Komponenten: Einhalten von Programmier-Konventionen Bereitstellung der Software in gebrauchsfertiger Verpackung» z.b. JAR-Archive in verschiedenen Varianten Nutzung von Infrastrukturdiensten des Containers» z.b. Container-Managed Persistence Berücksichtigung von Container-Aktionen» z.b. Activate-/Passivate-Methoden (Hook-Methoden) "Verstecken" der Client-Systeme und der Infrastruktur "Vertrag" für den Programmierer der Client-Anwendung: Programmieren "gegen" abstrakte Schnittstellen» Objekt-Schnittstelle (Remote Interface)» Verwaltungs-Schnittstelle (Home Interface) "Verstecken" der Implementierungsdetails und der Infrastruktur Wiederholung: EJB Class "CounterEJB" (1) import javax.ejb.sessionbean; import javax.ejb.sessioncontext; public class CounterEJB implements SessionBean { private int count; private int startvalue; private int incrvalue; private boolean enabled; public void ejbcreate() { startvalue = 0; incrvalue = 1; reset(); enabled = true; public int getcurrent () { return count;... public int getstartvalue () { return startvalue; Sicht: Hersteller von Server-Komponenten Seite 2
Wiederholung: EJB Class "CounterEJB" (2)... public void reset () { count = startvalue; public void count () { if (enabled) { count += incrvalue; // EJB Lifecycle Callback Methods public void ejbremove() { public void ejbactivate() { public void ejbpassivate() { public void setsessioncontext(sessioncontext sc) { Sicht: Hersteller von Server-Komponenten Wiederholung: Schnittstellen für Client public interface Counter extends EJBObject { public int getcurrent() throws RemoteException; public int getstartvalue() throws RemoteException; public void setstartvalue(int value) throws RemoteException; public int getincrvalue() throws RemoteException; public void setincrvalue(int value) throws RemoteException; public boolean getenabled() throws RemoteException; public void setenabled(boolean value) throws RemoteException; public void reset() throws RemoteException; public void count() throws RemoteException; public interface CounterHome extends EJBHome { Counter create() throws RemoteException, CreateException; Sicht: Hersteller von Client-Software Seite 3
Wiederholung: Client-Programm import javax.naming.context; import javax.naming.initialcontext; import javax.rmi.portableremoteobject;... try { Context ictx = new InitialContext(); Object ctrref = ictx.lookup("jndi Name"); CounterHome ctrhome = (CounterHome)PortableRemoteObject.narrow (ctrref,counterhome.class); Counter counter = ctrhome.create();... counter.setstartvalue(...); counter.count();... catch (Exception ex) { System.err.println("Error when connecting to server"); ex.printstacktrace(); Sicht: Hersteller von Client-Software "Offizielles" EJB-Rollenmodell EJB-2.0-Standard definiert sieben verschiedene Rollen: Enterprise Bean Provider» Hersteller flexibler, wiederverwendbarer Server-Komponenten Application Assembler» Erstellung von Anwendungen aus EJBs und anderen Komponenten Deployer» Anpassung und Installation einer bestimmten Anwendung für Ausführungsumgebung (incl. EJB Server und Container) EJB Server Provider & EJB Container Provider» Bereitstellung von Server-Software und Werkzeugen» vgl. Sun Referenz-Implementierung für J2EE-Server Persistence Manager Provider» Bereitstellung von persistenter Speicherung für Entity Beans System Administrator» Konfiguration, Beobachtung, Anpassung im laufenden Betrieb Seite 4
Kapitel 3 Java-Komponenten-Technologien 3.3 Enterprise JavaBeans-Technologie EJB-Architektur Session Beans Wiederholung; Rollen in der EJB-Entwicklung Entity Beans Transaktionsbehandlung, Sicherheit Message-Driven Beans Achtung: Dieser Abschnitt gibt verbesserte und detailliertere Fassungen der Folien Nr. 29-33 aus der letzten Vorlesung! Entity Beans Aus der Sicht eines Client-Programms: Entity Bean = Komponente, die eine objektorientierte Sicht auf eine oder mehrere Entitäten bereitstellt, die in persistentem (dauerhaftem) Speicher abgelegt werden. Sehr ähnliche Konventionen wie für Session Beans Container-Managed Persistence (CMP): (siehe folgendes Beispiel) Volle Ausnutzung der möglichen Aufgabenteilung Abbildung auf persistente Speicherung verborgen vor dem Entwickler der Server-Komponenten (EJB Provider) (Hier: EJB 2.0-Standard) Bean-Managed Persistence (BMP): Persistenz als Bestandteil der Server-Komponenten Verwendung traditioneller Hilfsmittel (z.b. eingebettetes SQL) Seite 5
Beispiel: Remote Interface "Account" import java.rmi.remoteexception; import javax.ejb.ejbobject; public interface Account extends EJBObject { int getaccountno() throws RemoteException; int getbalance() throws RemoteException; String getowner() throws RemoteException; void credit(int amount) throws RemoteException; void debit(int amount) throws RemoteException, InsufficientFundsException; public class InsufficientFundsException extends Exception { public InsufficientFundsException() { Eine Entity-Bean-Klasse repräsentiert eine Sicht auf einen Datenbestand. Bevorzugt Getter- und Setter-Methoden Objektorientiertes Prinzip: auch fachliche Methoden definiert Hilfsklassen z.b. für fachliche Ausnahmesituationen Granularität von Entity Beans Eine Instanz einer Entity Bean umfaßt mindestens einen Datensatz, kann aber auch mehrere Datensätze kapseln. Empfehlenswert: Kapselung eines (existenz-)unabhängigen Objekts mit davon abhängigen Objekten (dependent objects) "Granularität" von EJBs nicht zu klein wählen! Beispiel: Bestellung 1..* 1 Order OrderLine Product 1 * Order und Product sind unabhängig voneinander OrderLine ist abhängig von Order und Product Eine Entity Bean für Order und OrderLine verwenden! Seite 6
Beispiel: Home Interface "AccountHome" import javax.ejb.ejbhome; import java.rmi.remoteexception; import javax.ejb.createexception; import javax.ejb.finderexception; import java.util.collection; public interface AccountHome extends EJBHome { Account create(string owner, int accountno) throws RemoteException, CreateException; Account findbyprimarykey(integer pk) throws RemoteException, FinderException; Collection findbyowner(string owner) throws RemoteException, FinderException; Verwaltung großer Mengen von Entity-Bean-Instanzen Diverse Such-Methoden; verpflichtend findbyprimarykey Löschen von Instanzen über Methoden von javax.ejb.ejbhome Ergebnis einer Suchmethode Remote Interface Klasse, falls immer einelementig java.util.collection (von Remote Interface), falls mehrelementig "Home Methods": Fachliche Methoden, die auf allen Instanzen arbeiten Objektidentität und Primärschlüssel Identität über Home Interface und Primärschlüssel: Wenn zwei Objekte über das gleiche Home-Interface zugänglich sind und den gleichen Primärschlüssel tragen, gelten sie als identisch. Der Primärschlüssel-Wert eines Objektes darf sich über seine Lebenszeit nicht verändern. Vordefinierte Methode in EJBObject: boolean isidentical(ejbobject o) Folgende Verfahren stellen nicht (immer) die Identität zweier Objekte fest:» Vergleich der Referenzen mit "=="» Vergleich der Objektidentität mit equals() Container müssen Objektinstanzen entfernen, erzeugen, umwidmen etc. können, unabhängig von der fachlichen Identität. Seite 7
Beispiel: EJB Class mit CMP "AccountEJB" (1) import javax.ejb.entitybean; import javax.ejb.entitycontext; public abstract class AccountEJB implements EntityBean { // Container-managed persistent fields public abstract int getaccountno(); public abstract void setaccountno(int no); public abstract String getowner(); public abstract void setowner(string owner); public abstract int getbalance(); public abstract void setbalance(int bal); Persistentes Feld "accountno" // Constructor public AccountEJB() { public Integer ejbcreate(string owner, int accountno) { setaccountno(accountno); setowner(owner); setbalance(0); return null;... Initialisierung bei Erzeugung Typ des Primärschlüssels als Resultat; Konvention (bei CMP): Rückgabewert "null" Deployment-Information zur Persistenz Seite 8
Wahl von Primärschlüssel-Klassen Einfache Primärschlüssel: java.lang.string, java.lang.integer etc. Konversion von int nach Integer etc. vom Container unterstützt Zusammengesetzte Primärschlüssel: Eigene Hilfsklasse definieren (z.b. AccountPK) Reine Datenstrukturklasse, Schlüsselbestandteile als öffentliche Felder Feldnamen identisch zu Namen der entsprechenden persistenten Felder hashcode() und equals() implementiert z.b.: public AccountPK { public Integer accountno; public String owner;... Remote Interface und persistente Felder public interface Account extends EJBObject { Remote public int getaccountno() throws RemoteException; Interface public int getbalance() throws RemoteException; public String getowner() throws RemoteException;... public abstract class AccountEJB implements EntityBean { public abstract int getaccountno(); public abstract void setaccountno(int no); Persistente public abstract int getbalance(); Felder in public abstract void setbalance(int bal); public abstract String getowner(); EJB Class public abstract void setowner(string owner);... Implementierung der Get- und Set-Methoden durch Container Offenlegung (exposition) von Get- und Set-Methoden im Remote Interface Meist nur Auswahl offengelegt (hier z.b. "read-only") Set-Methode für Primärschlüssel (hier setaccountno) niemals offenlegen! Seite 9
Beispiel: EJB Class mit CMP "AccountEJB" (2) public void ejbpostcreate(string owner, int accountno) { public void credit(int amount) { Nichttrivial nur, wenn eigene setbalance(getbalance() + amount); Objektidentität verarbeitet wird. public void debit(int amount) throws InsufficientFundsException { int oldbalance = getbalance(); if (amount > oldbalance) throw new InsufficientFundsException(); else setbalance(oldbalance - amount); // EJB Lifecycle Callback Methods public void ejbremove() { public void ejbactivate() { public void ejbpassivate() { public void setentitycontext(entitycontext ec) { public void unsetentitycontext() { public void ejbload() { public void ejbstore() { Speichern des Entity Context meist sinnvoll (Zugang zu weiterer Information) Trivial nur im Falle der Container Managed Persistence! Und wer kümmert sich um die Datenbank? Quellcode der Entity Bean ist völlig unabhängig vom unterliegenden Persistenz-Mechanismus. "Deployment"-Zeitpunkt: Festlegung der konkreten Datenbank Sun Referenzumgebung:» Einfaches relationales Datenbanksystem "Cloudscape"» Vordefinierte Datenbanken und JNDI-Namen Notwendige Informationen im Deployment Tool / Descriptor Seite 10
Und wer implementiert die "find"-methoden? Methoden findbyprimarykey und findbyowner tauchen im Quellcode der EJB Class nicht auf (da CMP verwendet)! Aufruf der Methoden in der Referenzimplementierung: Fehler, z.b.: "javax.ejb.ejbexception: No SQL statement for findbyprimarykey" Implementierungen der "find"-methoden bei CMP: Bei relationalen Datenbanken als Persistenzmechanismus:» Abbildung auf SQL-Abfragen findbyprimarykey:» automatisch erzeugbar aus den gegebenen Informationen findbyowner (und alle anderen benutzerdefinierten find-methoden):» Spezifikation mittels Deployment-Werkzeug in der plattformunabhängigen Sprache "EJB-QL" (EJB-Query Language)» Ablage im Deployment Descriptor (also "mit verpackt")»übersetzung meist nach SQL, ggf. auch andere Behandlung je nach Laufzeitumgebung Beispiel: Erzeugung von SQL-Code Gleicher Mechanismus für Manipulation von Tabellen und findbyprimarykey() Seite 11
Beispiel: EJB-QL für "findbyowner" FROM Account o WHERE o.owner =?1 Enterprise Java Beans Query Language (EJB QL) Abfragen über Entity Beans mit Container-Managed Persistence Stark angelehnt an SQL, aber: optimierbar bei Übersetzung auf SQL portierbar jenseits proprietärer SQL-Dialekte, sogar jenseits RDBMS Syntax: [ <select_clause> ] <from_clause> [ <where_clause> ] <select_clause>: unnötig, wenn <from_clause> nur eine freie Variable enthält <from_clause>:» Navigation über Referenzen (d.h. über Kollektionen): FROM OrderBean o, l IN o.lineitems» Navigation zu entfernten Objekten: =>-Operator <where_clause>:» Eingabeparameter:?n für n-ten Parameter (Anfang bei 1)» Arithmetische Ausdrücke, Bereiche, Mustervergleich von Zeichenreihen,... Seite 12
Client-Programm für Account EJB (Auszug) import javax.naming.context; import javax.naming.initialcontext; import java.rmi.remoteexception; import javax.rmi.portableremoteobject; public class SimpleAccountClient { private static void printaccount(account acc) throws RemoteException { System.out.println("Account no "+acc.getaccountno()+" status "+"(owner = "+acc.getowner()+")"); System.out.println("balance = "+acc.getbalance()); public static void main(string[] args) { try { Context ictx = new InitialContext(); Object acctref = ictx.lookup("hh14account"); AccountHome accthome = (AccountHome)PortableRemoteObject.narrow (acctref,accounthome.class); Account acc1 = accthome.create("hussmann",55); printaccount(acc1); acc1.credit(1000); printaccount(acc1);... Der Persistenz-Effekt Mehrfacher Aufruf des einfachen Client-Programms führt zu verschiedenen Ergebnissen: Erster Aufruf: OK Weitere Aufrufe: javax.ejb.duplicatekeyexception: Duplicate primary key Mehrere unabhängige Programme können auf der gleichen Entity Bean arbeiten! Entity Beans bleiben sogar über Systemabschaltungen, die meisten "Abstürze" etc. hinweg erhalten! Seite 13
Beispiel: Client-Programm zur Abfrage import javax.naming.context; import javax.naming.initialcontext; import java.rmi.remoteexception; import javax.rmi.portableremoteobject; import java.util.*; public class FindAccountClient { private static void printaccount(account acc) { public static void main(string[] args) { try { Context ictx = new InitialContext(); Object acctref = ictx.lookup("hh14account"); AccountHome accthome = (AccountHome)PortableRemoteObject.narrow (acctref,accounthome.class); Iterator it = (accthome.findbyowner("hussmann")).iterator(); while (it.hasnext()) printaccount((account)it.next()); catch (Exception ex) {... Persistente Beziehungen zwischen EJBs Eine EJB kann dauerhafte Beziehungen (relationships) zu anderen EJBs und abhängigen Klassen besitzen. eins-zu-eins, eins-zu-viele, viele-zu viele einseitig oder beidseitig navigierbar Prinzipielle Realisierung bei CMP: Container-managed persistent fields mit Referenzen auf Remote Interface» "container managed relationships" Für "zu-viele"-beziehungen: java.util.collection Referentielle Integrität und Multiplizität werden vom Container sichergestellt» Auffinden von referenzierten Objekten (auch remote)» Redundante Referenzen in lokalen Feldern werden automatisch synchron gehalten» Typüberprüfung von Kollektionen, die Beziehungen realisieren Seite 14
Bean Managed Persistence (BMP) Wichtigste Unterschiede zur Container Managed Persistence: EJB Class greift direkt auf Speichermedium zu (z.b. Datenbank via JDBC) Datenbankschema muß explizit angelegt werden Aufwendigere Codierung; u.u. schlechtere Portabilität Keine automatische Verwaltung von Beziehungen Keine Unterschiede in Home/Remote Interface! Client-Programm kennt die Realisierungsvariante (CMP/BMP) nicht. Ausführliches Beispiel zu Bean Managed Persistence: Sun J2EE Developer's Guide (siehe Vorlesungs-Homepage) Beispiel: EJB Class mit BMP "AccountEJB" (1) import java.sql.*; import javax.sql.*; import java.util.*; import javax.ejb.*; import javax.naming.*; public class AccountEJB implements EntityBean { private int accountno; private String owner; private double balance; private Connection con; Lokale Variablen zum Zwischenspeichern persistenter Informationen private String dbname = "java:comp/env/jdbc/accountdb"; public Integer ejbcreate(string owner, int accountno) { try { insertrow(accountno, owner, balance); catch (Exception ex) { throw new EJBException(); this.accountno = accountno; this.owner = owner; this.balance = 0; return new Integer(accountNo);... Bei BMP: Primärschlüsselwert zurückgeben Seite 15
Beispiel: EJB Class mit BMP "AccountEJB" (2) // Beispiel einer lokalen Hilfsmethode (JDBC) // Hier werden die Daten persistent abgelegt private void insertrow (int accountno, String owner, int balance) throws SQLException { String insertstatement = "insert into account values (?,?,? )"; PreparedStatement prepstmt = con.preparestatement(insertstatement); prepstmt.setinteger(1, accountno); prepstmt.setstring(2, owner); prepstmt.setinteger(3, balance); prepstmt.executeupdate(); prepstmt.close();... Beispiel: EJB Class mit BMP "AccountEJB" (3) // Fachliche Methoden (credit, debit) kaum anders als bei CMP: // Hier weggelassen! public int getaccountno() { return accountno;... public Integer ejbfindbyprimarykey(integer primarykey) throws FinderException { boolean result; try { result = selectbyprimarykey(primarykey); catch (Exception ex) { throw new EJBException(); if (result) { return primarykey; else { throw new ObjectNotFoundException... Get- und Set-Methoden des Remote Interface explizit programmiert Suchmethoden explizit programmiert (Ergebnis Primärschlüssel, nicht Remote Interface) ("Row for id " + primarykey + " not found."); Seite 16
Beispiel: EJB Class mit BMP "AccountEJB" (4) public void setentitycontext(entitycontext context) { try { makeconnection(); catch (Exception ex) { throw new EJBException(); public void ejbload() { // ejbstore() analog! try {... loadrow(); catch (Exception ex) { throw new EJBException(); // makeconnection(), loadrow(): // Explizite Datenbankzugriffe mit JDBC EJB Lifecycle Methoden explizit programmiert (nicht nur "Callback-Methoden") Life Cycle einer Entity Bean does not exist 1. newinstance() 2. setentitycontext() unsetentitycontext() 1. ejbcreate() 2. ejbpostcreate() ejbactivate() pooled ejbpassivate() ejbfind... ejbselect... ejbhome... ejbremove() ready ejbload() ejbstore() fachliche Methoden Seite 17