Wzorce projektowe warstwy usług
Wzorce projektowe warstwy usług Service Locator Ułatwia wyszukanie komponentów usługowych Service Activator Umożliwia asynchroniczne przesyłanie żądań do komponentów biznesowych Session Façade Zapewnia wspólny interfejs dla wielu komponentów biznesowych Wzorce projektowe warstwy usług 2
Service Locator Wzorce projektowe warstwy usług 3/\
Service Locator - problemy Połączenie się z komponentem usługowym wymaga jego odnalezienia lub utworzenia nowego komponentu. Do tego celu wykorzystuje się obiekty domowe komponentów. Dla uzyskania dostępu do obiektu domowego trzeba utworzyć inicjalny kontekst usługi U wielu różnych klientów pojawia się ten sam kod wykorzystujący API usługi. Wyszukanie obiektu domowego zużywa znaczną ilość zasobów. Wzorce projektowe warstwy usług 4
Struktura komponentów Client uses «singleton» Service Locator uses creates uses uses uses Initial Context looks up Business Service looks up / creates Service Factory Wzorce projektowe warstwy usług 5/\
Współdziałanie komponentów Client «singleton» Service Locator Business Service 1: Get Instance 1.1: Get Instance Initial Context 2: Get service 2.1: Lookup 2.3: Return Service 2.4: Invoke Method 2.1.2: Return Service Factory 2.2: Get Service 2.1.1: Create Service Factory 2.2.1: Create / lookup Wzorce projektowe warstwy usług 6/\
Strategie implementacji Dla komponentów EJB z wykorzystaniem obiektu domowego (interfejs EJBHome) Przy wymianie komunikatów P2P (point-topoint) z wykorzystaniem kolejki komunikatów (JMS) Przy wymianie komunikatów P/S (publish/subscribe) z wykorzystaniem usług tematycznych Wzorce projektowe warstwy usług 7
Przykład implementacja lokalizatora z wykorzystaniem obiektu domowego (1) public class ServiceLocator private static ServiceLocator me; InitialContext context = null; private ProjectHome = null; private ResourceHome = null; // Tworzenie nowego kontekstu inicjalnego private ServiceLocator() context = new InitialContext(); // Implementacja Singletona metoda zwraca pojedynczą instancję klasy public static ServiceLocator getinstance() if (me == null) me = new ServiceLocator(); return me; Wzorce projektowe warstwy usług 8
Przykład implementacja lokalizatora z wykorzystaniem obiektu domowego (2) // Wyliczenie typów usług public class Services final public static int PROJECT = 0; final public static int RESOURCE = 1; // Definicje klasy i nazwy dla EJB "Project" final static Class PROJECT_CLASS = ProjectHome.class; final static String PROJECT_NAME = "Project"; // Definicje klasy i nazwy dla EJB "Resource" final static Class RESOURCE_CLASS = ResourceHome.class; final static String RESOURCE_NAME = "Resource"; Wzorce projektowe warstwy usług 9
Przykład implementacja lokalizatora z wykorzystaniem obiektu domowego (3) // Zwraca klasę dla danego typu usługi static private Class getserviceclass (int service) switch( service ) case Services.PROJECT: return PROJECT_CLASS; case Services.RESOURCE: return RESOURCE_CLASS; return null; // Zwraca nazwę JNDI dla danego typu usługi static private String getservicename (int service) switch( service ) case Services.PROJECT: return PROJECT_NAME; case Services.RESOURCE: return RESOURCE_NAME; return null; Wzorce projektowe warstwy usług 10
Przykład implementacja lokalizatora z wykorzystaniem obiektu domowego (4) // Zwraca obiekt domowy dla danego typu usługi // wykorzystując nazwę JNDI i klasę obiektu private EJBHome gethome (int service) EJBHome home = null; // utworzenie inicjalnego kontekstu Context initial = new InitialContext(); // Wyszukanie referencji do obiektu // przez inicjalny kontekst Object objref = initial.lookup (getservicename(service)); // Zawężenie klasy obiektu domowego Object obj = PortableRemoteObject.narrow (objref, getserviceclass(s)); // Utworzenie obiektu domowego home = (EJBHome)obj; return home; // Zwraca statyczny obiekt domowy dla usługi public EJBHome getservicehome(int service) switch( service ) case Services.PROJECT: if (ProjectHome==null) ProjectHome=GetHome(s); return ProjectHome; case Services.RESOURCE: if (ResourceHome==null) ResourceHome=GetHome(s); return ResourceHome; return null; Wzorce projektowe warstwy usług 11
Zalety zastosowania wzorca Ukrycie złożoności procesu wyszukiwania i tworzenia obiektów biznesowych Zapewnienie jednolitego dostępu do usług Ułatwienie dodawania nowych obiektów biznesowych Zwiększenie wydajności sieci Zwiększenie wydajności aplikacji przez lokalne buforowanie Wzorce projektowe warstwy usług 12
Service Activator Wzorce projektowe warstwy usług 13/\
Service Activator - motywacje Wywoływanie metod komponentów biznesowych następuje przez zdalne referencje w sposób synchroniczny. Brak mechanizmu zapewniającego ciągły stan aktywności i gotowości komponentu biznesowego. Niektórzy klienci nie chcą lub nie mogą czekać na zakończenie przetwarzania synchronicznego. Komponenty biznesowe nie zapewniają mechanizmu dostępu asynchronicznego do usług (zwłaszcza komponenty ze stanami i komponenty encji). Wzorce projektowe warstwy usług 14
Rozwiązanie Aktywator usług odbiera komunikaty od klientów i przetwarza je na wywołania komponentów usługowych. Może powiadamiać klienta o zakończeniu przetwarzania asynchronicznego lub o błędach w przetwarzaniu. Może być zaimplementowany jako osobna usługa (wywołuje usługi po stronie serwera). Może wykorzystywać lokalizator usług. Wzorce projektowe warstwy usług 15
Współdziałanie komponentów Client Service Activator Business Object 1 Business Object 2 1: Send (Message (Request)) 1.1: Parse (Message) 1.2: Process (Request) 1.3: Process (Request) 14: Send (Acknowledge (Result)) Wzorce projektowe warstwy usług 16/\
Strategie implementacji Dla komponentu usługowego: Zastosowanie komponentu encji Zastosowanie komponentu sesji Dla aktywatora usług: Implementacja w postaci osobnej aplikacji sterowanej komunikatami Implementacja w postaci usługi serwera aplikacji Komponent biznesowy w roli klienta Klientem może być inny komponent biznesowy Możliwość integracji starszych aplikacji z J2EE Wzorce projektowe warstwy usług 17
Przykład implementacja aktywatora przez kolejkę komunikatów (1) public class OrderServiceActivator implements javax.jms.messagelistener // Obiekty realizujące kolejkę komunikatów private QueueSession orderqueuesession; private QueueReceiver orderqueuereceiver; // Nazwy powinny pochodzić ze środowiska lub pliku konfiguracyjnego private String connfactoryname = "PendingOrdersQueueFactory"; private String queuename = "PendingOrders"; // Wykorzystywany lokalizator usług private JMSServiceLocator servicelocator; // Konstruktor aktywatora rozpoczyna nasłuchiwanie komunikatów public OrderServiceActivator(String connfactoryname, String queuename) super(); this.connfactoryname = connfactoryname; this.queuename = queuename; startlistener(); Wzorce projektowe warstwy usług 18
Przykład implementacja aktywatora przez kolejkę komunikatów (2) // Metoda nasłuchiwania private void startlistener() try // Korzystamy z lokalizatora usług i tworzymy połączenie dla kolejki servicelocator = new JMSServiceLocator (connfactoryname); qconnfactory = servicelocator.getqueueconnectionfactory(); qconn = qconnfactory.createqueueconnection(); // Tworzymy sesję kolejki, samą kolejkę i odbiornik kolejki orderqueuesession = qconn.createqueuesession (...); Queue ordersqueue = servicelocator.getqueue(queuename); orderqueuereceiver = orderqueuesession.createreceiver(ordersqueue); // Do odbiornika kolejki podłączamy ten komponent aktywatora orderqueuereceiver.setmessagelistener(this); catch (JMSException excp)... Wzorce projektowe warstwy usług 19
Przykład implementacja aktywatora przez kolejkę komunikatów (3) // Asynchronicznie wywoływana metoda reakcji na komunikat przychodzący do kolejki public void onmessage(message msg) try // rozpoznanie komunikatu Message msg... // wykorzystanie delegata biznesowego do przetwarzania zamówienia OrderProcessorDelegate orderprocdeleg = new OrderProcessorDelegate(); // Wykorzystanie parametrów z komunikatu do realizacji zamówienia orderprocdeleg.fulfillorder(...); // wysyłanie potwierdzenia... catch (JMSException jmsexcp)... catch (Exception excp)... Wzorce projektowe warstwy usług 20
Zalety i wady Możliwość wprowadzenia sterowania komunikatami dla starszych aplikacji Zapewnia asynchroniczne wywołanie dla wszystkich typów komponentów biznesowych. Zwalnia klientów od konieczności oczekiwania na zakończenie wykonywania usług. Implementacja w postaci osobnej aplikacji wymaga upewnienia się co to aktywności aplikacji rozwiązanie implementacja jako usługa serwera usług. Wzorce projektowe warstwy usług 21
Session Façade Wzorce projektowe warstwy usług 22/\
Session Façade - problemy Zmiany interfejsów komponentów usługowych wymuszają zmiany ich wykorzystania po stronie klienta. Brak jednolitej strategii dostępu dla klienta niespójne interfejsy komponentów usługowych Liczne żądania wywołania przekazywane między klientem a warstwą usług problemy z wydajnością sieci. Wzorce projektowe warstwy usług 23
Zalecenia Uprościć interfejs między klientami a komponentami biznesowymi. Zmniejszyć liczbę komponentów biznesowych udostępnianych dla klienta przez warstwę sieciową. Ukryć przed klientem interakcje i wzajemne zależności między komponentami biznesowymi. Stworzyć jednolitą, gruboziarnistą warstwę pośredniczącą oddzielającą komponenty biznesowe od warstwy aplikacji. Wzorce projektowe warstwy usług 24
Rozwiązanie Fasada sesji (Session Façade) jako klasa pośrednicząca pomiędzy warstwą aplikacji a warstwą usług, która: Zarządza interakcjami pomiędzy klientami a obiektami biznesowymi oraz pomiędzy samymi obiektami biznesowymi. Zarządza cyklem życia obiektów biznesowych (tworzenie, wyszukiwanie, modyfikacja, usuwanie). Może delegować zarządzanie do pojedynczego obiektu (np. lokalizatora usług). Modeluje nietrwałe relacje między obiektami jako przepływ pracy (workflow). Wzorce projektowe warstwy usług 25
Session Façade struktura komponentów Client uses «session» Session Facade accesses Business Object «entity» Business Entity «session» Business Session accesses accesses DAO Wzorce projektowe warstwy usług 26/\
Współdziałanie komponentów Client «session» Session Facade «entity» Business Entity 1 «session» Business Session «entity» Business Entity 2 DAO 1: Invoke Method 1.1: Get / Set Data 1.2: Invoke Method 2: Invoke Method 2.1: Invoke Method 2.1.1: Get / Set Data 2.1.2: Get/Set Data 3: Invoke Method 3.1: Get/Set Data Wzorce projektowe warstwy usług 27/\
Implementacja bezstanowa a implementacja stanowa Niekonwersacyjny proces biznesowy tylko jedno wywołanie metody umożliwia całkowite wykonanie usługi bezstanowy komponent sesyjny Konwersacyjny proces biznesowy wykonanie usługi wymaga kilku wywołań metod komponent sesyjny ze stanami Wzorce projektowe warstwy usług 28
Strategie implementacyjne dla obiektów biznesowych Implementacja przez komponent sesyjny Implementacja przez komponent encyjny Implementacja przez DAO Wzorce projektowe warstwy usług 29
Przykład interfejs zdalny fasady sesji (1) public interface ProjectResourceManager extends EJBObject // Połączenie do nowego zbioru encji public resetentities (String resourceid, String projectid,...) throws RemoteException, ResourceException ; // Przypisanie zasobu do projektu public void assignresourcetoproject (int numhours) throws RemoteException, ResourceException ; // Odłączenie zasobu od projektu public void unassignresourcefromproject () throws RemoteException, ResourceException ;... // Metody dostępu do danych zasobu public ResourceTO getresourcedata() throws RemoteException, ResourceException ; public void setresourcedata (ResourceTO resource) throws RemoteException, ResourceException ; public ResourceTO createnewresource (ResourceTO resource) throws ResourceException ; Wzorce projektowe warstwy usług 30
Przykład interfejs zdalny fasady sesji (2) // Blokowanie czasu zasobu public void addblockouttime(collection blockouttime) throws RemoteException,BlockoutTimeException ; // Aktualizacja blokady (odblokowanie) czasu zasobu public void updateblockouttime(collection blockouttime) throws RemoteException,BlockoutTimeException ; // Metody dostępu do angaży zasobu public Collection getresourcecommitments() throws RemoteException, ResourceException; // Metody dostępu do danych projektu public ProjectTO getprojectdata() throws RemoteException, ProjectException ; public void setprojectdata (ProjectTO project) throws RemoteException, ProjectException ; public ProjectTO createnewproject (ProjectTO project) throws RemoteException, ProjectException ;... Wzorce projektowe warstwy usług 31
Przykład implementacja fasady sesji (1) public class ProjectResourceManagerSession implements SessionBean // wewnętrzny kontekst sesji private SessionContext context; // Zdalne referencje do komponentów encyjnych private Resource resourceentity = null; private Project projectentity = null;... // Tworzenie sesji dla określonego zasobu i projektu public void ejbcreate(string resourceid, String projectid,...) throws CreateException, ResourceException try // Połączenie z wymaganymi komponentami encyjnymi connecttoentities(resourceid, projectid,...); catch(...)... Wzorce projektowe warstwy usług 32
Przykład implementacja fasady sesji (2) // Metoda połączenia z komponentami encyjnymi // dla podanych wartości kluczy głównych private void connecttoentities (String resourceid, String projectid) throws ResourceException resourceentity = getresourceentity(resourceid); projectentity = getprojectentity(projectid);... // Metoda ponownego połączenia fasady sesji // z innymi komponentami encyjnymi dla innych wartości kluczy public resetentities (String resourceid, String projectid,...) throws PSAException connecttoentities(resourceid, projectid,...); Wzorce projektowe warstwy usług 33
Przykład implementacja fasady sesji (3) // Prywatna metoda uzyskania dostępu do obiektu domowego zasobów private ResourceHome getresourcehome() throws ServiceLocatorException return ServiceLocator.getInstance().getHome ("ResourceEntity", ResourceHome.class); // Prywatna metoda uzyskania dostępu do obiektu domowego projektu private ProjectHome getprojecthome() throws ServiceLocatorException return ServiceLocator.getInstance().getHome ("ProjectEntity", ProjectHome.class); Wzorce projektowe warstwy usług 34
Przykład implementacja fasady sesji (4) // Prywatna metoda uzyskania dostępu do encji zasobu private Resource getresourceentity (String resourceid) throws ResourceException try ResourceHome home = getresourcehome(); return (Resource) home.findbyprimarykey(resourceid); catch(... )... // Prywatna metoda uzyskania dostępu do encji projektu private Project getprojectentity (String projectid) throws ProjectException... Wzorce projektowe warstwy usług 35
Przykład implementacja fasady sesji (5) // Metoda realizacji przepływu związanego z przypisaniem zasobu do projektu public void assignresourcetoproject (int numhours) throws PSAException try if ((projectentity == null) (resourceentity == null)) // Błąd przy braku dostępu do encji projektu lub zasobu throw new PSAException(...); ResourceTO resourceto = resourceentity.getresourcedata(); // Pobranie danych zasobu ProjectTO projectto = projectentity.getprojectdata(); // Pobranie danych projektu projectentity.addresource (resourceto); // Dodanie zasobu do projektu CommitmentTO commitment = new CommitmentTO(...); projectentity.addcommitment(commitment); catch(...)... // Utworzenie nowego angażu dla projektu // Dodanie angażu do zasobu Wzorce projektowe warstwy usług 36
Skutki zastosowania wzorca (1) Wprowadza warstwę sterującą warstwą biznesową w większych aplikacjach można zastosować wiele fasad sesji w mniejszych służy jako proxy Przedstawia jednolity interfejs Upraszcza interfejs do warstwy biznesowej Ujednolica interfejsy do różnych komponentów usługowych Zmniejsza powiązanie, ułatwia zarządzanie Przy modyfikacji warstwy usług aplikacje klienckie mogą pozostać bez zmian modyfikacje kończą się w warstwie pośredniczącej Zwiększa wydajność, redukuje drobnoziarnistość metod Zmniejsza narzut sieciowy na aplikację poprzez zmniejszenie liczby wywołań usług z warstwy biznesowej przez klienta. W zamian klienci wywołują gruboziarniste usługi fasady. Wzorce projektowe warstwy usług 37
Skutki zastosowania wzorca (2) Zapewnia dostęp gruboziarnisty Zamiast osobnego interfejsu do każdego komponentu encyjnego można stosować pojedynczą fasadę dla każdego podsystemu. Jedna fasada dla całego systemu tylko w prostych aplikacjach Centralizuje zarządzanie bezpieczeństwem Poprzez scentralizowanie metod bezpieczeństwa w fasadzie można prowadzić ujednoliconą politykę bezpieczeństwa dla wszystkich komponentów usługowych (nie potrzebne wielokrotne logowanie) Centralizuje sterowanie transakcjami Umożliwia dopasowanie usług do modelu przypadków użycia na zasadzie przepływu sterowania (workflow). Umożliwia sterowanie transakcyjne. Prezentuje mniej zdalnych interfejsów dla klientów Ułatwia zrozumienie interfejsu przez klienta. Wzorce projektowe warstwy usług 38
Literatura Rysunki i przykłady pochodzą z następujących źródeł: http://java.sun.com/blueprints/corej2eepatterns/patterns/servicelocator.html http://java.sun.com/blueprints/corej2eepatterns/patterns/serviceactivator.html http://java.sun.com/blueprints/corej2eepatterns/patterns/sessionfacade.html Literatura uzupełniająca: Gamma et al: Wzorce projektowe, WNT Warszawa 2005 http://student.agh.edu.pl/~zegarow/filez/wzorce/wzorce_projektowe.pdf Buschman et al: Pattern-Oriented Software Architecture Volume 1: A System of Patterns, Wyd. Wiley, Schmidt et al: Pattern-Oriented Software Architecture Volume 2: Patterns for Concurrent and Networked Objects, Wyd. Wiley, Wzorce projektowe warstwy danych 39