Wprowadzenie do Enterprise JavaBeans 2.0
Transkrypt
Wprowadzenie do Enterprise JavaBeans 2.0
71 Wprowadzenie do Enterprise JavaBeans 2.0 Maciej Zakrzewicz [email protected] http://www.cs.put.poznan.pl/mzakrzewicz/ 72 Plan rozdziału • Wprowadzenie do EJB • Rodzaje komponentów • Zdalny i lokalny dostęp do komponentów 73 Charakterystyka EJB • 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) 74 Przegląd rodzajów komponentów EJB EJB Sesyjne Stanowe Bezstanowe CMP Wartości atrybutów obiektu są tracone pomiędzy wywołaniami Wartości atrybutów obiektu są przechowywane pomiędzy wywołaniami Komunikatowe Encyjne BMP Interakcja z bazą danych implementowana przez programistę Interakcja z bazą danych implementowana przez kontener 75 EJB 2.0: składniki (1/2) • 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 76 EJB 2.0: składniki (2/2) • 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) OC4J 3 Żądanie utworzenia obiektu EJB kontener EJB obiekt Home Klient EJB 5 Referencja do obiektu EJB 4 Utworzenie obiektu EJB obiekt EJB 6 Wywołanie metody EJB 7 Delegacja wywołania EJB Bean 2 Referencja do obiektu Home JNDI 1 Pobranie referencji do obiektu Home 77 Zdalny dostęp do komponentu EJB (komunikatowy EJB) OC4J Klient EJB 3 Nazwiązanie połączenia z kolejką 4 Wysłanie komunikatu EJB Bean 6 Delegacja wywołania obiekt EJB 5 2 Odbiór komunikatu Referencja do kolejki JNDI 1 Pobranie referencji do kolejki JMS 78 79 Klient EJB dla sesyjnych i encyjnych EJB • 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 80 Zdalny klient EJB: przykład 1. 2. 3. 4. 5. Przygotuj ustawienia JNDI Utwórz obiekt klasy InitialContext() Pobierz referencję do obiektu Home przy pomocy metody lookup Dokonaj rzutowania otrzymanego obiektu przy pomocy interfejsu Local Home i metody PortableRemoteObject.narrow() 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)); 81 Lokalny klient EJB: przykład 1. 2. 3. 4. 5. Zarejestruj wołany komponent EJB w pliku web.xml (application-client.xml, ejb-jar.xml) – nadaj mu nazwę logiczną Utwórz obiekt klasy InitialContext() Pobierz referencję do obiektu Home przy pomocy metody lookup (stosuj lokalny adres o postaci java:comp/env/...) Dokonaj rzutowania otrzymanego obiektu przy pomocy interfejsu Local Home 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> serwlet Java 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)); 82 Dostęp do EJB z poziomu JSP • 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() %> 83 OJSP EJB: przykład <%@ 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")); %> ... 84 Sesyjne komponenty EJB 85 Plan rozdziału • • • • • Wprowadzenie Rodzaje sesyjnych EJB Implementacja sesyjnych EJB Przykład tworzenia prostego sesyjnego EJB Tworzenie sesyjnego komponentu EJB w środowisku JDeveloper9i/10g 86 Wprowadzenie • 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 87 Rodzaje sesyjnych EJB • 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) 88 Implementacja sesyjnych EJB • 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) 89 Metoda setSessionContext() • 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. 90 Cykl życia sesyjnego EJB Brak setSessionContext(ctx) ejbCreate() ejbRemove() ejbPassivate() Gotowy Pasywny ejbActivate() 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 interface SessionEJB extends EJBObject { public void ejbActivate() {} public void ejbPassivate() {} double dodaj(double a, double b) throws RemoteException; } public void ejbRemove() {} Deskryptor instalacji public void setSessionContext(SessionContext ctx) {} public double dodaj(double a, double b) { ... <description>Session Bean ( Stateless )</description> return a+b; <display-name>SessionEJB</display-name> }} <ejb-name>SessionEJB</ejb-name> Interfejs Home <home>SessionEJBHome</home> import javax.ejb.*; <remote>SessionEJB</remote> import java.rmi.RemoteException; <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 96 Komunikatowe komponenty EJB 97 Plan rozdziału • • • • • 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 • 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 98 99 OC4J JMS • 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 100 Konfiguracja OC4J: jms.xml <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> 101 JMS API • Wysyłanie komunikatu do kolejki: – – – – – – – wyszukaj Connection Factory poprzez JNDI wyszukaj kolejkę poprzez JNDI otwórz połączenie i rozpocznij sesję Context ctx = new InitialContext(); QueueConnectionFactory cf = utwórz obiekt-nadawcę (QueueConnectionFactory) ctx.lookup(...); utwórz komunikat QueueConnection conn = cf.createQueueConnection(); wyślij komunikat conn.start(); QueueSession sess = conn.createQueueSession(false, zamknij używane obiekty • Typy komunikatów: – – – – – TextMessage MapMessage BytesMessage StreamMessage ObjectMessage 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(); 102 JMS API • 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ę Context ctx = new InitialContext(); utwórz komunikat TopicConnectionFactory topicFactory = wyślij komunikat (TopicConnectionFactory) ctx.lookup(...); zamknij używane obiekty 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(); 103 Komunikatowe komponenty EJB • 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 104 Przykładowy komunikatowy EJB Klasa komponentu public class MyMessageDrivenEJBBean implements MessageDrivenBean, MessageListener { private MessageDrivenContext context; public void ejbCreate() {} <enterprise-beans> Deskryptor instalacji <message-driven> public void onMessage(Message msg) { <description>Message Driven Bean</description> try { <display-name>MyMessageDrivenEJB</display-name> TextMessage textMessage = (TextMessage) msg; <ejb-name>MyMessageDrivenEJB</ejb-name> String text = textMessage.getText(); <ejb-class>mypackage7.impl.MyMessageDrivenEJBBean System.out.println(text); </ejb-class> } catch (Exception e) {} <transaction-type>Container</transaction-type> } <acknowledge-mode>Auto-acknowledge </acknowledge-mode> public void ejbRemove() {} <message-driven-destination> <destination-type>javax.jms.Queue</destination-type> public void setMessageDrivenContext (MessageDrivenContext ctx) { this.context = ctx; } } </message-driven-destination> </message-driven> </enterprise-beans> Tworzenie komunikatowego EJB w środowisku JDeveloper9i/10g Utworzenie nowego komponentu EJB Powiązanie z JMS (orion-ejb-jar.xml) 105