Realisierung verteilter Anwendungen: Teil 6
Ralf Möller, FH-Wedel
Beim vorigen Mal:
Einführung in Multitier-Architekturen
Dynamische Seitengenerierung (JSP und Servlets)
Inhalt heute
Komponentenarchitekturen (am Beispiel von Enterprise
Java Beans)
Lernziel:
Grundverständnis des Designs der EJB-Architektur
zur weiteren Vertiefung im Beruf
Enterprise Java Beans (EJB)
Teile von einigen der nachfolgenden Folien wurden übernommen aus:
VL Anwendungssysteme
Gerald Weber
Ziele der EJB-Architektur
Standard-Applikationsserver-Architektur für Java
Abstraktion von Low-Level Aufgaben bei
Transaktionen, Multithreading, Connection Pooling
Komponenten-Orientierung: Applikationen können
aus Teilen verschiedener Hersteller aufgebaut
werden
Definierte Rollenverteilung für die Systemerstellung
Definition der Aufgaben der Rollen durch Contracts
EJB-Architektur
EJB-Server
RMI
Clients
RDBMS
B
JDBC
Container
B
CORBA
LegacyApplication
Beispiel: E-Commerce-System
Bean-Provider Cat.com
bietet Produktkatalog
MyCat an
App. Assembler WebVend
erstellt Applikation BuyMe
Marktplatz GoodStuff ist
Deployer, EJBServer und
Container kommen von
MegaBeans
MyCat
.jar
JSP
DD
.jar
Client
Client
Client
HTTP
EJB
Serv.+
Cont.
Cart
MyCat
Order
M.
C. O.
DD = Deployment Descriptor
JMS (Java Message Service)
JNDI (Java Naming and Directory Interface)
EJB Rollen
Bean Provider (Experte im Anwendungsbereich)
Application Assembler: (Experte im
Anwendungsbereich)
Deployer (Experte für spezielle Systemumgebung)
EJB Server Experte (TP-Experte, z.B. DB-Anbieter)
EJB Container Provider (Experte für Systemprogrammierung, Load Balancing)
System-Administrator
Welche Analyse-Klassen stellen EJBs dar?
EJBs repräsentieren grobkörnige Objekte:
Sitzungsobjekte: Session Beans
Stateless: single-use service, haben keinen Zustand
Stateful: speichern Zustand, aber nur transient
Persistente Objekte: Entity Beans
Beispiel: Eirichtung einer Bean für eine Rechnung,
aber nicht für einen Rechnungsposten
Komponentenbegriff
Beans implementieren Business-Logik.
Beans sind verteilte Objekte.
Bean ist über eine Anzahl von Parametern
anpaßbar.
Beans enthalten deklarative Informationen über
den Einsatzkontext (Deployment-Descriptor).
Client-Zugriff erfolgt durch festgelegte
Interfaces
Java-Sprachebene: Elemente einer EJBean
Home Interface: Feste Arten
von Klassen-Methoden. U.a.
Life-cycle-Management
Methoden (Erzeugung...)
Remote Interface:
Instanzmethoden, BusinessMethoden
Beanklasse: Implementiert
beide Interfaces
Deployment Descriptor
Verwendete andere Klassen
(Helper Classes)
Home
Remote
Bean
Helper Helper
Beispiel: Die EntityBean MyCat
Home-Interface
MyCatHome:
create(String Name)
findByPrimaryKey(String)
findLike(String keyword)
Remote-Interface MyCat:
getPrice() etc.
setPrice() etc.
buy(int pieces)
Bean-Klasse MyCatBean:
Implementiert Methoden
aus MyCatHome und
MyCat.
Deployment Descriptor:
type: entity
role admin: Alle Methoden
role customer: nicht
setPrice().
Locating a (session) Bean’s home interface
JNDI (Java Naming and Directory Interface)
Context initialContext = new InitialContext();
BankBeanHome myBeanHome = (BankBeanHome)
initialContext.lookup("Systems/gsj21/Repository/Applicat
ions/BankExample1/Homes/BankSessionBean");
EJB Contracts: Client-View-Contract
Client kann durch RMI auf Bean zugreifen.
Pro Deployment einer Bean ist ein HomeInterface-Objekt in JNDI eingetragen und für
den Client nutzbar.
Bean Instanzen implementieren das RemoteInterface Der Client erhält sie durch das HomeInterface.
Component Contract
Beans werden in Container eingebettet
Bean implementiert Business-M., Life-cycle-M. u.a. Callbacks.
Container ruft diese sinngemäß auf
Container behandelt z.B. Transaktionen,
Security und Exceptions
Container bietet JNDI-Environment, EJBContext
Bean Provider vermeidet Programmierung, die das Container
Runtime Management stört
Optional: Container behandelt Persistenz
Deployment-Descriptor enthält entsp. Daten
Motivation der J2EE-Umgebungseinbettung
Beispiel: Verbindungen (connections)
Verbindungsobjekte repräsentieren eine
Zugriffsmöglichkeit auf eine Ressource (z.B. JDBC)
Nachteile des häufigen Verbindungsaufbaus
Auf- und Abbau einer Verbindung ist aufwendig
Bei häufigem Zugriff entsteht großer Overhead
Häufig gilt: mehrere Komponenten greifen auf die
gleiche Ressource zu
Wünschenswert: Pool von Verbindungen für
mehrere Komponenten jeweils für eine Ressource
Beispiel: JDBC-Verbindungen
Connection con;
ResultSet results;
try {
con = DriverManager.getConnection(
"jdbc:odbc://vodka.fh-wedel.de/Db",
username,
password);
results = con.createStatement().executeQuery("...")
} catch (Exception e) {
System.out.println(e); }
con.close();
Kontextabhängigkeit des DB-Treibers
try {
Class.forName("org.gjt.mm.mysql.Driver")
} catch (ClassNotFoundException cnfe) {
System.out.println("Cannot load driver");
}
Aber: der Treiber hängt von der Umgebung ab!
Bei Einhaltung des Komponentengedankens muß der
Treibername zur Laufzeit erfragt werden!
Hierzu dient ein Kontextobjekt (sog. EJB-Kontext)
Verbindungen im EJB-Kontext (ohne Pool)
import java.sql.*; import javax.sql.*;
public class AccountBean implements EntityBean {
public Collection ejbFindByLastName(String lName) {
try {
String dbdriver = new
InitialContext().lookup("java:comp/env/DBDRIVER").toString();
Class.forName(dbdriver).newInstance();
Connection conn =
DriverManager.getConnection("java:comp/env/DBURL",
"userID", "password");
<body>
conn.close();
}}
Reduzierung des Aufwandes
Im Applikationsserver laufen viele EJBs
Jede EJB führt kurze Interaktion mit DB durch ...
... und meldet die Verbindung gleich wieder ab
Idee: Teilung von Verbindungen zwischen mehreren
EJBs und mehreren Aufrufen von EJB-Methoden
Notwendig: Verwaltung eines kritischen Abschnitt
(bedingt durch Multithreading) und ggf.
Transaktionsmanagement
Soll das jeder EJB-Programmierer selbst machen?
Connection Pooling durch Container
Idee: Connection Pooling wird durch Umgebung
(container) für alls EJBs übernommen
Verbindungen im EJB-Context (mit Pool) (1)
import java.sql.*;
import javax.sql.*;
// import here vendor-specific JDBC drivers
public ProductPK ejbCreate() {
try {
// initialize JNDI lookup parameters
Context ctx = new InitialContext(...);
...
// Following params could come from a JNDI look-up
ConnectionPoolDataSource cpds =
(ConnectionPoolDataSource)ctx.lookup(cpsource);
Verbindungen im EJB-Context (mit Pool) (2)
...
cpds.setDatabaseName("PTDB");
cpds.setUserIF("XYZ");
PooledConnection pc = cpds.getPooledConnection();
Connection conn = pc.getConnection();
// do business logic
conn.close();
}
...
}
Zusammenfassung der Motivation für J2EE
Es gibt Aspekte der
Anwendungsprogrammierung, die
für alle Softwarekomponenten
relevant sind
Es ist sinnvoll, sie nur einmal zu
programmieren und von für
verschiedene Komponenten zu
nutzen
Es gibt bestimmte Abhängigkeiten
der Komponenten vom konkreten
Einsatzkontext
Eine Beispielanwendung
Benutzer macht Eingaben in HTML-Formular
Das ausgefüllte Formular wird durch ein Servlet
verarbeitet
Das Servlet lokalisiert die Verarbeitungskomponente
(Session Bean) über JNDI (Java Naming and Directory
Service)
Session Bean macht Berechnung
Servlet kommuniziert Ergebnis zum Benutzer
J2EE Software und Setup
Java 2 SDK Enterprise Edition (J2EE),
Version 1.2.1
(http://java.sun.com/j2ee/download.html)
Java 2 SDK, Standard Edition (J2SE)
Version 1.2 oder neuer
(http://java.sun.com/jdk/index.html).
Annahme: installiert in $HOME/J2EE/j2sdkee1.2.1
bzw. $HOME/J2EE/jdk1.2.2
PATH: $HOME/J2EE/jdk1.2.2/bin und
$HOME/J2EE/j2sdkee1.2.1/bin
CLASSPATH: $HOME/J2EE/j2sdkee1.2.1/lib/j2ee.jar
J2EE Application Components
Application client components
Enterprise JavaBeans components
Servlets and JavaServer Pages components (auch
Web components genannts)
Applets
J2EE Application Components
Servlet mit HTML-Dateien werden zu einem Web
Archive (WAR) zusammengefaßt
Session Bean und Klassen zu einem JAR Archiv
zusammengefaßt
Enterprise Archive (EAR) Datei zur Verifikation,
zum Testen und zum Deployment in die
Produktionsumgebung enthält alle Teil-Archive
Erzeugen der HTML-Seite bonus.html
Der HTML-Code in .../J2EE/ClientCode
<HTML>
<BODY BGCOLOR = "WHITE"> <BLOCKQUOTE>
<H3>Bonus Calculation</H3>
<FORM METHOD="GET" ACTION="BonusServlet">
<P> Enter social security Number:
<P> <INPUT TYPE="TEXT" NAME="SOCSEC"></INPUT>
<P> Enter Multiplier:
<P> <INPUT TYPE="TEXT" NAME="MULTIPLIER"></INPUT>
<P> <INPUT TYPE="SUBMIT" VALUE="Submit">
<INPUT TYPE="RESET">
</FORM> </BLOCKQUOTE>
</BODY>
</HTML>
Das Servlet
Retrieves the user data
Looks up the session bean
Passes the data to the session bean
Upon receiving a value back from the session
bean, creates an HTML page to display the
returned value to the user
Datei in
.../J2EE/ClientCode/BonusServlet.java
Initialisierungsmethode für Servlet
public class BonusServlet extends HttpServlet {
CalcHome homecalc;
public void init(ServletConfig config)
throws ServletException{
//Look up home interface
try{
InitialContext ctx = new InitialContext();
Object objref = ctx.lookup("calcs");
homecalc =
(CalcHome)PortableRemoteObject.narrow
(objref, CalcHome.class);
... }}
doGet Methode
Eingabe: request und response Objekt
Requests repräsentieren die Eingabe vom Browser
Responses repräsentieren einen Ausgabekanal
zum Browser
Aufgaben:
Finden des Home-Interfaces des Anwendungsobjekts
Aufruf der Methode calcBonus
Generieren des Antwort-HTML-Seite
doGet Methode (Ausschnitt)
public void doGet (HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
String socsec = null;
int multiplier = 0;
double calc = 0.0;
PrintWriter out;
response.setContentType("text/html");
String title = "EJB Example";
out = response.getWriter();
out.println("<HTML><HEAD><TITLE>")
out.println(title);
out.println("</TITLE></HEAD><BODY>");
doGet Methode (Ausschnitt)
try{
Calc theCalculation;
//Retrieve Bonus and Social Security Information
String strMult = request.getParameter("MULTIPLIER");
Integer integerMult = new Integer(strMult);
multiplier = integerMult.intValue();
socsec = request.getParameter("SOCSEC");
//Calculate bonus
double bonus = 100.00;
theCalculation = homecalc.create();
calc = theCalculation.calcBonus(multiplier, bonus);
} catch(Exception CreateException){
CreateException.printStackTrace();
}
doGet Methode (Ausschnitt)
//Display Data
out.println("<H1>Bonus Calculation</H1>");
out.println("<P>Soc Sec: " + socsec);
out.println("<P>Multiplier: " +
multiplier);
out.println("<P>Bonus Amount: " + calc);
out.println("</BODY></HTML>");
out.close();
}
Erstellung der Session Bean
Zustandlose Bean reicht aus
CalcBean.java
Calc.java
CalcHome.java
in .../J2EE/Beans
CalcHome
package Beans;
import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.ejb.EJBHome;
public interface CalcHome
extends EJBHome {
Calc create()
throws CreateException,
RemoteException;
}
Calc Remote Interface
package Beans;
import javax.ejb.EJBObject;
import java.rmi.RemoteException;
public interface Calc extends EJBObject {
public double calcBonus(int multiplier,
double bonus)
throws RemoteException;
}
CalcBean (Ausschnitt)
public class CalcBean implements SessionBean {
public double calcBonus(int multiplier, double bonus) {
double calc = (multiplier*bonus);
return calc;
}
public void ejbCreate() { }
public void setSessionContext(SessionContext ctx) { }
public void ejbRemove() { }
public void ejbActivate() { }
public void ejbPassivate() { }
public void ejbLoad() { }
public void ejbStore() { }
}
Übersetzung von Session Bean und Servel
#!/bin/sh
cd .../J2EE
J2EE_HOME=.../J2EE/j2sdkee1.2.1
CPATH=.:$J2EE_HOME/lib/j2ee.jar
javac -d . -classpath "$CPATH" Beans/CalcBean.java
Beans/CalcHome.java Beans/Calc.java
cd .../J2EE/ClientCode
J2EE_HOME=.../J2EE/j2sdkee1.2.1
CPATH=.:$J2EE_HOME/lib/j2ee.jar:
/home/monicap/J2EE
javac -d . -classpath "$CPATH" BonusServlet.java
Starten des Applikationsservers
j2sdkee1.2.1/bin/j2ee -verbose
... und des Deploy-Tools
deploytool
Fenster für J2EE Applications und Komponenten
Inspektorfenster für Information über ausgewählte
Applikation oder Komponenten
Server-Informationsfenster für installierte
Applikationen
Deploy-Tool
Zusammenbau der Applikation
Erzeugen eines J2EE-Applikation (BonusApp.ear).
Erzeugen einer Enterprise Bean (CalcBean.jar).
Erzeugen einer Web Komponente (Bonus.war).
Angabe eines JNDI Names für die Enterprise
bean (calcs).
Angabe eines sog. Root Context für die J2EEApplikation (BonusRoot).
Enterprise Bean
Web Komponente
JNDI-Eintrag und Root Context
Verifikation und Deployment der Applikation
Start der Applikation
Annahme : Web-Server verwendet Port 8000
(ggf. Konfigurierung in .../J2EE/j2sdkee1.2/config)
Eingabe der URL
http://localhost:8000/BonusRoot/bonus.html
in einem Brower
Ausgabe erfolgt in neuer HTML-Seite
Bonus Calculation
Soc Sec: 777777777
Multiplier: 25
Bonus Amount 2500.0
Diskussion
Die EJB-Architektur befindet sich zur Zeit in der
Entwicklung
Es wurde in dieser Vorlesung ein grober Eindruck der
Ziele und wesentlichen Ideen vermittelt, und ...
es wurden die grundlegenden Entwicklungsschritte für
einer N-Tier-Anwendung erläutert
Und beim nächsten Mal:
Transaktionsmanagement
Security
Persistenz
und eventuell etwas über Lastverteilung
(load balancing)