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)