Bean - Libra Software GmbH

Werbung
Enterprise Java Beans
Thomas van Husen
1
(c) Libra 2001
Standard Edition J2SE
1.3.1
1.4
Java
Enterprise Edition J2EE
1.3
2
(c) Libra 2001
J2EE 1.3 packages
Package
App Client
Applet
Web
EJB
JDBC 2.0
Extension
EJB 2.0
JA
N
JA
JA
JA
N
JA
JA
Servlets
2.3 2.3
Servlets
N
N
JA
N
JSP 1.2
JSP 1.2
N
N
JA
N
JMS 1.0
JMS
JA
N
JA
JA
JTA 1.0
N
N
JA
JA
JavaMail 1.2
N
N
JA
JA
JAF 1.0
N
N
JA
JA
JA
N
JA
JA
N
N
JA
JA
JA
N
JA
JA
EJB 2.0
JAXPJAXP
1.1 1.1
Connector 1.0
JAASJAAS
1.0 1.0
3
(c) Libra 2001
J2EE Architecture
Applet
Container
Applet
Webcontainer
J2SE
JAF
J2SE
Connectors
JAF
JAXP
JDBC
Java
Mail
Java
Mail
JTA
JAAS
JMS
EJB
JAXP
JDBC
Application
Client
JTA
JAAS
JMS
Application
Client Container
Servlet
Connectors
J2SE
JSP
EJB Container
DB
JDBC
JAXP
JAAS
JMS
J2SE
4
(c) Libra 2001
Firewall
J2EE Environment
EJB Container
Client
Entity
Bean
Session
Bean
Client
Client
Web Container
Entity
Bean
Enterprise
Information
System
Database
ERP
Legacy
Applications
Servlets
Client
Client Tier
JSP, HTML
Middle Tier
EIS Tier
5
(c) Libra 2001
J2EE Application Scenarios
Browser
Web Container
Stand-Alone
Client
EJB Container
Database
6
(c) Libra 2001
EJB
Enterprise Java Beans
Client A
EJB
Container
Kunde
Entity Bean
Kunde
Remote
Object
JDBC
Client B
Kunde
Remote
Object
Kunde
Nr
...
Kunde
Name
Ort
5153
Weka
Bau
Stuttga
rt
...
7
(c) Libra 2001
Presentation
Tier
Browser A
Web
Container
Kunde
Entity Bean
Controller
Session A
Model
Page
Browser B
EJB
Container
Session B
Model
Gui
Client A
Gui
Client B
JDBC
Kunde
Remote
Object
Kunde
Remote
Object
Kunde
Nr
...
Kunde
Name
Ort
5153
Weka
Bau
Stuttga
rt
...
8
(c) Libra 2001
Enterprise Beans
EJB Container
Home
Product
Remote
Client
Home
Order
Callback Methoden:
Jede Bean implementiert einen
Subtyp des EnterpriseBean
Interfaces, das verschiedene
Methoden definiert, die
"Callbacks" genannt werden.
Jede Callback Methode
instruiert die Bean über einen
bestimmten Event in ihrem
Lebenszyklus. Der Container
ruft diese Methoden auf, wenn
die Bean aktiviert wird, wenn
sie gespeichert werden soll,
wenn sie passiviert wird usw.
Die Bean kann in den Callback
Methoden das Ihrige tun, um
dem jeweiligen Event gerecht
zu werden.
Remote
9
(c) Libra 2001
Enterprise Beans
Client
EJB Container
Home
create()
Remote
newOrder()
selectCustomer()
addLine()
Home
findByPrimaryKey()
Home Interface
Order
Controller
Session
Bean
Remote Interface
Implementierung
Product
Enitity
Bean
Remote
getDetail()
setDetail()
10
(c) Libra 2001
EJB Container
EJB Container
Client
Transaktion Management
Persistence Management
Security Management
Jndi ENC, EJBContext
Bean
Callback Methods
Der Container isoliert die Enterprise
Bean gegen den direkten Zugriff eines
Clients. Wenn eine Client Anwendung
eine "remote" Methode einer Bean
aufruft, fängt der Container diesen
Aufruf ab und sichert die Belange von
Persistenz, Transaktionsmanagement
und Security.
Security, Transaktionssteuerung und
Persistenz werden vom Container
automatisch gesteuert, ohne dass sich
der Client darum kümmern muss.
Callback Methoden:
Jede Bean implementiert einen Subtyp
des EnterpriseBean Interfaces, das
verschiedene Methoden definiert, die
"Callbacks" genannt werden. Jede
Callback Methode instruiert die Bean
über einen bestimmten Event in ihrem
Lebenszyklus. Der Container ruft diese
Methoden auf, wenn die Bean aktiviert
wird, wenn sie gespeichert werden
soll, wenn sie passiviert wird usw. Die
Bean kann in den Callback Methoden
das Ihrige tun, um dem jeweiligen
Event gerecht zu werden.
11
(c) Libra 2001
Entity und Session
Beans
EJB Container
• Entity Bean
Customer
Order
Product
zwei grundsätzliche Typen von
Enterprise Beans: Entity Beans
und Session Beans. Entity
Beans stehen für Objekte, die
persistent in einer Datenbank
gehalten werden, und können
typischerweise mit einem
Substantiv bezeichnet werden.
Session Beans repräsentieren
hingegen Prozesse und
Aufgaben. Kandidaten für
Session Beans sind Objekte,
die mit Verben bezeichnet
werden.
.
• Session Bean
Order
Controller
12
(c) Libra 2001
Session –
Entity Beans
Browser A
Web
Container
Auftrag
Remote
Auftrag
Remote
EJB
Container
Kunde
Entity Bean
Auftrag
Session
Bean A
Kunde
Remote
Browser B
Kunde
Remote
Auftrag
Session
Bean B
Gui
Client C
Kunde
Remote
Object
Auftrag
Remote
Object
Gui
Client D
Kunde
Remote
Object
Auftrag
Remote
Object
Auftrag
Session
Bean C
Auftrag
Session
Bean D
13
(c) Libra 2001
Entity Bean Product
Bean
Home Interface
create(5153, Cotes
du Rhone, 7.80)
int id
String name;
double price;
ejbCreate(...)
Product
ID
...
Product
Name
Preis
5153
Cotes du
Rhone
7.80
...
Remote Interface
setPrice(. . .)
getPrice()
setPrice(double d) {
price = d;
}
getPrice() {
return price;
}
14
(c) Libra 2001
Entity Bean ejbCreate
der create() Methode auf dem Home Interface entspricht immer eine
ejbCreate() Methode in der Bean
die ejbCreate() Methode der Bean enthält (bei BMP) den SQL Code
(oder DAO Aufruf), um den Record, der die Bean persistent
repräsentiert, der Datenbank hinzuzufügen
durch das create() auf dem Home Interface erhält der Client ein
Remote Interface, das die einzelne erzeugte Bean repräsentiert
und durch das der Client Methoden der Bean aufrufen kann
das Remote Interface enthält keine Methode „Save“
15
(c) Libra 2001
Product Table
MEASUREUNIT
MEASUREUNITID
CHAR(3)
MEASUREUNITDESC
CHAR(50)
PRODUCT
PRODUCTNUM
NUMERIC(7)
PRODUCTDESC
CHAR(50)MEASUREUNITID = MEASUREUNITID
PRICE
DECIMAL(15,2)
MEASUREUNITID
CHAR(3)
create table PRODUCT
(
PRODUCTNUM
NUMERIC(7)
PRODUCTDESC
CHAR(50)
PRICE
DECIMAL(15,2)
MEASUREUNITID
CHAR(3)
primary key (PRODUCTNUM)
);
not null ,
,
,
,
16
(c) Libra 2001
Product Bean Impl
public class ProductEJBBean implements EntityBean
{
private int id;
private String desc;
private double price;
private String measureUnitId;
public EntityContext context;
public ProductPK ejbCreate (String desc, double price,
String measureUnitId)
throws CreateException, DuplicateKeyException
{
. . .
}
. . .
}
17
(c) Libra 2001
Product ejbCreate() - 1
public ProductPK ejbCreate (String desc, double price, String measureUnitId)
throws CreateException, DuplicateKeyException
{
this.desc = desc;
this.price = price;
this.measureUnitId = measureUnitId;
String sql = "insert into PRODUCT " +
"(" +
"PRODUCTNUM, PRODUCTDESC, PRICE, MEASUREUNITID" +
") " +
"values " +
"(" +
"?, ?, ?, ? " +
")";
Connection dbConnection = null;
PreparedStatement stmt = null;
try {
try {
. . .
(c) Libra 2001
18
. . .
Product ejbCreate() - 2
try {
try {
dbConnection = getDbConnection();
this.id = getMaxProductNumber(dbConnection) + 1;
stmt = dbConnection.prepareStatement(sql);
int i = 1;
stmt.setInt(i++, this.id);
stmt.setString(i++, this.desc);
stmt.setDouble(i++, this.price);
stmt.setString(i++, this.measureUnitId);
if (stmt.executeUpdate() == 1)
return new ProductPK(this.id);
else
throw new CreateException("Error creating Product");
}
finally {
if (stmt != null) stmt.close();
if (dbConnection != null) dbConnection.close();
}
}
catch (java.sql.SQLException e) {
throw new EJBException (e);
}
(c)
} Libra 2001
19
Entity Bean ejbCreate() Aufgaben
in der ejbCreate() Methode müssen:
die Instanzvariablen der Bean gesetzt werden
das Objekt der Datenbank (per JDBC) hinzugefügt werden
die Werte, die zum Erstellen des Objekts notwendig sind, erhält die
ejbCreate() Methode als Parameter
bei Erfolg gibt ejbCreate() den Primary Key zurück (auf dem Home
Interface gibt die entsprechende create() Methode das Remote
Object zurück)
auftretende SQLExceptions (sind Subsystem Exceptions) werden in
EJBExceptions (sind RuntimeExceptions) umgewandelt und
geworfen
20
(c) Libra 2001
public class ProductPK implements java.io.Serializable {
private final int id;
public ProductPK(int id) {
this.id = id;
Product Primary Key
}
public int getId() {
return id;
}
public boolean equals(Object o) {
if (this == o)
return true;
if ( !(o instanceof ProductPK))
// will also return false when o == null
return false;
ProductPK other = (ProductPK) o;
return this.id == other.id;
}
public int hashCode() {
return id;
}
public String toString() {
return "[" + getClass().getName() + ": " + id + "]";
}
}
(c) Libra 2001
21
Entity Bean Primary Key Aufgaben
jede Entity Bean hat einen Primary Key
im genannten Beispiel wäre es nicht notwendig gewesen, eine
eigene Klasse als Primary Key zu verwenden – in der Praxis sind
Primary Keys wegen der Zusammensetzung aus mehreren DB
Feldern (Mandant etc.) jedoch immer eigene Klassen
die PK Klasse muss das Interface java.io.Serializable haben
die equals() Methode von java.lang.Object muss überschrieben
werden und damit auch die hashCode() Methode
die Klasse sollte als Immutable codiert werden (alle Instanzvariable
final)
22
(c) Libra 2001
Primary Key
im Deployment Descriptor
<ejb-jar>
<enterprise-beans>
<entity>
<description>product</description>
<ejb-name>ProductEJB</ejb-name>
<home>schulung.app.product.ProductEJBHome</home>
<remote>schulung.app.product.ProductEJB</remote>
<ejb-class>schulung.app.product.ProductEJBBean</ejb-class>
<persistence-type>Bean</persistence-type>
<prim-key-class>schulung.app.product.ProductPK</prim-key-class>
<reentrant>False</reentrant>
. . .
</entity>
die Primary Key Klasse wird im Deployment Descriptor der Bean
eingetragen
23
(c) Libra 2001
private java.sql.Connection getDbConnection()
Database Connection
{
InitialContext jndiContext;
javax.sql.DataSource ds;
try {
jndiContext = new InitialContext();
ds = (javax.sql.DataSource) jndiContext.lookup("java:comp/env/jdbc/edu");
java.sql.Connection con = ds.getConnection("sa", "");
return con;
}
catch (javax.naming.NamingException e)
{
e.printStackTrace();
throw new javax.ejb.EJBException(e);
}
catch (java.sql.SQLException e) {
e.printStackTrace();
throw new javax.ejb.EJBException(e);
}
}
24
(c) Libra 2001
Database Connection Aufgaben
Die JDBC Connection wird prinzipiell aus einer DataSource genommen.
Die DataSource wird über JNDI Lookup aufgefunden. Dies ist möglich, weil
der EJB Container die DataSource in seinem JNDI Service zuvor
registriert hat – entsprechend seiner (Container spezifischen
Konfigurations) Einstellungen und der (J2EE Standard) Angaben im
Deployment Descriptor
Dadurch dass die Connection nicht direkt mit dem JDBC Driver erstellt,
sondern aus einer vom Container zur Verfügung gestellten Datasource
gezogen wird, kann der Container seine Services wie „Connection
Pooling“ und Transaktionssteuerung „injizieren“.
Bei Connection Pooling müssen im Anwendungscode Connections immer
gleich wieder geschlossen werden.
25
(c) Libra 2001
Database Connection im
Deployment Descriptor
<ejb-jar>
<enterprise-beans>
<entity>
<description>product</description>
<ejb-name>ProductEJB</ejb-name>
<home>schulung.app.product.ProductEJBHome</home>
<remote>schulung.app.product.ProductEJB</remote>
<ejb-class>schulung.app.product.ProductEJBBean</ejb-class>
<persistence-type>Bean</persistence-type>
<prim-key-class>schulung.app.product.ProductPK</prim-key-class>
<reentrant>False</reentrant>
<resource-ref>
<description>Datasource for Product EJB</description>
<res-ref-name>jdbc/edu</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
</entity>
try {
jndiContext = new InitialContext();
ds = (javax.sql.DataSource) jndiContext.lookup("java:comp/env/jdbc/edu");
26
(c) Libra 2001
Home Interface
Bean
int id
String name;
double price;
ejbCreate(...)
Remote Interface
Enterprise Bean
Home, Remote,
Impl
Jede Enterprise Bean besteht aus
drei Klassen: Home Interface,
Remote Interface und Bean
Implementierung
Ein Client kann immer nur das
Home und Remote Interface
verwenden, niemals die Bean
selbst
Der Container verwendet die
Bean Implementierungsklasse
Auf dem Client wird das Home Interface verwendet, um spezifische Instanzen zu
erzeugen
Das Home Interface gibt ein Remote Interface zurück. Das Remote Interface ist
ein Proxy für die Bean im Container. Der Client kann transparent Methoden
vom Remote Interface aufrufen, als wäre es ein „lokales“ Objekt.
27
(c) Libra 2001
public static void main(String [] args) {
Client - Product Insert
try {
Properties p = new Properties();
p.setProperty(Context.INITIAL_CONTEXT_FACTORY,
"org.jnp.interfaces.NamingContextFactory");
p.setProperty(Context.PROVIDER_URL,
"localhost:1099");
p.setProperty("java.naming.factory.url.pkgs",
container spezifische Properties
"org.jboss.naming:org.jnp.interfaces");
für Initial JNDI Context
InitialContext context = new InitialContext(p);
Object ref = context.lookup("ProductEJB");
ProductEJBHome productEJBHome =
Name für Bean aus
Deployment Descriptor
(ProductEJBHome) PortableRemoteObject.narrow(ref,
Home Interface
ProductEJBHome.class);
// insert
ProductEJB productCrt = productEJBHome.create("Cotes du Rhone", 7.8, "fl");
System.out.println("Product: id=" + productCrt.getId()
Remote Interface
+ ", desc=" + productCrt.getDesc()
+ ", price=" + productCrt.getPrice()
+ ", measureUnitPK=" + productCrt.getMeasureUnitPK()
);
28
(c) Libra 2001
public static void main(String [] args) {
try {
Client PortableRemoteObject.narrow
. . .
InitialContext context = new InitialContext(p);
Object ref = context.lookup("ProductEJB");
ProductEJBHome productEJBHome =
(ProductEJBHome) PortableRemoteObject.narrow(ref, ProductEJBHome.class);
. . .
Downcast
und nicht:
Object ref = context.lookup("ProductEJB");
ProductEJBHome productEJBHome = (ProductEJBHome) ref;
. . .
29
(c) Libra 2001
Entity Bean ejbFindxxx
Mit einer create() Methode auf dem Home Interface wird auf dem
Server ein Objekt instantiiert und zugleich neu erzeugt – d.h. mit
der Instantiierung des Objekts ist ein „neu Erstellen“ im persistenten
Storage verbunden
Objekte, die schon in der Datenbank vorhanden sind, werden dagegen
durch Aufruf von find() Methoden auf dem Home Interface im
Container Objekte „instantiiert“, d.h. in der Datenbank aufgefunden
und als Bean Instanzen mit Datenbank Werten geladen
einer findxxx() Methode auf dem Home Interface entspricht immer eine
ejbFindxxx() Methode in der Bean
jede Entity Bean muss mindestens eine findByPrimaryKey() Methode
auf dem Home Interface und eine ejbFindByPrimaryKey() Methode
in der Bean Implementierung haben
30
(c) Libra 2001
Bean
Home Interface
findByPrimaryKey
(5153)
int id
String name;
double price;
ejbFindByPrimaryKey(...)
Entity Bean Product
find()
Product
ID
...
Product
Name
Preis
5153
Cotes du
Rhone
7.80
...
Remote Interface
setPrice(. . .)
getPrice()
setPrice(double d) {
price = d;
}
getPrice() {
return price;
}
31
(c) Libra 2001
public static void main(String [] args) {
Client - Product find
try {
Properties p = new Properties();
...
InitialContext context = new InitialContext(p);
Object ref = context.lookup("ProductEJB");
ProductEJBHome productEJBHome =
(ProductEJBHome) PortableRemoteObject.narrow(ref,
Home Interface
ProductEJBHome.class);
// find by primary key
ProductPK pk = new ProductPK(5);
Primary Key
ProductEJB productEJB;
try
Remote Interface
{
productEJB = productEJBHome.findByPrimaryKey(pk);
} catch (javax.ejb.FinderException e) {
System.err.println("No object found for " + pk);
return;
}
System.out.println("Product: id=" + productEJB.getId()
+ ", desc=" + productEJB.getDesc()
+ ", price=" + productEJB.getPrice()
+ ", measureUnitPK=" + productEJB.getMeasureUnitPK()
(c) Libra 2001
);
32
Product Home Interface
public interface ProductEJBHome extends EJBHome
{
public ProductEJB create(String desc, double price, String measureUnitId)
throws RemoteException, CreateException, DuplicateKeyException;
public ProductEJB findByPrimaryKey(ProductPK productPK)
throws RemoteException, FinderException;
}
33
(c) Libra 2001
Bean – ejbFindByPrimaryKey()
public ProductPK ejbFindByPrimaryKey(ProductPK pk) throws FinderException
{
Connection dbConnection = null;
Statement stmt = null;
ResultSet rs = null;
String sql = "select PRODUCTNUM from PRODUCT " +
"where PRODUCTNUM = " + pk.getId() ;
try {
try {
dbConnection = getDbConnection();
stmt = dbConnection.createStatement();
rs = stmt.executeQuery(sql);
if (rs.next()) {
return pk;
Primary Key
}
else {
throw new javax.ejb.ObjectNotFoundException(
"No product found in database for " + pk);
}
}
finally {
if (dbConnection != null)
dbConnection.close();
}
}
catch (java.sql.SQLException e) {
throw new EJBException ("SQL Exception in find by primary key" + e);
}
}
34
(c) Libra 2001
ejbFindByPrimaryKey() Aufgaben
Die Aufgabe der ejbFindByPrimaryKey() Methode ist nur, den
Primary Key, den die Methode schon als Parameter bekommen
hat, zurückzugeben, falls ein entprechendes Objekt in der
Datenbank vorhanden ist, d.h. im Grunde nur festzustellen, ob für
den Primary Key ein Satz in der Datenbank vorhanden ist.
Wird kein Satz in der Datenbank gefunden wird, muss die Methode
eine FinderException werfen.
Aufgabe ist nicht(!!!), die Werte aus der Datenbank zu laden und
damit die Instanzvariablen zu setzen. Das ist Aufgabe der
ejbLoad() Methode.
35
(c) Libra 2001
Bean – ejbLoad()
public void ejbLoad() {
ProductPK pk = (ProductPK)context.getPrimaryKey();
Connection dbConnection = null;
String sql = "select * from PRODUCT " +
"where PRODUCTNUM = " + pk.getId() ;
Statement stmt = null;
ResultSet rs = null;
try {
try {
dbConnection = getDbConnection();
stmt = dbConnection.createStatement();
rs = stmt.executeQuery(sql);
if (rs.next()) {
this.id = rs.getInt("PRODUCTNUM");
this.desc = rs.getString("PRODUCTDESC");
this.price = rs.getDouble("PRICE");
this.measureUnitId = rs.getString("MEASUREUNITID");
}
}
finally {
if (rs != null)
rs.close();
if (stmt != null)
stmt.close();
if (dbConnection == null)
dbConnection.close();
}
} catch (java.sql.SQLException e) {
throw new EJBException (e);
}
}
(c) Libra 2001
36
ejbLoad() Aufgaben
ejbLoad() kann nicht vom Client, sondern allein vom Container
aufgerufen werden
wann ejbLoad() aufgerufen wird, ist durch die Sequenzdiagramme
der EJB Spezifikation geregelt (bei Find Sequenzen wird
ejbLoad() nach ejbFindxxx aufgerufen und bevor der Client
Methoden des durch die Find Methode erhaltenen Remote
Interface aufruft)
Aufgabe ist, mit dem Primary Key aus dem Entity Context die Werte
für das Objekt aus der Datenbank zu laden und die
Instanzvariablen zu setzen.
37
(c) Libra 2001
Enity Context
public void setEntityContext(EntityContext context)
{
this.context = context;
}
setEntityContext() ist eine Methode, die von der Bean implementiert
werden muss. Sie wird vor ejbLoad() aufgerufen (genauer gesagt vor
ejbActivate() oder vor ejbPostCreate())
Der Enity Context hat eine Methode getPrimaryKey().
Die getPrimaryKey() Methode gibt den Primary Key des EJB
Objekts zurück, das mit der Bean Instanz assoziiert ist.
38
(c) Libra 2001
Product Remote Interface
public interface ProductEJB extends EJBObject
{
public int getId() throws RemoteException;
public String getDesc() throws RemoteException;
public void setDesc(String desc) throws RemoteException;
public double getPrice() throws RemoteException;
public void setPrice(double price) throws RemoteException;
public MeasureUnitPK getMeasureUnitPK() throws RemoteException;
public void setMeasureUnitPK(MeasureUnitPK measureUnitPK) throws RemoteException;
}
Das Remote Interface enthält keine Methode „save“. Wenn das
Server Objekt durch eine setXXX() Methode verändert wurde,
kann der Client davon ausgehen, dass das Objekt persistent
geändert wurde. Er braucht sich um die Persistenz der Änderung
nicht zu kümmern.
39
(c) Libra 2001
public void ejbStore() {
ProductPK pk = (ProductPK)context.getPrimaryKey();
Connection dbConnection = null;
String sql = "update PRODUCT set " +
"PRODUCTNUM = ?" +
", PRODUCTDESC = ?" +
", PRICE = ?" +
", MEASUREUNITID = ?" +
" where PRODUCTNUM = " + pk.getId();
PreparedStatement stmt = null;
try {
try {
dbConnection = getDbConnection();
stmt = dbConnection.prepareStatement(sql);
int i = 1;
stmt.setInt(i++, this.id);
stmt.setString(i++, this.desc);
stmt.setDouble(i++, this.price);
stmt.setString(i++, this.measureUnitId);
if (stmt.executeUpdate() == 1)
return;
else
throw new SQLException("Error on update");
}
finally {
if (stmt != null)
stmt.close();
if (dbConnection != null)
dbConnection.close();
}
} catch (java.sql.SQLException e) {
throw new EJBException (e);
}
}
Bean – ejbStore()
40
(c) Libra 2001
Implementierung der Business Methods
– Trivia
public int getId()
{
return this.id;
}
public String getDesc()
{
return this.desc;
}
public void setDesc(String desc)
{
this.desc = desc;
}
public double getPrice()
{
return this.price;
}
public void setPrice(double price)
{
this.price = price;
}
public MeasureUnitPK getMeasureUnitPK()
{
return new MeasureUnitPK(this.measureUnitId);
}
public void setMeasureUnitPK(MeasureUnitPK measureUnitPK)
{
this.measureUnitId = measureUnitPK.measureUnitId;
}
(c) Libra 2001
41
public class ProductEJBBean implements EntityBean {
Entity Bean - Skelett
public ProductPK ejbCreate (...)
throws CreateException, DuplicateKeyException {
// returns Primary Key Object
// für jede create() Methode aus Home eine von der Signatur her passende
// für einen Satz in die Datenbank, der die Bean repräsentiert
// setzt die Instanz Variablen
}
public void ejbPostCreate(...) {
// EJB object identity ist jetzt verfügbar (EntityContext.getEJBObject())
}
public void ejbRemove() throws RemoveException {
// entfernt Satz aus Datenbank, der die Bean repräsentiert
}
public void ejbLoad() {
// synchronisiert Instanzvariable mit Satz aus Datenbank
}
public void ejbStore() {
// schreibt Zustand der Instanzvariablen in Datenbank
}
public ProductPK ejbFindByPrimaryKey(ProductPK pk) throws FinderException {
// locates one entity object in the database
}
public void setEntityContext(EntityContext context) {
// container übergibt reference to EntityContext
// bean allocates resources held for the bean's lifetime
}
public void unsetEntityContext() {
// Freigabe von Ressource, die allokiert wurden in setEntityContext
}
public void ejbActivate() {
// container associates EJB object identity with an instance
// bean allocates additional resources needed in ready state
}
public void ejbPassivate() {
// container dissociates identity from instance
// bean frees resources allocated in ejbActivate
}
}
(c) Libra 2001
42
Entity Bean –
Zustandsablauf 1
Client:
ProductEJB productCrt = productEJBHome.create("Cotes du Bourgogne", 7.8, "fl");
log EJB Server:
[Default] schulung.app.product.ProductEJBBean:
[Default] schulung.app.product.ProductEJBBean:
[Default] schulung.app.product.ProductEJBBean:
104]
[Default] schulung.app.product.ProductEJBBean:
setEntityContext() null
ejbCreate() null
ejbPostCreate() [schulung.app.product.ProductPK:
ejbStore() [schulung.app.product.ProductPK: 104]
Client:
System.out.println("Product: id=" + productCrt.getId()
+ ", desc=" + productCrt.getDesc()
+ ", price=" + productCrt.getPrice()
+ ", measureUnitPK=" + productCrt.getMeasureUnitPK()
);
log EJB Server:
[Default] schulung.app.product.ProductEJBBean:
[Default] schulung.app.product.ProductEJBBean:
[Default] schulung.app.product.ProductEJBBean:
[Default] schulung.app.product.ProductEJBBean:
ejbStore()
ejbStore()
ejbStore()
ejbStore()
[schulung.app.product.ProductPK:
[schulung.app.product.ProductPK:
[schulung.app.product.ProductPK:
[schulung.app.product.ProductPK:
104]
104]
104]
104]
Client:
productCrt.remove();
log EJB Server:
[Default] schulung.app.product.ProductEJBBean: ejbRemove() [schulung.app.product.ProductPK: 105]
43
(c) Libra 2001
Client:
Entity Bean –
Zustandsablauf 2
ProductPK pk = new ProductPK(5);
productEJB = productEJBHome.findByPrimaryKey(pk);
log EJB Server:
[Default] schulung.app.product.ProductEJBBean: setEntityContext() null
[Default] schulung.app.product.ProductEJBBean: ejbFindByPrimaryKey()
[Default] schulung.app.product.ProductEJBBean: found [schulung.app.product.ProductPK: 5]
Client:
System.out.println("Product: id=" + productEJB.getId()
+ ", desc=" + productEJB.getDesc()
+ ", price=" + productEJB.getPrice()
+ ", measureUnitPK=" + productEJB.getMeasureUnitPK()
);
log EJB Server:
[Default] schulung.app.product.ProductEJBBean: setEntityContext() null
[Default] schulung.app.product.ProductEJBBean: ejbActivate() [schulung.app.product.ProductPK: 5]
[Default] schulung.app.product.ProductEJBBean: ejbLoad() [schulung.app.product.ProductPK: 5]
[Default] schulung.app.product.ProductEJBBean: ejbStore() [schulung.app.product.ProductPK: 5]
[Default] schulung.app.product.ProductEJBBean: ejbStore() [schulung.app.product.ProductPK: 5]
[Default] schulung.app.product.ProductEJBBean: ejbStore() [schulung.app.product.ProductPK: 5]
[Default] schulung.app.product.ProductEJBBean: ejbStore() [schulung.app.product.ProductPK: 5]
Client:
String desc = productEJB.getDesc().trim();
log EJB Server:
[Default] schulung.app.product.ProductEJBBean: ejbStore() [schulung.app.product.ProductPK: 5]
Client:
desc = desc + "-1";
productEJB.setDesc(desc);
log EJB Server:
[Default] schulung.app.product.ProductEJBBean: ejbStore() [schulung.app.product.ProductPK: 5]
44
(c) Libra 2001
Deployment Descriptor
ejb-jar.xml 1
<?xml version="1.0" encoding="UTF-8" ?>
- <ejb-jar>
<description>Libra edu Enterprise Beans</description>
<display-name>Libra edu Enterprise Beans</display-name>
- <enterprise-beans>
- <entity>
<description>product</description>
<ejb-name>ProductEJB</ejb-name>
<home>schulung.app.product.ProductEJBHome</home>
<remote>schulung.app.product.ProductEJB</remote>
<ejb-class>schulung.app.product.ProductEJBBean</ejbclass>
<persistence-type>Bean</persistence-type>
<prim-key-class>schulung.app.product.ProductPK</prim-keyclass>
<reentrant>False</reentrant>
- <resource-ref>
<description>Datasource for Product EJB</description>
<res-ref-name>jdbc/edu</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
</entity>
45
(c) Libra 2001
<?xml version="1.0" encoding="UTF-8" ?>
- <ejb-jar>
- <enterprise-beans>
...
</enterprise-beans>
- <assembly-descriptor>
- <container-transaction>
- <method>
<ejb-name>ProductEJB</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
- <container-transaction>
- <method>
<ejb-name>ProductEJB</ejb-name>
<method-name>findByPrimaryKey</method-name>
</method>
<trans-attribute>NotSupported</trans-attribute>
</container-transaction>
- <container-transaction>
- <method>
<ejb-name>ProductEJB</ejb-name>
<method-name>getDetail</method-name>
</method>
<trans-attribute>NotSupported</trans-attribute>
</container-transaction>
</assembly-descriptor>
</ejb-jar>
Deployment Descriptor
ejb-jar.xml 2
46
(c) Libra 2001
Jar File
EJB
Server
Deployment
META-INF/ejb-jar.xml
edu.jar
ProductEJB.class
ProductEJBHome.class
ProductEJBBean.class
ProductPK.class
jar cvf edu.jar META-INF/ejb-jar.xml META-INF/jboss.xml
schulung/app/product/*.class
copy edu.jar "\jboss-2.4.3\deploy"
47
(c) Libra 2001
J2EE Patterns
DAO (Data Access Object)
Auslagerung des SQL Codes in
eine eigene Klasse
Value Objects
Bündelung von Attributen in einer
Klasse
-> „Core J2EE Patterns – Best
Practices and Design Strategies“
by Alur / Cupri / Malks
ISBN 0-13-064884-1
48
(c) Libra 2001
EJB 2.0 – Entity Beans
CMP Modell hat sich erheblich verbessert
Container managed Relations zwischen Entity
Beans
Neben Remote Interfaces auch Local Interfaces
Query Language für Entity Beans
49
(c) Libra 2001
Session Beans
Session Beans werden dazu verwendet, um serverseitige Aufgaben im
Auftrag des Clients auszuführen, Ressourcen (wie Kurse und Tabellen)
zugänglich zu machen und das Zusammenspiel von Entity Beans zu
organisieren. Session Beans haben keine Persistenz und repräsentieren
keine Daten aus einer Datenbank (sehr wohl kann es aber zu ihren
Aufgaben gehören, Daten aus der Datenbank zu lesen und zu schreiben)
und enkapsulieren typischerweise die Business Logik einer Anwendung.
Typische Beispiele für Session Beans sind:
• Warenkorb, der sich während einer Session aufbaut
• Währungsumrechner, Buchungsprozesse
50
(c) Libra 2001
Es gibt zwei grundsätzliche Arten von Session Beans: Stateless und Stateful.
Stateless Session Beans behalten keine Zustandsinformation von einem Aufruf zum
nächsten. Man kann sie wie Funktionsaufrufe verstehen, die allein mit den
übergebenen Parametern arbeiten:
Eingabe von einer Währung – Ausgabe in Euro
Stateful – Stateless
Session Beans
Stateful Session Beans behalten einen Zustand von Aufruf zu Aufruf. Wenn einem
Warenkorb ein Artikel hinzugefügt wird, ist dieser auch beim nächsten Hinzufügen
noch erhalten. Eine "stateful" Session Bean spiegelt den Zustand einer client-seitigen
"Session" wider.
Der Container kann (aus Container Management Gründen) eine Session Bean
zeitweise aus dem Memory nehmen und in einen Secondary Storage (Disk)
schreiben. Dieser Transfer wird Instanz "Passivation" genannt. Der umgekehrte
Transfer ist "Activation". Der Container sollte eine Session Bean nur passivieren,
wenn sie nicht Teil einer Transaktion ist. Damit der Container den "State" einer
Session Bean besser managen kann, wird ihm im Deployment Descriptor der Bean
mitgeteilt, ob es sich um eine STATELESS oder STATEFUL Session Bean handelt.
Bei STATELESS Session Beans bleibt kein Zustand zwischen Methoden Aufrufen
vorhanden und kann eine Bean Instanz von jedem Client verwendet werden. Bei
STATEFUL Session Beans muss der Zustand der Bean zwischen Methoden und über
Transaktionsgrenzen hinweg erhalten bleiben.
51
(c) Libra 2001
OrderController
Session Bean
OrderController
SessionBean
List positions;
Home Interface
create();
Remote Interface
addProduct(
ProductPK pk);
getTotalPrice();
ejbCreate() {...}
addProduct(ProductPK pk)
{
productEJB =
productHome.
findByPrimaryKey(pk);
productDetail =
productEJB.getDetail();
positions.add(productDetail);
}
Product EntityBean
int id
String name;
double price;
Home Interface
findByPrimaryKey
(5153)
ejbFindByPrimaryKey(...)
Remote Interface
getDetail()
P ro du ct
ID
. . .
P ro du ct
N am e
Preis
5 15 3
C otes d u
R h one
7.80
. . .
(c) Libra 2001
getDetail() {
return new
ProductDetail(id,
name, price..);
}
52
SessionBean - Skelett
public class OrderControllerEJBBean implements SessionBean {
public void ejbCreate () throws CreateException {
}
public void ejbRemove() throws RemoveException {
}
public void setEntityContext(EntityContext context) {
// container übergibt reference to EntityContext
// bean allocates resources held for the bean's lifetime
}
public void unsetEntityContext() {
// Freigabe von Ressource, die allokiert wurden in setEntityContext
}
public void ejbActivate() {
// container associates EJB object identity with an instance
// bean allocates additional resources needed in ready state
}
public void ejbPassivate() {
// container dissociates identity from instance
// bean frees resources allocated in ejbActivate
}
Kein
public
public
public
public
void ejbPostCreate(...) {}
void ejbLoad() {}
void ejbStore() {}
... ejbFindByPrimaryKey(...) throws FinderException {}
}
53
(c) Libra 2001
public class OrderControllerEJBBean implements SessionBean {
private SessionContext context;
private javax.naming.InitialContext jndiContext;
private List positions;
public void ejbCreate() throws RemoteException, CreateException {
positions = new ArrayList();
}
OrderController
SessionBean
public void addProduct(ProductPK productPK) {
// check for duplicates
Iterator it = positions.iterator();
while (it.hasNext())
{
OrderPos pos = (OrderPos) it.next();
Product product = pos.getProduct();
if (product.getPK().equals(productPK))
{
pos.setQuantity( pos.getQuantity() + 1);
return;
}
}
// find product and add it to positions
try
{
ProductEJBHome productHome = getProductEJBHome();
ProductEJB productEJB = productHome.findByPrimaryKey(productPK);
OrderPos pos = new OrderPos();
pos.setProduct(productEJB.getDetail());
pos.setQuantity(1);
positions.add(pos);
}
catch (javax.ejb.FinderException e)
{
throw new EJBException(e);
}
catch (java.rmi.RemoteException e)
{
throw new EJBException(e);
}
(c) Libra} 2001
54
Pro
Gründe für und gegen den Einsatz
von EJB
Anwendungssysteme lassen sich schneller und zuverlässiger aufbauen. EJB Komponenten
profitieren von einer deklarativen Middleware, mit der sich Instance Pooling, Transaktionen,
Security, Persistenz, Relationships (EJB 2.0) und Caching einstellen lassen. Auf der Basis von
Standard Java allein, müsste man diese Mechanismen und Middleware selbst entwicklen. EJB ist
ein verlässlicher und getesteter Standard.
EJB ist ein etablierter Standard. Es gibt Entwickler und Projektsoftwarehäuser auf dem Markt, die
die Technologie beherrschen. Bei eigenentwickelter Middleware können neue Entwickler nur mit
langen Vorlaufzeiten eingestellt werden.
Jeder der auf Basis von EJB Technologie Anwendungen entwickelt, profitiert von der weltweiten
Erfahrung im Umgang mit der Technolgie. Aus dieser Erfahrung haben sich bereits dokumentierte
Patters ergeben.
EJB sind eine zentrale Anwendungsschnittstelle für technologisch unterschiedliche Clients.
Es gibt eine Vielzahl von Entwicklungswerkzeugen für EJB Technolgie. Aus UML Diagarammen
können EJB automatisch generiert werden.
Web und Applikationsserver können netzwerktechnisch getrennt werden.
Contra
Wenn die Anwendung einfach ist, kann EJB Technologie Overkill sein.
(c) Libra 2001
55
EJB Server
IBM Websphere
BEA Weblogic
JBoss (www.jboss.org)
Open Source + lizenzfrei
56
(c) Libra 2001
JBoss
Entstanden 1999 - JBoss ist das Produkt einer OpenSource
Developer Community die das erklärte Ziel hatte, den besten J2EEcompliant Applikationsserver auf dem Markt zu entwickeln
1000 Developer weltweit
Jboss ist wahrscheinlich der verbreiteste EJB Server der Welt heute
4000 Downloads des EJB Servers pro Tag (mehr als manche
kommerzielle Hersteller insgesamt haben)
Die Distrubition erfolgt unter LGPL License, d.h. Jboss kostet KEINE
Lizenzgebühren.
JBoss hat sich als eine vitale Alternative zu überpreisten EJB Servern im
kommerziellen Umfeld entwickelt.
57
(c) Libra 2001
Unternehmen und Institutionen, die JBoss einsetzen
AbaXX, Germany, ABC Virtual Communications, Accenture, Acxiom, AdvancePCS Inc.,
Agilent, Agility Mgmt. Partners, Ardec, Argotec Germany, BaaN, BAE Systems, Bank of
America, Baring Asset Management, BellSouth, Benefit AB Sweden, Boeing, Bouygues
Telecom, British Petroleum UK, Cardinal Health, Cepsa Spain , CGDA, Compaq, Computer
Associates, Coremetrics, Coritel, CPW UK, CSC, CSIRO, Data Experts Gmbh Germany,
Datenzentrale, DCI Ltd. UK, Decell Israel, Deutschebank AG, Directory Technology Pty Ltd,
Dow Jones & Co., DP AG, Dresdner Kleinwort Wasserstein UK, Earthlink Inc, Epixtech
Corp., FGM Corp., Finland Post Corporation, Frontwire UK, Fujixerox Japan, GE Capital
TIP, General dynamics/Techsight, Highmark, Inc., Getronics Govt. Solutions, Highbridge,
Home Depot, Honeywell, IcomXpress, Ifm electronic gmbh, IGT, IHS Accumap,
Informatique CDC, DTA, Informativi S.p.A., Integris, KB, Ivertexo Internet Solutions, JP
Morgan, KPMG Consulting, LandSafe, Logica, Lexign, Maxim Group Business Solutions,
MBT, McLeodUSA, Mercury Interactive, Michigan State University, MIT, Mitre Corp.,
Motorola, NASA, National Computer System Peregrine Systems, Norsk
Eiedomsinformasjon Norway, Novell, Nuasis, Orange Communications Switzerland, Politet
Datajeneste Norway, Pracom, Private, Proximo, Rational Software, Raytheon, Riva
Technologies Inc., Rivcoll Union, RoadRunner Broadband, Hoffmann-La Roche,
Schlumberger, Sempra Energy Trading, Sextantech Technology Consulting, Shiftat Bvba
Belgium, Siemens AG, Silverline, Sisa Studio Switzerland, Sistemi, SolidSource Corp.,
Soltima Czech Republic, Spirent Systems, Sprint PCS, Statoil, Stilo Technology UK,
Summit Information Systems, Telenor Network Services, Tenovis Germany, TietoEnator
Consulting, TietoEnator Corp., Triversity Inc., University of Bremen Germany, University of
Florida, UPB, USCO Logistics, Verizon, Viant Intl. Corp.UK, Videotron, Volkswagen
Germany, Walkers Snack Foods UK, Winterthur Insurance, WM-data, World Travel
Partners, WorldCom, XML Asia Ltd. Hong Kong, Zantaz Corp.,
58
(c) Libra 2001
Trademarks
Sun, Sun Microsystems, the Sun logo, Java, Jini, J2EE, JavaServer Pages, Enterprise JavaBeans, Java Compatible, JDK, JDBC, JavaBeans, JavaMail, Write Once, Run Anywhere, and
Java Naming and Directory Interface are trademarks or registered trademarks of Sun
Microsystems, Inc. in the U.S. and other countries.
IBM and WebSphere are trademarks of International Business Machines Corporation in the
United States, other countries, or both. iSeries and the e-business logo are trademarks of
International Business Machines Corporation in the United States or other countries or both.
OS/400 and AIX are registered trademarks of International Business Machines Corporation in
the United States or other countries or both.
Urls
http://java.sun.com/products/ejb/
http://java.sun.com/j2ee/
http://www.jboss.org
59
(c) Libra 2001
Herunterladen