Enterprise Java Beans - Teil 2 ■ Aspektorientierte Programmierung ■ Session Beans ■ Entity Beans Einführung ■ EJB Client Aspektorientierte Programmierung Concerns School of Engineering © K. Rege, ZHAW 2 von 54 Aspektorientierte Programmierung ■ Software hat verschiedene Arten von Anforderungen: ■ technische Anforderungen (System Level Concerns), z.B. Security, Logging, Persistenz ■ nicht/schlecht modellierbar/umsetzbar durch OOP ■ nicht funktionale Anforderungen: z.B. Performance, Stabilität, Benutzbarkeit, etc. ■ abgedeckt durch System-Architektur, Projektvorgehensweise, etc. ■ sind allgemeine, nicht im Code lokalisierte Anforderungen School of Engineering A sp ek t Konto Bankkonto Bankkonto BankService Bank Bank Kunde Bestellung Bestellung Rechnung Rechnung Rechnung Security Klassen e funktionale Anforderungen (Core Level Concerns*): z.B. Bankkonto ■ gut modellierbar/umsetzbar mittels OOP Logging Persistenz ■ © K. Rege, ZHAW *Concern : Anforderung 3 von 54 Probleme ■ Probleme bei der Umsetzung der technischen Anforderungen in traditioneller Art und Weise: ■ Aufruf von Behälter-Funktionen im Anwendungs-Code Aufrufe: Aufrufe:imperative imperativeForm Form public public void void deposit(double deposit(double amount) amount) {{ UserTransaction UserTransaction ut ut == sc.getUserTransaction(); sc.getUserTransaction(); ut.begin(); ut.begin(); if if (sc.isCallerInRole("Custormer") (sc.isCallerInRole("Custormer") {{ saldo saldo += += amount; amount; logger.info("deposit logger.info("deposit "" ++ amount amount ++ "" for for "" ++ Prinzipal.getName(); Prinzipal.getName(); }} ut.commit(); ut.commit(); }} ■ Dies führt zu: ■ ■ Code-Tangling (Durcheinander): gleichzeitige Präsenz mehrerer Aspekte in einer Klasse: schlechte Lesbarkeit, Wartbarkeit Code-Scattering (Streuung): Verteilung eines Aspekt über verschiedene Klassen: erschwert Wartbarkeit, verletzt das Kapselungsprinzip School of Engineering © K. Rege, ZHAW 4 von 54 Eigenschaften von Aspekten, Begriffe ■ Concern: Anforderung an die Funktionalität eines Programm ■ Core Level Concern ■ Hauptanforderung an Komponente (anwendungsspezifisch) ■ Cross Cutting oder System Level Concerns als Aspekte umgesetzt ■ ■ ■ ■ ■ sind orthogonal zur Objektfunktionalität sind schwer getrennt kapselbar haben mehrfaches Auftreten in verschiedenen Objekten behindern Wiederverwendung der Objekte senken Verständlichkeit ■ Typische Stellen im Programmfluss, wo Aspekte ansetzen: Joint Points ■ ■ ■ ■ vor, nach Aufruf von Methoden vor, nach dem Setzen von Feldern bei der Instanzierung von Objekten, Erzeugung der Klasse im Fehlerfall ■ Advise: Code des Aspekts, der bei Erreichen des Joint Points ausgeführt wird School of Engineering © K. Rege, ZHAW 5 von 54 Lösungen ■ Lösungsansatz 1 (bis EJB 2.1) oder Spring Framework ■ ■ Herausziehen der Aspekte in separate Descriptor-Dateien deklarative Form: was aber nicht wie (Umsetzung Aufgabe des Containers) <enterprise-beans> <enterprise-beans> <session> <session> <ejb-name>Konto</ejb-name> <ejb-name>Konto</ejb-name> <transaction-type>Container</transaction-type> <transaction-type>Container</transaction-type> …… …… public public void void deposit(double deposit(double amount) amount) {{ saldo saldo += += amount; amount; }} +Separation von technischen Aspekten + Zur Laufzeit konfigurierbar - getrennt von Code; schwer wartbar, fehleranfällig ■ Lösungsansatz 2 (ab EJB 3) ■ Einflechten der Aspekte durch klar abgetrennte Anweisung in deklarativer Form @Tx(TxType.REQUIRED) @Tx(TxType.REQUIRED) @MethodPermission({"customer"}) @MethodPermission({"customer"}) @AroundInvoke @AroundInvoke public public void void deposit(double deposit(double amount) amount) {{ }} Annotationen: Annotationen:deklarative deklarativeForm Form saldo saldo += += amount; amount; School of Engineering © K. Rege, ZHAW 6 von 54 Technische Umsetzung ■ Zwei Mechanismen wie mit Aspekten umgegangen wird ■ Interception von Aufrufen durch Container ■ ■ ■ ■ Unterbrechung des Programmflusses zur Behandlung eines Concerns Vorher-Interception Nachher-Interception Anstatt-Interception ■ Dependency Injection von Werten in Bean durch Container ■ ■ Container "impft" die Werte/Verweise in Beans ein; Stellen für das "Einimpfen" sind entsprechend markiert durch durchBean Bean injection vs lookup @Resource @Resource public publicDataSource DataSourceDozentenDS DozentenDS; ; durch Container durch Container School of Engineering © K. Rege, ZHAW 7 von 54 Java Annotationen in Java 5 ■ Die wichtigste Neuerung in Java 5 überhaupt ■ Imperative Programmierung: es wird beschrieben, wie etwas gemacht wird ■ Deklarative Programmierung: es wird beschrieben, was gemacht wird Every Every new new release release of of Java Java has has introduced introduced new new features, features, but but few few warrant warrant aa new new way way of of thinking thinking to to realize realize their their full full potential. potential. Using Using annotations annotations effectively effectively to to simplify simplify programming programming in in Java Java requires requires aa shift shift in in our our thought thought processes. processes. N. N. Jayaratchagan Jayaratchagan OnJava OnJava (siehe (siehe Anhang) Anhang) Combined Combined with with JDK JDK 1.5 1.5 Annotations, Annotations, aspects aspects (AOP) (AOP) also also is is aa great great way way to to expand expand the the Java Java language language in in aa clean clean pluggable pluggable way way rather rather than than using using annotations annotations solely solely for for code code generation. generation. JBoss JBoss AOP AOP is is not not only only aa framework, framework, but but also also aa prepackaged prepackaged set set of of aspects aspects that that are are applied applied via via annotations, annotations, pointcut pointcut expressions, expressions, or or dynamically dynamically at at runtime. runtime. Anil Anil Saldhana Saldhana of of JBoss JBoss School of Engineering © K. Rege, ZHAW 8 von 54 Java Annotation in Java 5 ■ Definition eines Annotations-Typs ■ @-Zeichen vor "ganz normales" Interface public public @interface @interface Obsolete{} Obsolete{} ■ Verwendung: ■ vor die Klasse (die Methode, Feld, Parameter) kann die so definierte Annotation im eigenen Code gesetzt werden @Obsolete @Obsolete public class MyClass { } public class MyClass { } ■ Annotationen werden vom Compiler überprüft (-> import notwendig) @Obsolete @Obsolete class class MyClass MyClass // // OK OK @Obsolete() class MyClass // @Obsolete() class MyClass // OK OK @Obsolete("löschen") class MyClass @Obsolete("löschen") class MyClass // // Compilerfehler Compilerfehler School of Engineering © K. Rege, ZHAW 9 von 54 Java Annotation mit Parametern 1 ■ Definition: eine "value"-Methode mit dem gewünschten Typ als Rückgabewert public public @interface @interface Obsolete{ Obsolete{ String value(); String value(); }} ■ Verwendung: ■ muss muss"value" "value"heissen heissen es kann ein Parameter (z.B. String) der Annotation übergeben werden @Obsolete("löschen") @Obsolete("löschen") public class MyClass { } public class MyClass { } ■ Definition: beliebige Anzahl Parameter werden mit Namen versehen public public @interface @interface Obsolete Obsolete {{ String String useInstead(); useInstead(); int int reason(); reason(); }} ■ Verwendung: als Namen "=" Wert Parameter: "Named-Value" Parameter @Obsolete(useInstead="MyNewClass", @Obsolete(useInstead="MyNewClass", reason=1) reason=1) vom vomCompiler Compilerüberprüft überprüft School of Engineering © K. Rege, ZHAW 10 von 54 Java Annotation mit Parametern 2 ■ Definition: mehrdimensionale Parameter (als Arrays) public public @interface @interface Obsolete Obsolete {{ String[] String[] useInstead(); useInstead(); }} ■ Verwendung: ■ es kann ein einzelner Wert oder als Array von Werten übergeben werden @Obsolete(useInstead = "MyNewClass") @Obsolete(useInstead = "MyNewClass") oder oder @Obsolete(useInstead = {"MyNewClass", "MyOtherNewClass"}) @Obsolete(useInstead = {"MyNewClass", "MyOtherNewClass"}) ■ Definition: Enum Werte als Parameter (Enum-Typ ebenfalls neu in Java 5) public public @interface @interface Obsolete Obsolete {{ enum Reason {OLD,BUG,SECURITY}; enum Reason {OLD,BUG,SECURITY}; Reason Reason reason(); reason(); }} ■ Verwendung: @Obsolete(reason=Obsolete.Reason.SECURITY) @Obsolete(reason=Obsolete.Reason.SECURITY) School of Engineering © K. Rege, ZHAW 11 von 54 Parameter Default Werte und Built-In Annotationen ■ Default-Werte für nicht gesetzte Parameter können definiert werden public public @interface @interface Obsolete Obsolete {{ enum enum Reason Reason {{ OLD, OLD, BUG, BUG, SECURITY SECURITY }} String[] String[] useInstead() useInstead() default default "MyNewClass" "MyNewClass" ;; Reason reason() default Reason.BUG Reason reason() default Reason.BUG ;; }} ■ Vordefinierte Java 5 Annotationen ■ gibt an, dass eine Methode eine andere überschreiben möchte @Override @Override ■ gibt an, dass eine Methode veraltet ist -> entsprechende Warnung bei der Compilation @Deprecated @Deprecated ■ gibt an, dass Warnungen nicht angezeigt werden sollen @SuppressWarnings @SuppressWarnings School of Engineering © K. Rege, ZHAW 12 von 54 Attribute zur Definition von Annotation ■ Die Verwendungseigenschaften der Attribute, wird ebenfalls durch Attribute festgelegt @Target Art der annotierten Entität Klasse, Methode, …? @Retention Sichbarkeit der Annotation. Compiler oder auch zur Laufzeit? @Documented Annotation soll Teil der javadoc Dokumentation sein @Inherited Annotation sind auch für Nachfolge-Entitäten (z.B. in der erbenden Klasse) gültig import import static static java.lang.annotation.ElementType.*; java.lang.annotation.ElementType.*; @Target( @Target( {{ TYPE, TYPE, METHOD, METHOD, CONSTRUCTOR, CONSTRUCTOR, PACKAGE PACKAGE }} )) @Retention( value=RUNTIME ) @Retention( value=RUNTIME ) @Documented @Documented public public @interface @interface Obsolete Obsolete {{ ... ... }} School of Engineering © K. Rege, ZHAW 13 von 54 Auslesen von Annotationen ■ Auslesen über die Klasse (Reflection) Class Class cc == MyClass.class; MyClass.class; ■ oder wenn Instanz vorhanden Class Class cc == myClass.getClass() myClass.getClass() ■ für die Klassen-Annotationen von der Klasse die Methode getAnnotations aufrufen Obsolete Obsolete obsolete obsolete == c.getAnnotation(Obsolete.class); c.getAnnotation(Obsolete.class); System.out.print(obsolete.value()); System.out.print(obsolete.value()); ■ Auslesen von Methoden-Annotationen Method[] methods = c.getDeclaredMethods(); Method[] methods = c.getDeclaredMethods(); for(Method m : methods) { for(Method m : methods) { Obsolete obsolete = m.getAnnotation(Obsolete.class); Obsolete obsolete = m.getAnnotation(Obsolete.class); if(obsolete !=null) { if(obsolete !=null) { System.out.print(obsolete.value(); System.out.print(obsolete.value(); } } } } School of Engineering © K. Rege, ZHAW 14 von 54 Annotation: Vor- und Nachteile ■ Vorteile ■ ■ ■ ■ ■ Trennung von Core und System Level Concerns Schritt in Richtung deklarative Programmierung Teil der Java Sprache ■ Vom Compiler überprüft (im Gegensatz zu früheren Ansätzen XDoclet) Die Abhängigkeiten zur Umgebung können explizit und damit überprüfbar gemacht werden Stehen an der Stelle im Code auf den sie wirken (Kapselungsprinzip) ■ Nachteile ■ ■ An die Programmquelle gebunden Können nicht nachträglich ohne Neukompilation geändert werden (im Gegensatz zu externen Konfigurationsdateien) School of Engineering © K. Rege, ZHAW 15 von 54 Entwicklung der Logik in EJB 3 Session Beans School of Engineering © K. Rege, ZHAW 16 von 54 W Java Enterprise Edition Architektur ied er ho lu ng ■ Die EJB Architektur beschreibt die Verantwortlichkeiten und Interaktionen folgender Teile Application ApplicationServer Server EJB EJBClient Client Enterprise EnterpriseJavaBeans JavaBeans EJB EJBContainer Container Object ObjectRequest RequestBroker Broker Data DataSources Sources EJB EJBClient, Client, z.B. Tomcat z.B. Tomcat Enterprise Enterprise JavaBean JavaBean EJB Container z.B. JBoss Object Request Broker (ORB) Application Server School of Engineering © K. Rege, ZHAW 17 von 54 W Enterprise JavaBean (EJB) ied er ho lu ng ■ Komponenten die Anwendungslogik enthalten ■ Meist mehrere, Anwendungsdomänen spezifisch: Kunde, Konto, etc. ■ Implementiert zwei Arten von Schnittstellen: ■ ■ fachliche, so dass Anwendung strukturiert wird technische, so dass sie vom EJB Container verwaltet werden kann ■ Nimmt Dienste des EJB Containers in Anspruch ■ Kann (meist) über das Netzwerk angesprochen werden Enterprise Enterprise JavaBean JavaBean School of Engineering © K. Rege, ZHAW 18 von 54 W Entwurf: Wahl von Enterprise Bean Typ ied er ho lu ng ■ Meist eindeutig durch Zweck und/oder Eigenschaften bestimmt ■ Prozess/kein Zustand -> Session Bean ■ Mit Zustand als Teil von Prozess -> Entity Bean ■ Mit Zustand entfernter Zugriff -> Session + Entity Bean ■ Schnittstelle zu anderem System MDB Hat Hatpersistenten persistentenZustand, Zustand, wird lokal über BankService wird lokal über BankService angesprochen angesprochen hat hatkeinen keineneigenen eigenenZustand, Zustand, verarbeitet verarbeitetlediglich lediglichDaten, Daten, wird entfernt zugegriffen wird entfernt zugegriffen <<Entity Bean>> <<Entity Bean>> Konto Konto <<Session Bean>> <<Session Bean>> BankService BankService <<Entity Bean>> <<Entity Bean>> Vertrag Vertrag <<MDB>> <<MDB>> BankVerbindung BankVerbindung School of Engineering © K. Rege, ZHAW Verbindung Verbindungzu zuanderer andererBank Bank 19 von 54 Hello Session Bean Es gibt zwei Typen von Session Beans: Stateless und stateful Stateless Session Bean Stateless Session Bean HelloSessionBean.java package package trail; trail; HelloSession.java package package trail; trail; import import javax.ejb.*; javax.ejb.*; import javax.annotation.*; import javax.annotation.*; public public interface interface HelloSession HelloSession {{ public String hello public String hello (); (); }} @Stateless @Stateless @Remote @Remote (HelloSession.class) (HelloSession.class) public class public class HelloSessionBean HelloSessionBean {{ public String public String hello() hello() {{ return return "Hello "Hello Session Session Bean"; Bean"; }} }} Konfigurations-Datei Konfigurations-Dateiim im EAR EAR School of Engineering Remote RemoteInterface Interface application.xml <?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?> <application xmlns="http://java.sun.com/xml/ns/j2ee" <application xmlns="http://java.sun.com/xml/ns/j2ee" version="1.4"> version="1.4"> <module> <module> <ejb>beans.jar</ejb> <ejb>beans.jar</ejb> </module> </module> </application> </application> © K. Rege, ZHAW 20 von 54 Hello Session Bean Klient ■ Klient verbindet mit Session Bean über JNDI - Lookup ■ Aufruf mittels RMI index.jsp <%@ <%@ page page import="trail.*, import="trail.*, javax.naming.*, javax.naming.*, java.text.*, java.text.*, Lookup java.util.*"%> Lookup java.util.*"%> Namen <%! Namenaus ausServerLog ServerLogentnehmen entnehmen <%! private HelloSession helloBean = null; private HelloSession helloBean = null; public public void void jspInit jspInit () () {{ InitialContext ctx InitialContext ctx == new new InitialContext(); InitialContext(); helloBean = (HelloSession) helloBean = (HelloSession) ctx.lookup("java:global/trail.HelloSession"); ctx.lookup("java:global/trail.HelloSession"); }} %> %> <html><head/> <html><head/> <body> <body> <h1><%= <h1><%= helloBean.hello() helloBean.hello() %></h1> %></h1> </body> </body> </html> </html> web.xml Aufruf Aufrufvon vonBean BeanMethode Methode School of Engineering © K. Rege, ZHAW … … … … … … … … … … … … 21 von 54 Stateless Session Bean SLSB ■ Speichert keine Information zwischen den Aufrufen; ■ Stateless Session Beans werden in einem Pool verwaltet ■ ■ Zur Starzeit wird eine gewisse Anzahl Bean Instanzen initial erzeugt und in den Pool gesteckt Bei einem Aufruf wird die Verarbeitung einfach der nächsten freien Instanz zur Bearbeitung übergeben ■ Sie sind gerade während des Aufrufs einem Client zugeordnet; ■ Stateless Session Beans sind ■ ■ Effizienter als stateful SB weil besserer Umgang mit Resourcen Location transparent, d.h. der nächste Aufruf kann auf einen anderen Server umgeleitet werden; wichtig für Load-Balancing in verteilten Umgebungen ■ Load Balancing: die Last wird auf die verfügbaren Server (oder Knoten in Server Verbund) gleichmässig verteilt School of Engineering © K. Rege, ZHAW 22 von 54 Interfaces von Stateless Session Beans ■ Über Annotationen werden Local und Remote Interface bestimmt ■ Diese müssen von keinen Spezialinterfaces erben (wie in EJB 2.1) und müssen keine Remote-Exception werfen HelloSession.java package package trail; trail; HelloSessionBean.java import import javax.ejb.*; javax.ejb.*; import javax.annotation.*; import javax.annotation.*; public public interface interface HelloSession HelloSession {{ public String hello public String hello (); (); }} @Stateless @Stateless @Remote @Remote (HelloSession.class) (HelloSession.class) @Local (HelloSessionLocal.class) @Local (HelloSessionLocal.class) public public class class HelloSessionBean HelloSessionBean implements implements HelloSesion, HelloSesion, HelloSessionLocal{ HelloSessionLocal{ }} ■ Falls kein Interface angeben wird, dann sind automatisch alle public Methoden Teil des Local-Interfaces HelloSessionLocal.java package package trail; trail; public public interface interface HelloSessionLocal HelloSessionLocal {{ public public String String hello hello (); (); }} ■ Falls nur Remote angegeben ist (ohne Interface-Bezeichnung) dann sind alle Methoden Teil des Remote-Interfaces School of Engineering © K. Rege, ZHAW 23 von 54 Pooling ■ Durch Lookup via JNDI wird eine Remote Referenz erstellt InitialContext InitialContext ctx ctx == new new InitialContext(); InitialContext(); helloBean = (HelloSession) helloBean = (HelloSession) ctx.lookup("java:global/trail.HelloSession"); ctx.lookup("java:global/trail.HelloSession"); helloBean.hello() helloBean.hello() ■ ■ ■ ■ ■ Der Aufruf wird vom EJB Server abgefangen (Interception) dieser leitet dann diesen an ein gerade verfügbares, freies Session Bean Instanz aus dem Pool weiter Falls keine freien Instanzen verfügbar, dann werden neue erzeugt Wenn der Aufruf beendet ist, dann wird das Bean in den Pool zurückgegeben beim nächsten Aufruf wird der Client – mit einer grossen Wahrscheinlichkeit – mit einer anderen Bean Instanz arbeiten School of Engineering © K. Rege, ZHAW Enterprise Java Beans O'Reilly 24 von 54 Threading ■ Das SLSB selber ist single-threaded, d.h. es befindet sich jeweils nur ein Thread in Bearbeitung innerhalb eines Beans: Container weist einem neuen Aufrufer jeweils ein eigenes SLSB und Thread zu ■ EJBs sollen selber keine Threads starten, sondern das dem EJB Container überlassen. ■ Ist eine nicht immer leicht einzuhaltende Einschränkung (z.B. bei Verwendung von Log4J) Instance Pool School of Engineering © K. Rege, ZHAW 25 von 54 Lebenszyklus von Stateless Session Beans ■ Das Bean kann sich über Zustandsänderungen via Callback informieren lassen d.h. falls irgendwelche Initialisierungs-/Aufräumarbeiten durchgeführt werden müssen, könne Methoden entsprechend annotiert werden ■ HelloSessionBean.java import import javax.ejb.*; javax.ejb.*; import javax.annotation.*; import javax.annotation.*; @Stateless @Stateless public public class class HelloSessionBean HelloSessionBean {{ @PreDestroy @PostConstruct @PostConstruct public public void void initialieren() initialieren() {{ …… }} @PreDestroy @PreDestroy public public void void aufräumen() aufräumen() {{ …… }} @PostConstruct Enterprise Java Beans O'Reilly }} ■ @PostConstruct: The annotated method is called by the container immediately after a bean instance is instantiated. ■ @PreDestroy: The annotated method is called before the container destroys an unused or expired bean instance from its object pool. School of Engineering © K. Rege, ZHAW 26 von 54 Wieso ist stateless effizient - Taxi Analogie Stateless: Flughafen Taxi ■ ich benutze einfach nächstes freies Taxi aus der Taxi Warteschlage ■ Vorteil: ■ Taxi wird optimal ausgenutzt; Voraussetzung: gute Balance zwischen Anzahl Kunden und Taxis ■ Nachteil: ■ ■ ■ alles was ich benötige muss ich mitnehmen darf nichts liegen lassen muss (ehrlichen?) Taxifahrer bezahlen Stateful : Privatwagen ■ Habe meinen Privatwagen am Flughafen parkiert ■ Vorteil: ■ ■ kann etwas dort deponieren mein Auto ist sicher verfügbar ■ Nachteil: Wagen wird schlecht ausgenutzt (steht herum) ■ Parkplatz kann voll sein ■ Ich muss (hohe) Parkgebühren bezahlen School of Engineering © K. Rege, ZHAW ■ 27 von 54 Stateful Session Bean SFSB ■ Stateful: Zustand wird zwischen Client-Aufrufen gehalten; eine Instanz ist über mehrere Methodenaufrufe explizit einem Client zugeordnet ■ Bleiben dem Klienten zugeordnet bis sie ■ mittels remove() vom Klienten wieder freigegeben werden. ■ nach einem bestimmten Timeout, vom Server selbständig freigegeben werden (Annahme: Klient hat Verbindung verloren oder ist abgestürzt) ■ Stateful Session Beans sind: ■ ■ ■ weniger Effizient, da Instanzen aufbewahrt und wieder zugeordnet werden müssen nicht „location transparent“ (Ortsunabhängig) weil der Zustand typischerweise im Hauptspeicher oder Dateisystem des Servers gespeichert wird Herstellerabhängige Lösungen für Server-Cluster School of Engineering Enterprise Java Beans O'Reilly © K. Rege, ZHAW 28 von 54 Interfaces, Aufruf ■ Stateful Session Beans werden mit @stateful gekennzeichnet ■ Stateful SB muss Serializable implementieren ■ Bean dem Klient zugeordnet: Typische Anwendung ShoppingCart: ■ Inhalt bleibt des Einkaufswagens bleibt während der Session erhalten ShoppingCartBean.java @Stateful @Stateful public public class class ShoppingCartBean ShoppingCartBean implements implements Serializable Serializable {{ @PostConstruct @PostConstruct @PostActivate @PostActivate public void initRemoteConnectionToAccountSystem() public void initRemoteConnectionToAccountSystem() {{ ...} ...} @PreDestroy @PreDestroy @PrePassivate @PrePassivate public public void void closeRemoteConnectionToAccountSystem() closeRemoteConnectionToAccountSystem() {{ ...} ...} }} @Remove @Remove public public void void checkout() checkout() {{ ... ... }} public addArticle(String article( public addArticle(String article( ... ... }} ■ Definition der Interfaces gleich wie bei stateless SB ■ Zusätzlicher Zustand: "Passive": länger nicht mehr gebrauchte Objekte werden aus dem Hauptspeicher entfernt School of Engineering © K. Rege, ZHAW 29 von 54 Callbacks ■ Passivate-> Objekt wird serialisiert und aus dem Speicher entfernt ■ Activate -> Objekt wird deserialisiert und wieder instanziert ■ alle Instanzvariablen, die nicht serialisiert wurden, müssen wieder hergestellt werden @Init @PostConstruct @PreDestroy @Remove @PrePassivate @PostActivate School of Engineering © K. Rege, ZHAW Enterprise Java Beans O'Reilly 30 von 54 Callback Annotationen ■ @PostConstruct: see stateless session bean ■ @PreDestroy: see stateless session bean ■ @PrePassivate: If a stateful session bean instance is idle for too long, the container may passivate it and store its state to a cache. The method tagged by this annotation is called before the container passivates the bean instance. This annotation is applicable only to stateful session beans. ■ @PostActivate: When the client uses the passivated stateful session bean again, a new instance is created and the bean state is restored. The method that tagged this annotation is called when the activated bean instance is ready. This annotation is only applicable to stateful session beans. ■ @Remove tag. It is not a callback method since the application, not the container, calls the @Remove method on the bean stub to remove the bean instance in the container object pool. ■ @Init: This annotation designates initialization methods for a stateful session bean. It is different from the @PostConstruct annotation in that multiple methods can be tagged with @Init in a stateful session bean. However, each bean instance can have only one @Init method invoked. The EJB 3.0 container determines which @Init method to invoke depending on how the bean is created (see the EJB 3.0 specification for details). The @PostConstruct method is called after the @Init method. School of Engineering © K. Rege, ZHAW 31 von 54 ejb-jar.xml ■ Anstatt mit Annotationen zu arbeiten kann auch weiterhin mit Werten im Deployment Descriptor gearbeitet werden. ■ Werte im Deployment Descriptor haben Vorrang <ejb-jar> <ejb-jar> <description>jBoss <description>jBoss test test application application </description> </description> <display-name>Test</display-name> <display-name>Test</display-name> <enterprise-beans> <enterprise-beans> <session> <session> <ejb-name>Teller</ejb-name> <ejb-name>Teller</ejb-name> <remote>org.jboss.ejb3.test.bank.Teller</remote> <remote>org.jboss.ejb3.test.bank.Teller</remote> <ejb-class>org.jboss.ejb3.test.bank.TellerBean</ejb-class> <ejb-class>org.jboss.ejb3.test.bank.TellerBean</ejb-class> <session-type>Stateless</session-type> <session-type>Stateless</session-type> <transaction-type>Container</transaction-type> <transaction-type>Container</transaction-type> </session> </session> <enterprise-beans> <enterprise-beans> <ejb-jar> <ejb-jar> School of Engineering © K. Rege, ZHAW 32 von 54 Paketierung: EAR Datei ■ Archive Format für EJB Anwendungen myEJB.ear META-INF application.xml Beschreibung Beschreibungder derEAR EAR Datei Datei beans.jar META-INF zusätzliche zusätzlicheBeschreibung Beschreibung der derEnterprise EnterpriseBeans Beans (optional) (optional) ejb-jar.xml MyBean.class EJB Klassen EJB Klassen web.war hello.jsp WEB WEBKlassen Klassen <ear <ear destfile="${build.dir}/myapp.ear" destfile="${build.dir}/myapp.ear" appxml="${src.dir}/metadata/application.xml"> appxml="${src.dir}/metadata/application.xml"> <fileset <fileset dir="${build.dir}" dir="${build.dir}" includes="*.jar,*.war"/> includes="*.jar,*.war"/> </ear> </ear> School of Engineering © K. Rege, ZHAW 33 von 54 application.xml ■ Beschreibt Struktur der EAR Datei ■ Hat sich seit EJB 3 stark vereinfacht <?xml <?xml version="1.0" version="1.0" encoding="UTF-8"?> encoding="UTF-8"?> <application xmlns="http://java.sun.com/xml/ns/j2ee" <application xmlns="http://java.sun.com/xml/ns/j2ee" version="1.4" version="1.4" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/application_1_4.xsd"> http://java.sun.com/xml/ns/j2ee/application_1_4.xsd"> <display-name>trail</display-name> <display-name>trail</display-name> <description>Einfaches <description>Einfaches Beispiel</description> Beispiel</description> <module> <module> <ejb>beans.jar</ejb> <ejb>beans.jar</ejb> </module> </module> EJB Klassen EJB Klassen <module> <module> <web> WEB <web> WEBKlassen Klassen <web-uri>web.war</web-uri> <web-uri>web.war</web-uri> <context-root>trail</context-root> <context-root>trail</context-root> </web> </web> </module> </module> </application> </application> School of Engineering Zugriff Zugriffmit mitlocalhost:8080/trail localhost:8080/trail © K. Rege, ZHAW 34 von 54 Zusammenfassung Session Beans ■ Session Beans: die Fachlogik Komponenten ■ Sind mit @Stateless oder @Stateful gekennzeichnet ■ Stateless Session Beans: SLSB ■ ■ ■ es wird kein Zustand zwischen den Aufrufen gespeichert können in Pool verwaltet werden effizient ■ stateful Session Beans: SFSB ■ ■ ■ halten den Zustand so lange, wie vom Klient Referenz existiert können schlecht/nicht in Pool verwaltet werden sind weniger effizient als SLSB ■ Callbacks bei den Zustandsübergängen ■ Paketierung in EAR Datei School of Engineering © K. Rege, ZHAW 35 von 54 Einfacher Datenbank Zugriff School of Engineering © K. Rege, ZHAW 36 von 54 Datenbank Zugriff Innerhalb Session Beans ■ Datenbank-Zugriff in Java über JDBC Verbindung String String urlString urlString ="jdbc:odbc:odbcsourcename"; ="jdbc:odbc:odbcsourcename"; String username ="dba", String username ="dba", password password ="sql"; ="sql"; Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); Connection Connection con con == DriverManager.getConnection DriverManager.getConnection (urlString,username,password); (urlString,username,password); ■ Probleme ■ ■ ■ Datenbank-Treiber Typ ist hart kodiert: Unterhaltssproblem Die Initialisierungsstring der Datenbank ist im Programm hart kodiert: dito ebenso Benutzername und Passwort: Sicherheitsproblem ■ EJB-Lösung ■ ■ Datenbank-Parameter werden ausserhalb Anwendung (im Container) definiert Diesen Parametern wird ein symbolischer Namen zugewiesen: z.B. Dozenten und unter diesem ins JNDI Verzeichnis als DataSource eingetragen ■ Verwendung: InitialContext ctx = new InitialContext(); InitialContext ctx = new InitialContext(); DataSource DozentenDS = (DataSource) ctx.lookup("jdbc/myprofresource"); DataSource DozentenDS = (DataSource) ctx.lookup("jdbc/myprofresource"); Connection con = DozentenDS.getConnection(); Connection con = DozentenDS.getConnection(); …. …. con.close(); con.close(); School of Engineering © K. Rege, ZHAW 37 von 54 Verbindungsdaten im Container definiert ■ Die Verbindungsdaten werden (Ort, Passwort, etc) werden im Container spezifiziert Business Business Logic Logic associate associatevalid valid connection connection pool poolofof opened openedjdbc jdbc connections connections DataSource ds jdbc/myprofresource data source jndi jndiname name connection pool EJB Container z.B. Glassfish School of Engineering myprofpool © K. Rege, ZHAW 38 von 54 Zugriff auf die Daten ■ SQL Abfrage wie gewohnt ■ Prepared Statement verwenden um SQL-Injektion zu vermeiden ■ AutoCommit = false (Transaktionen werden i.d.R. vom Container gesteuert) Connection con = DozentenDS.getConnection(); con.setAutoCommit(false); logger.info("got connection"); PreparedStatement statement = con.prepareStatement("SELECT * FROM Dozenten WHERE name LIKE ?"); statement.setString(1, name + "%"); ResultSet rs = statement.executeQuery(); LinkedList list = new LinkedList(); while (rs.next()) { Professor st = new Professor(rs.getLong("SCHLUESSEL"), rs .getString("NAME"), rs.getString("FIRSTNAME")); list.add(st); } School of Engineering © K. Rege, ZHAW 39 von 54 Data Sources im Anwendungsserver ■ Beschreiben der DataSources im Anwendungsserver ■ Zusätzlicher Dienst: Connection Pooling ■ ■ ■ die Verbindungen werden nicht geöffnet und wieder geschlossen, sondern es wird mit einem Pool von geöffneten Verbindungen gearbeitet. schneller und billiger (wegen DB-Preis pro Verbindung) con.close() -> Rückgabe in Pool School of Engineering © K. Rege, ZHAW 40 von 54 Dependency Injection School of Engineering © K. Rege, ZHAW 41 von 54 Dependency Injection ■ Ist eine Form von Inversion of Control (IOC) ■ 4. Art der Container-Bean Interaktion ■ Konventionell ■ Externe Resourcen müssen zuerst über einen Verzeichnis-Dienst (z.B. JNDI-lookup) erfragt werden InitialContext ctx = new InitialContext(); InitialContext ctx = new InitialContext(); DozentenDS = (DataSource) ctx.lookup("jdbc/myprofresource"); DozentenDS = (DataSource) ctx.lookup("jdbc/myprofresource"); ■ als Dependency Injection ■ der Container "impft" die externe Resource in den Code zur Laufzeit ein. Stellen für die Einpflanzung werden annotiert. mappedName -> JNDI lookup mappedName -> JNDI lookup @Resource(mappedName @Resource(mappedName=="jdbc/myprofresource") "jdbc/myprofresource") public DataSource DozentenDS public DataSource DozentenDS; ; ■ Beim Instanzieren des Session Beans, wird die Verbindung vom Container gesetzt School of Engineering © K. Rege, ZHAW Vorteil: Vorteil:Abhängigkeit Abhängigkeitwird wirdexplizit explizit und kann vor dem Ausführen und kann vor dem Ausführen(zur (zur Verteilzeit) Verteilzeit)überprüft überprüftwerden. werden. 42 von 54 Dependency Injection ■ Die Dependency-Annotation wird einfach vor die Instanzvariable @Resource(mappedName @Resource(mappedName=="jdbc/myprofresource") "jdbc/myprofresource") public DataSource DozentenDB; public DataSource DozentenDB; ■ oder vor eine Setter-Methode gesetzt @Resource(mappedName = "jdbc/myprofresource") @Resource(mappedName = "jdbc/myprofresource") public setDataSource (DataSource public setDataSource (DataSourceds) ds) { { DozentenDS DozentenDS==ds; ds; }} ■ beliebige ins JNDI eingetragene Resourcen können so verwendet werden: mappedName=<jndi-name> ■ Namenskonventionen: ■ lokale Resourcen (unter java:comp/env/ im JNDI Verzeichnis) werden ohne Präfix referenziert @Resource(mappedName="queue/A") ■ Bekannte Resourcen müssen nicht benannt werden: ■ @Resource SessionContext oder ■ @Resource TimeService School of Engineering © K. Rege, ZHAW 43 von 54 Referenzierung anderer Session Beans ■ Ebenfalls andere Beans können so referenziert werden (JNDI Eintrag) @EJB @EJB (mappedName="java:global/Professor/ProfessorSessionBean!myBeans.ProfessorSessionBeanRemote") (mappedName="java:global/Professor/ProfessorSessionBean!myBeans.ProfessorSessionBeanRemote") Professor Professor prof; prof; Log LogEintrag Eintragbeim beimStarten Startendes des Servers beachten Servers beachten ■ Es kann auch ein lokales Bean mit einem Interface angegeben werden; es wird nach Klasse gesucht, die dieses Interface implementiert @EJB @EJB (beanInterface="myBeans.ProfessorSessionBeanLocal") (beanInterface="myBeans.ProfessorSessionBeanLocal") Professor Professor prof; prof; ■ Wenn nur @EJB steht, dann wird automatisch nach Bean mit passendem Interface Typ gesucht; für Referencen auf local Interfaces @EJB @EJB ProfessorSessionBeanLocal prof; ProfessorSessionBeanLocal prof; School of Engineering © K. Rege, ZHAW 44 von 54 Entity Beans - Einführung School of Engineering © K. Rege, ZHAW 45 von 54 Referenzierung von Entity Beans ■ SessionBeans greifen oft über Entity Beans auf Daten zu ■ Zugriff auf Entity Bean erfolgt über EntityManager @Stateless @Stateless public public class class DozentService DozentService {{ @PersistenceContext @PersistenceContext (unitName="myprofpu") (unitName="myprofpu") private EntityManager private EntityManager em; em; }} Entity EntityBean Bean @Entity @Entity @Table(name @Table(name == "Dozenten") "Dozenten") public public class class Dozent Dozent implements implements Serializable Serializable {{ ... ... }} public public Collection Collection <Dozent> <Dozent> findByName findByName (String (String namePattern) namePattern) {{ return return em.createQuery( em.createQuery( "FROM "FROM Dozent Dozent rr WHERE WHERE r.name r.name LIKE LIKE :name) :name) .setParameter ("name", namePattern) .setParameter ("name", namePattern) .getResultList(); .getResultList(); Session }} SessionBean Bean Persistence.xml DataSource DataSourceenthält enthältInformation Information <persistence> über DB <persistence> über DB <persistence-unit <persistence-unit name="myprofpu"> name="myprofpu"> <jta-data-source>jdbc/myprofresource</jta-data-source> <jta-data-source>jdbc/myprofresource</jta-data-source> <properties> <properties> <property <property name="hibernate.dialect" name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/> value="org.hibernate.dialect.HSQLDialect"/> <property name="hibernate.hbm2ddl.auto" <property name="hibernate.hbm2ddl.auto" value="create-drop"/> value="create-drop"/> School of Engineering ins ins META-INF META-INFVerzeichnis Verzeichnis des EJB Jars des EJB Jars © K. Rege, ZHAW DefaultDS mitgelieferte DB DefaultDS mitgelieferte DB 46 von 54 Persistency Unit Beschreibung ■ Die Persistency Unit beschreibt den Zugriff auf die DataSource associate associatevalid valid connection connection Business Business Logic Logic pool poolofof opened openedjdbc jdbc connections connections EntityManager em jdbc/myprofresource Entity EntityBean Bean Persistency Unit Data Source Connection Pool myprofpool EJB Container z.B. Glassfish School of Engineering jndi jndiname name © K. Rege, ZHAW 47 von 54 Entity Beans - Einführung ■ Entity Bean: POJO mit @Entity Annotation ■ Default: Klassen-Name = Tabellen-Name, kann mit @Table übersteuert werden import javax.persistence.*; import javax.persistence.*; @Entity @Entity @Table(name = "Dozenten") @Table(name = "Dozenten") public class Dozent implements Serializable { public class Dozent implements Serializable { private string kurzzeichen; private string kurzzeichen; private String name; private String name; private String vorname; private String vorname; ... ... public Dozent () {} public Dozent () {} } School of Engineering public Dozent (String id, String name, String, vorname, ....) { public Dozent (String id, String name, String, vorname, ....) { this.id = id; this.name = name; ... this.id = id; this.name = name; ... } } @Id @Id public String getKurzzeichen () { public String getKurzzeichen () { return kurzzeichen; return kurzzeichen; } } public void setKurzzeichen (String id) { public void setKurzzeichen (String id) { this.id = id; this.id = id; } } @Column(name="FamilienName") @Column(name="FamilienName") public String getName () { public String getName () { return name; return name; } } // Other getter and setter methods ... // Other getter and setter methods ... } © K. Rege, ZHAW 48 von 54 Entity Beans ■ Der Entity Manager führt Buch über die Veränderungen der Beans und übernimmt den Abgleich mit DB @Stateless @Stateless public class DozentService { public class DozentService { @PersistenceContext (unitName="myprofpu") @PersistenceContext (unitName="myprofpu") private EntityManager em; private EntityManager em; .... .... Hinzufügen Hinzufügenvon vonneuen neuenWerten Werten public add (Dozent dozent) { public add (Dozent dozent) { em.persist(dozent); em.persist(dozent); } } public remove (String id) { public remove (String id) { Dozent doz = (Dozent)em.find(Dozent.class,id); Dozent doz = (Dozent)em.find(Dozent.class,id); em.remove(doz); em.remove(doz); } } Finden über Id und Finden über Id und Löschen Löschen public setTelNumber (String id, String telNumber) { public setTelNumber (String id, String telNumber) { Dozent doz = (Dozent)em.find(Dozent.class,id); Dozent doz = (Dozent)em.find(Dozent.class,id); doz.setTelNumber(telNumber); doz.setTelNumber(telNumber); // em.flush(); // em.flush(); } } } } Veränderte Werte werden automatisch mit Veränderte Werte werden automatisch mit Datenbank Datenbankabgeglichen abgeglichen(flush (flushnicht nichtnötig nötig!)!) School of Engineering © K. Rege, ZHAW 49 von 54 Java Persistence Query Language ■ Mittels Persistence Query Language können beliebige Abfragen durchgeführt werden public public Collection Collection <Dozent> <Dozent> findByName findByName (String (String namePattern) namePattern) {{ return return em.createQuery( em.createQuery( "SELECT "SELECT pp FROM FROM Dozent Dozent rr WHERE WHERE r.name r.name LIKE LIKE :name") :name") .setParameter .setParameter ("name", ("name", namePattern) namePattern) .getResultList(); .getResultList(); }} ■ Eigenschaften: ■ ■ ■ ■ ■ ■ SQL angelehnte Syntax: SELECT p FROM Dozent r WHERE r.name LIKE :name Werte von Objekten können "eingeflochten" werden r.name Datenbankunabhängig (keine SQL Dialekte) Platzhalter können in Ausdrücken verwendet werden :name und dann gesetzt werden .setParameter("name", namePattern) Resultat kann eine Collection<> sein .getResultList(); School of Engineering © K. Rege, ZHAW 50 von 54 EJB Client School of Engineering © K. Rege, ZHAW 51 von 54 Local / Remote Client von Session Bean 1. Lookup mittels JNDI Local und Remote Stubs haben unterschiedliche JNDI Einträge 2. Aufrufen 3. Bei stateful SB am Schluss (wenn nicht mehr gebraucht): remove() Klientenseitig: InitialContext InitialContext ctx ctx == new new InitialContext(); InitialContext(); helloBean = (HelloSession) helloBean = (HelloSession) ctx.lookup("java:global/trail.HelloSession"); ctx.lookup("java:global/trail.HelloSession"); helloBean.hello() helloBean.hello() // // stateful stateful only only helloBean.remove() helloBean.remove() jndi.properties java.naming.provider.url=rmi://localhost:1099 java.naming.provider.url=rmi://localhost:1099 java.naming.factory.initial=com.sun.jndi.rmi.registry.RegistryContextFactory java.naming.factory.initial=com.sun.jndi.rmi.registry.RegistryContextFactory wenn nicht "localhost" am einfachsten eine JNDI Property Datei anpassen @EJB (mappedName="java:global/trail.HelloSession") @EJB (mappedName="java:global/trail.HelloSession") HelloSession helloBean; HelloSession helloBean; Serverseitig einfach über Dependency Injection School of Engineering © K. Rege, ZHAW 52 von 54 Zusammenfassung ■ Einfacher Datenbankzugriff über DataSources ■ Referenzen auf beliebige Resourcen über Dependency Injection ■ ■ sämtliche in JNDI eingetragenen Resourcen z.B. andere Session Beans ■ EJB 3.0 Entity Beans ■ ■ ■ basierend auf Hibernate Konzepten Verwendung von Annotationen EntityManager für den Abgleich mit Datenbank ■ EJB 3.0 Klient ■ Lookup über JNDI School of Engineering © K. Rege, ZHAW 53 von 54 Anhang: TimerService ■ Timer ist neuer Service in EJB 3.0 ■ können in SessionBeans zeitverzögerte oder auch wiederholende Aufgaben gelöst werden. public interface TimerTest { ■ Beispiel import import javax.ejb.*; javax.ejb.*; public interface TimerTest { public public void void runTimer(); runTimer(); }} @Stateless @Stateless @Local(TestTimer.class) @Local(TestTimer.class) public public class class TestTimerBean TestTimerBean implements implements TestTimer TestTimer {{ @Resource @Resource public public TimerService TimerService timer; timer; public public void void runTimer() runTimer() {{ timer.createTimer(new timer.createTimer(new Date(System.currentTimeMillis() Date(System.currentTimeMillis() ++ 1000), 1000), 1000, 1000, “test”); “test”); System.out.println(“started System.out.println(“started timerbean”); timerbean”); }} }} @Timeout @Timeout public public void void timeout(Timer timeout(Timer timer) timer) {{ System.out.println(“timeout System.out.println(“timeout ““ ++ timer.getInfo()); timer.getInfo()); }} School of Engineering © K. Rege, ZHAW 54 von 54