Enterprise Java Beans

Werbung
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
Herunterladen