71 Wprowadzenie do Enterprise JavaBeans 2.0 Maciej Zakrzewicz Maciej.Zakrzewicz@cs.put.poznan.pl http://www.cs.put.poznan.pl/mzakrzewicz/
Plan rozdziału 72 Wprowadzenie do EJB Rodzaje komponentów Zdalny i lokalny dostęp do komponentów
Charakterystyka EJB 73 Enterprise JavaBeans (EJB) to przenaszalne komponenty implementujące przetwarzanie danych zgodne z logiką biznesową Enterprise JavaBeans nigdy nie są wykonywane samodzielnie ich metody są wywoływane przez programy klientów EJB (którymi mogą być inne EJB) Dwa rodzaje klientów EJB: zdalny i lokalny (ta sama JVM) Rodzaje komponentów EJB: Sesyjne EJB (Session EJB): pozwalają wykonywać dowolny kod w architekturze RMI Encyjne EJB (Entity EJB): obsługują komunikację z bazą danych; reprezentują rekordy znajdujące się w bazie danych Komunikatowe EJB (Message-Driven EJB): są odbiorcami asynchronicznych komunikatów JMS (Java Messaging System)
Przegląd rodzajów komponentów EJB 74 EJB Sesyjne Encyjne Komunikatowe Stanowe Bezstanowe CMP BMP Wartości atrybutów obiektu są przechowywane pomiędzy wywołaniami Wartości atrybutów obiektu są tracone pomiędzy wywołaniami Interakcja z bazą danych implementowana przez programistę Interakcja z bazą danych implementowana przez kontener
EJB 2.0: składniki (1/2) 75 Interfejs Remote: (javax.ejb.ejbobject) deklaruje metody komponentu, które będą dostępne dla klientów zdalnych Interfejs Local: (javax.ejb.ejblocalobject) deklaruje metody komponentu, które będą dostępne dla klientów lokalnych Obiekt EJB: wygenerowana przez kontener implementacja interfejsu Remote; deleguje wywołania metod do obiektu komponentu (EJB Bean) Interfejs Home: (javax.ejb.ejbhome) deklaruje metody zarządzania cyklem życia komponentu dla klientów zdalnych Interfejs Local Home: (javax.ejb.ejblocalhome) deklaruje metody zarządzania cyklem życia komponentu dla klientów lokalnych Obiekt Home: wygenerowana przez kontener implementacja interfejsu Home; wykorzystuje metody callback klasy komponentu
EJB 2.0: składniki (2/2) 76 Klasa komponentu EJB: (javax.ejb.sessionbean/entitybean) implementuje metody biznesowe oraz metody zarządzania cyklem życia komponentu Klasa komponentu EJB dla komponentów komunikatowych implementuje interfejsy javax.ejb.messagedrivenbean i MessageListener; zawiera metodę onmessage(), implementującą logikę biznesową Deskryptor instalacji: dokument XML opisujący wszystkie pozostałe składniki komponentu EJB
Zdalny dostęp do komponentu EJB (sesyjny EJB, encyjny EJB) 77 Klient EJB 3 Żądanie utworzenia obiektu EJB OC4J kontener EJB obiekt Home 5 Referencja do obiektu EJB 2 Referencja do obiektu Home 1 Pobranie referencji do obiektu Home JNDI 4 Utworzenie obiektu EJB obiekt EJB 6 Wywołanie metody EJB 7 Delegacja wywołania EJB Bean
Zdalny dostęp do komponentu EJB (komunikatowy EJB) 78 OC4J Klient EJB 3 Nazwiązanie połączenia z kolejką 4 Wysłanie komunikatu EJB Bean 6 Delegacja wywołania obiekt EJB 5 Odbiór komunikatu 2 Referencja do kolejki 1 Pobranie referencji do kolejki JNDI JMS
Klient EJB dla sesyjnych i encyjnych EJB 79 Klientem EJB może być samodzielna aplikacja Java, serwlet Java, aplikacja JSP lub komponent EJB Klient lokalny: funkcjonuje w ramach tej samej JVM, w której pracuje komponent przekazuje argumenty metod komponentu za pomocą referencji posiada dostęp do metod komponentu EJB zadeklarowanych w interfejsie Local Klient zdalny: może znajdować się na dowolnej maszynie przekazuje argumenty metod komponentu za pomocą wartości posiada dostęp do metod komponentu EJB zadeklarowanych w interfejsie Remote
Zdalny klient EJB: przykład 80 1. Przygotuj ustawienia JNDI 2. Utwórz obiekt klasy InitialContext() 3. Pobierz referencję do obiektu Home przy pomocy metody lookup 4. Dokonaj rzutowania otrzymanego obiektu przy pomocy interfejsu Local Home i metody PortableRemoteObject.narrow() 5. Utwórz obiekt komponentu przy pomocy metody create() Hashtable env = new Hashtable(); env.put(context.initial_context_factory, "com.evermind.server.rmi.rmiinitialcontextfactory"); env.put(context.security_principal, "admin"); env.put(context.security_credentials, "welcome"); env.put(context.provider_url, "http:ormi://miner.cs.put.poznan.pl/moja_aplikacja"); Context context = new InitialContext(env); SessionEJBHome myhome = (SessionEJBHome) PortableRemoteObject.narrow(context.lookup("SessionEJB"), SessionEJBHome.class); SessionEJB myejb; myejb = myhome.create(); System.out.println(myEJB.dodaj(2,3));
Lokalny klient EJB: przykład 81 1. Zarejestruj wołany komponent EJB w pliku web.xml (application-client.xml, ejb-jar.xml) nadaj mu nazwę logiczną 2. Utwórz obiekt klasy InitialContext() 3. Pobierz referencję do obiektu Home przy pomocy metody lookup (stosuj lokalny adres o postaci java:comp/env/...) 4. Dokonaj rzutowania otrzymanego obiektu przy pomocy interfejsu Local Home 5. Utwórz obiekt komponentu przy pomocy metody create() web.xml <ejb-local-ref> <ejb-ref-name>ejb/myejb</ejb-ref-name> <ejb-ref-type>session</ejb-ref-type> <local-home>sessionejblocalhome</local-home> <local>sessionejblocal</local> </ejb-local-ref> Context context = new InitialContext(); SessionEJBLocalHome myhome = (SessionEJBLocalHome) context.lookup("java:comp/env/ejb/myejb"); SessionEJBLocal myejblocal; myejblocal = myhome.create(); out.println(myejblocal.dodaj(2,3)); serwlet Java
Dostęp do EJB z poziomu JSP 82 Użycie biblioteki znaczników OJSP EJB: <%@ taglib uri="/web-inf/ejbtaglib.tld" prefix="ejb" %> Wyszukanie komponentu poprzez JNDI oraz utworzenie obiektu Home: <ejb:usehome id = "nazwa_obiektu_home" type = "nazwa_interfejsu_home" location = "nazwa_jndi" [local = "true" "false"]/> Utworzenie obiektu komponentu i rzutowanie przy pomocy interfejsu Remote <ejb:usebean id = "nazwa_obiektu_komponentu" type = "nazwa_interfejsu_remote" [scope="page" "request" "session" "application"][local="true" "false"]> <ejb:createbean instance="<%=nazwa_obiektu_home.create()%>" /> </ejb:usebean> Wywoływanie metod obiektu komponentu <% nazwa_obiektu_komponentu.metoda() %>
OJSP EJB: przykład 83 <%@ taglib uri="/web-inf/ejbtaglib.tld" prefix="ejb" %>... <!-- Utwórz obiekt Home --> <ejb:usehome id="baskethome" type="mypackage6.basketejblocalhome" location="java:comp/env/ejb/basketejb" local="true" /> <!-- Utwórz obiekt EJB --> <ejb:usebean id = "basketbean" type = "mypackage6.basketejblocal" scope="session" local="true"> <ejb:createbean instance="<%=baskethome.create()%>" /> </ejb:usebean> <!-- Dodaj nowy element do koszyka --> <% if (request.getparameter("add")!=null) basketbean.addtobasket(request.getparameter("add")); %>...
Sesyjne komponenty EJB 84
Plan rozdziału 85 Wprowadzenie Rodzaje sesyjnych EJB Implementacja sesyjnych EJB Przykład tworzenia prostego sesyjnego EJB Tworzenie sesyjnego komponentu EJB w środowisku JDeveloper9i/10g
Wprowadzenie 86 Sesyjny EJB to komponent biznesowy o następującej charakterystyce: Jest używany przez jednego klienta lub użytkownika Istnieje tylko przez czas trwania sesji Jest niszczony w wypadku awarii kontenera Nie jest obiektem trwałym Może zostać przekroczony dla niego limit czasu życia Może uczestniczyć w transakcjach Może posłużyć do zamodelowania stanowej lub bezstanowej komunikacji między klientem a komponentami warstwy biznesowej
Rodzaje sesyjnych EJB 87 Stanowy sesyjny EJB (Stateful Session EJB) zapamiętuje stan pomiędzy kolejnymi wywołaniami przez tego samego klienta dla każdego klienta powoływane jest oddzielne wystąpienie komponentu stan komponentu może być zapisywany w systemie plików (pasywacja) algorytm LRU pasywacji nie podlegają zasoby: połączenia sieciowe, połączenia z bazą danych, itp. jest to zadaniem programisty (ejbpassivate(), ejbactivate()) przykładowe zastosowania: koszyk zakupów, tymczasowe struktury danych Bezstanowy sesyjny EJB (Stateless Session EJB) nie zapamiętuje stanu przykładowe zastosowania: przeliczanie walut, wyliczanie rat kredytu kolejne odwołania pochodzące od tego samego klienta mogą być realizowane przez różne obiekty komponentu, znajdujące się w puli kontenera EJB zwykle nie implementuje ciała żadnych metod interfejsu SessionBean Wyboru rodzaju sesyjnego EJB dokonuje się w pliku deskryptora instalacji (ejb-jar.xml)
Implementacja sesyjnych EJB 88 Implementują interfejs javax.ejb.sessionbean: setsessioncontext(sessioncontext ctx) W chwili utworzenia, obiekt komponentu otrzymuje tzw. obiekt kontekstu, przydatny do interakcji z kontenerem (calback) ejbactivate() Wywoływana gdy kontener przywraca obiekt komponentu do pamięci, po jego wcześniejszym przeniesieniu na dysk ejbpassivate() Wywoływana gdy kontener przenosi obiekt komponentu z pamięci na dysk ejbcreate() Wywoływana gdy tworzony jest nowy obiekt komponentu ejbremove() Wywoływana bezpośrednio przed likwidacją obiektu komponentu przez kontener (np. zakończenie sesji)
Metoda setsessioncontext() 89 Obiekt SessionContext przekazywany przez kontener do metody setsessioncontext() oferuje następujące metody: getejbobject() zwraca referencję do obiektu EJB getejbhome() zwraca interfejs Home getcalleridentity() obiekt opisujący tożsamość wołającego użytkownika getenvironment() zwraca zmienne środowiska komponentu EJB setrollbackonly() zaznacza bieżącą transakcję jako transakcję do wycofania getusertransaction() zwraca kontekst transkakcji iscallerinrole() sprawdza, czy wołający użytkownik posiada podaną rolę public class mybean implements SessionBean { SessionContext sessctx; void setsessioncontext(sessioncontext ctx) { sessctx = ctx; Typowa implementacja metody setsessioncontext() polega na kopiowaniu obiektu SessionContext do zmiennej wystąpienia, która będzie dostępna dla innych metod komponentu. }...
Cykl życia sesyjnego EJB 90 Brak setsessioncontext(ctx) ejbcreate() ejbremove() Gotowy ejbpassivate() ejbactivate() Pasywny wyłącznie dla stanowych sesyjnych EJB
91 Przykład tworzenia prostego sesyjnego EJB Klasa komponentu Interfejs Remote import javax.ejb.*; import javax.ejb.*; import java.rmi.remoteexception; public class SessionEJBBean implements SessionBean { public void ejbcreate() {} public void ejbactivate() {} public void ejbpassivate() {} public void ejbremove() {} public void setsessioncontext(sessioncontext ctx) {} public double dodaj(double a, double b) { return a+b; }} Interfejs Home import javax.ejb.*; import java.rmi.remoteexception; public interface SessionEJB extends EJBObject { double dodaj(double a, double b) throws RemoteException; } Deskryptor instalacji... <description>session Bean ( Stateless )</description> <display-name>sessionejb</display-name> <ejb-name>sessionejb</ejb-name> <home>sessionejbhome</home> <remote>sessionejb</remote> <ejb-class>sessionejbbean</ejb-class> <session-type>stateless</session-type> public interface SessionEJBHome extends EJBHome { SessionEJB create() throws RemoteException,... CreateException; }
Tworzenie sesyjnego komponentu EJB w 92 środowisku JDeveloper9i/10g Utworzenie nowego komponentu EJB Nazwa komponentu, jego rodzaj (stanowy/bezstanowy) Na kolejnych stronach: nazwa klasy komponentu, nazwy interfejsów Home, Remote, Local Home, Local Remote
Tworzenie sesyjnego komponentu EJB w 93 środowisku JDeveloper9i/10g Utworzone pliki dla komponentu sesyjnego SessionEJB: SessionEJB.java interfejs Remote SessionEJBBean.java klasa komponentu SessionEJBHome interfejs Home SessionEJBLocal.java interfejs Local Remote SessionEJBLocalHome.java interfejs Local Home ejb-jar.xml standardowy deskryptor instalacji orion-ejb-jar.xml specyficzny dla OC4J deskryptor instalacji 9i 10g
Tworzenie sesyjnego komponentu EJB w 94 środowisku JDeveloper9i/10g Implementacja metod komponentu: 9i: (Menu kontekstowe na ikonie reprezentującej komponent -> Edit EJB -> Methods ->Add) 10g: (Dwuklik -> Methods-> Add)
Tworzenie sesyjnego komponentu EJB w 95 środowisku JDeveloper9i/10g Tworzenie aplikacji klienta EJB Uruchamianie lokalnie: Run na komponencie Run na kliencie
Komunikatowe komponenty EJB 96
Plan rozdziału 97 Wstęp: systemy przekazywania komunikatów Charakterystyka OC4J Java Messaging Service Wykorzystywanie JMS API Przykładowy komunikatowy EJB Tworzenie komunikatowego EJB w środowisku JDeveloper9i/10g
Wstęp: systemy przekazywania komunikatów 98 Systemy przekazywania komunikatów (Messaging Systems) służą do asynchronicznej wymiany danych pomiędzy aplikacjami OC4J JMS Oracle Advanced Queueing IBM MQSeries BEA WebLogic JMS Sun iplanet Message Queue Programy Java wykorzystują systemy przekazywania komunikatów przy pomocy biblioteki JMS API (Java Messaging Service API) Klient JMS API publisher OC4J JMS Klient JMS API subscriber
OC4J JMS 99 Obiekty zarejestrowane w JNDI: Connection Factory: odpowiada za tworzenie połączeń klientów z usługą JMS Destination: tematy (topics) lub kolejki (queues) do których komunikaty są wysyłane lub z których są odbierane Modele komunikacji: Point-to-point: nadawca wysyła wiadomość do kolejki, odbiorca odbiera wiadomość z kolejki; z jednej kolejki może korzystać wielu nadawców i wielu odbiorców, ale każdy nadawany komunikat jest adresowany do konkretnego odbiorcy Publish-and-subscribe: nadawca wysyła wiadomość do tematu, wiadomość jest automatycznie rozsyłana do wszystkich odbiorców tematu; z jednego tematu może korzystać wielu nadawców i odbiorców
Konfiguracja OC4J: jms.xml 100 <jms-server port="9127"> <topic name="demo Topic" location="jms/demotopic"> <description>temat demo</description> </topic> <topic-connection-factory name="demo Connection Factory" location="jms/thetopicconnectionfactory"> <description>connection Factory dla tematu demo</description> </topic-connection-factory> <log> <file path="../log/jms.log" /> </log> </jms-server>
JMS API 101 Wysyłanie komunikatu do kolejki: wyszukaj Connection Factory poprzez JNDI wyszukaj kolejkę poprzez JNDI otwórz połączenie i rozpocznij sesję utwórz obiekt-nadawcę utwórz komunikat wyślij komunikat zamknij używane obiekty Typy komunikatów: TextMessage MapMessage BytesMessage StreamMessage ObjectMessage Context ctx = new InitialContext(); QueueConnectionFactory cf = (QueueConnectionFactory) ctx.lookup(...); QueueConnection conn = cf.createqueueconnection(); conn.start(); QueueSession sess = conn.createqueuesession(false, Session.AUTO_ACKNOWLEDGE); Queue queue = (Queue) ctx.lookup(...); QueueSender sender = sess.createsender(queue); TextMessage message = sess.createtextmessage(); message.setlongproperty("msgid",...); message.settext(...); sender.send(message); sender.close(); sess.close(); conn.close();
JMS API 102 Wysyłanie komunikatu do tematu: wyszukaj Connection Factory poprzez JNDI wyszukaj temat poprzez JNDI otwórz połączenie i rozpocznij sesję utwórz obiekt-nadawcę utwórz komunikat wyślij komunikat zamknij używane obiekty Context ctx = new InitialContext(); TopicConnectionFactory topicfactory = (TopicConnectionFactory) ctx.lookup(...); TopicConnection topicconnection = topicfactory.createtopicconnection(); TopicSession session = topicconnection.createtopicsession( false, Session.AUTO_ACKNOWLEDGE); Topic topic = (Topic) context.lookup("..."); TopicPublisher pub = session.createpublisher(topic); TextMessage message = session.createtextmessage(); message.settext(...); pub.publish(topic, message); topicconnection.close();
Komunikatowe komponenty EJB 103 Komunikatowe EJB (Message-Driven Beans): są asynchronicznymi odbiorcami komunikatów JMS są bezstanowe, wykonywane po stronie serwera aplikacji nie łączą się bezpośrednio z klientami nie posiadają interfejsu Home ani interfejsu Remote są uruchamiane w chwili nadejścia nowego komunikatu (metoda onmessage()) implementują interfejsy javax.ejb.messagedrivenbean i javax.jms.messagelistener cykl życia jest identyczny jak cykl życia bezstanowego sesyjnego EJB
Przykładowy komunikatowy EJB 104 Klasa komponentu public class MyMessageDrivenEJBBean implements MessageDrivenBean, MessageListener { private MessageDrivenContext context; public void ejbcreate() {} public void onmessage(message msg) { try { TextMessage textmessage = (TextMessage) msg; String text = textmessage.gettext(); System.out.println(text); } catch (Exception e) {} } public void ejbremove() {} public void setmessagedrivencontext (MessageDrivenContext ctx) { this.context = ctx; } } <enterprise-beans> <message-driven> Deskryptor instalacji <description>message Driven Bean</description> <display-name>mymessagedrivenejb</display-name> <ejb-name>mymessagedrivenejb</ejb-name> <ejb-class>mypackage7.impl.mymessagedrivenejbbean </ejb-class> <transaction-type>container</transaction-type> <acknowledge-mode>auto-acknowledge </acknowledge-mode> <message-driven-destination> <destination-type>javax.jms.queue</destination-type> </message-driven-destination> </message-driven> </enterprise-beans>
Tworzenie komunikatowego EJB w środowisku JDeveloper9i/10g 105 Utworzenie nowego komponentu EJB Powiązanie z JMS (orion-ejb-jar.xml)