Seam framework in_action
Upcoming SlideShare
Loading in...5
×
 

Like this? Share it with your network

Share

Seam framework in_action

on

  • 2,996 views

Presentation about Seam Framework

Presentation about Seam Framework

Statistics

Views

Total Views
2,996
Views on SlideShare
2,716
Embed Views
280

Actions

Likes
2
Downloads
28
Comments
0

4 Embeds 280

http://michalorman.pl 224
http://www.slideshare.net 46
http://localhost:4000 5
http://www.linkedin.com 5

Accessibility

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Seam framework in_action Presentation Transcript

  • 1. Seam Framework w akcji
  • 2. Szew ● Miejsce zszycia kawałków tkaniny, futra itp. wraz z nićmi, którymi te kawałki zszyto. ● Operacyjne zszycie tkanek miękkich. ● Naturalne połączenie dwu przylegających do siebie kości spojonych tkanką łączną. ● Połączenie brzegów przedmiotów metalowych za pomocą nitkowania lub spawania.
  • 3. JSF EJB
  • 4. AJAX Facelets JSF ICEFaces GWT RichFaces Drools Wicket Spring WebBeans JPA EJB Hibernate Guice Groovy jBMP Seam one framework to rule them all...
  • 5. Czym jest Seam?
  • 6. Stos aplikacji ● Integruje różne frameworki z różnych warstw JEE ● Widoku (JSF, RichFaces, ICEFaces, Wicket) ● Dostępu do danych (JPA, Hibernate) ● i więcej ...
  • 7. Kontener komponentów ● Integruje komponenty JPA, EJB, POJO oraz JSF w taki sposób, że zaciera granice pomiędzy poszczególnymi warstwami i daje wrażenie korzystania z jednego kontenera
  • 8. Komponenty i kontenery Kontener Tworzenie komponentu EJB @Stateful, @Stateless, @MessageDriven, ejb- jar.xml JSF faces-config.xml Spring applicationContext.xml Kontener servletów web.xml
  • 9. Komponenty i kontenery Kontener Tworzenie komponentu EJB @Stateful, @Stateless, @MessageDriven, ejb- jar.xml JSF faces-config.xml Spring applicationContext.xml Kontener servletów web.xml Seam @Name, components.xml
  • 10. Facelets / RichFaces / JSP JSF Seam EJB / Spring / JPA / Hibernate Seam context variable
  • 11. Definiowanie komponentu Seam 1. @Name("foo") 2. @Scope(ScopeType.CONVERSATION) 3. public class Foo { }
  • 12. Wstrzykiwanie zależności 1. @Name("bar") 2. public class Bar { 3. 4. @In 5. private Foo foo; 6. 7. }
  • 13. Wstrzykiwanie zależności cd... 1. @Name("bar") 2. public class Bar { 3. 4. @In(create = true) 5. private Foo foo; 6. 7. }
  • 14. Wstrzykiwanie zależności cd... 1. @Name("bar") 2. public class Bar { 3. 4. @In("#{foo}") 5. private Foo foo; 6. 7. }
  • 15. Inversion of Control ● Wzorzec projektowy „rozluźniający” powiązania pomiędzy komponentami ● Pozwala komponentom na skupienie się na wykorzystywaniu innych komponentów (serwisów) niż ich wyszukiwaniu ● Wszyscy go dobrze znają...
  • 16. Inversion of Control ● Zwykle ludzie mówiąc o IoC mają na myśli dependency injection (DI), jeden z przypadków użycia IoC ● Jednakże IoC > DI
  • 17. DI jest zbyt statyczne Problem z klasycznym podejściem do DI jest taki, że wstrzykiwanie zależności odbywa się tylko raz, tuż po stworzeniu instancji komponentu. Komponent jest przywiązany do referencji obiektów wstrzykniętych mu w czasie tworzenia. Komponenty powinny być świadome swojego istnienia w kontekście i powinny brać aktywny udział w zarządzaniu komponentami.
  • 18. IoC w Seam ● W Seam mamy do czynienia z dependency bijection ● W Seam zależności są wstrzykiwane dynamicznie w czasie życia komponentu, a nie tylko podczas jego tworzenia ● Dependency bijection pozwala na wstrzykiwanie zależności do komponentu, jak i umieszczanie komponentów w kontekście ● Bijection = injection + outjection
  • 19. Bijection ● Bijection jest to kombinacja injection i outjection ● Bijection zachodzi w momencie wywołania metody (a nie tworzenia komponentu) ● Injection w momencie wywołania metody ● Outjection po powrocie metody
  • 20. Disinjection ● Wszystkie pola komponentów do których zostały wstrzyknięte zależności otrzymują wartość null. ● Zapobiega wyciekom pamięci ● Rozwiązuje problem serializacji obiektów
  • 21. Bijection interceptor Komponent wywołujący metodę Interceptor Wstrzykiwanie zależności w pola oznaczone adnotacją @In Wywołanie metody Outjection na polach oznaczonych adnotacją @Out Disinjection na polach oznaczonych adnotacją @In Powrót z metody
  • 22. Bijection w akcji 1. @Name("authenticator") 2. public class Authenticator { 3. @In 4. private Credentials credentials; 5. 6. @Out(scope = ScopeType.SESSION, required = false) 7. private Long currentUserId; 8. 9. @In(create = true) 10. private UserQuery userQuery; 11. 12. public boolean authenticate() { 13. userQuery.setUsername(credentials.getUsername()); 14. User user = userQuery.getSingleResult(); 15. if (isPasswordValid(credentials.getPassword(), user)) { 16. currentUserId = user.getId(); 17. } 18. } 19. 20. // pozostałe metody 21. }
  • 23. Inne formy wstrzykiwania zależności ● @RequestParameter ● @PersistenceContext ● @DataModelSelection ● @DataModelSelectionIndex
  • 24. Inne formy dependency outjection ● @DataModel ● @Factory ● @Unwrap
  • 25. Omijanie bijection ● Wewnętrzne wywołania metod ● @BypassInterceptors
  • 26. Generowanie zdarzeń
  • 27. Zdarzenia ● Seam posiada wbudowane wsparcie dla wzorca observer, który w znacznym stopniu pozwala redukować zależności między komponentami (budować luźne powiązania) ● Seam pozwala na generowanie zdarzeń z metod jak i ich obsługę z metod komponentów ● Zdarzenia mogą być generowane na wiele sposobów, jak i można generować wiele typów zdarzeń (synchroniczne, asynchroniczne, czasowe, transakcyjne)
  • 28. Generowanie zdarzeń 1. public String register() { 2. // registration action 3. Events.instance().raiseEvent("registered"); 4. return "success"; 5. }
  • 29. Generowanie zdarzeń 1. @In private Events events; 2. 3. public String register() { 4. // registration action 5. entityManager.persist(newUser); 6. events.raiseTransactionSuccessEvent( 7. "registered", newUser); 8. return "success"; 9. }
  • 30. Generowanie zdarzeń 1. @RaiseEvent("registered") 2. public String register() { 3. // registration action 4. return "success"; 5. }
  • 31. Generowanie zdarzeń 1. <page view-id="/register.xhtml"> 2. <navigation 3. from-action="#{userManager.register}"> 5. <rule if-outcome="success"> 6. <raise-event type="registered" /> 7. <redirect 8. view-id="/registered.xhtml" /> 9. </rule> 10. </navigation> 11. </page>
  • 32. Obserwowanie zdarzeń 1. @Name("registrationObserver") 2. public class RegistrationObserver { 3. @Logger private Log logger; 4. 5. @Observer(value="registered", create=true) 6. public void onRegisteredEvent(User newUser) { 7. logger.info("Registered new user: " 8. + newUser.getUsername()); 9. } 10. 11. }
  • 33. Obserwowanie zdarzeń 1. <event type="registered"> 2. <action 3. execute= 4. "#{registrationObserver.onRegisterEvent(newUser)}" 5. /> 6. </event>
  • 34. Wbudowane zdarzenia ● Inicjalizacja kontenera seamowego ● Przypisanie zmiennej kontekstowej (added, removed) ● Zdarzenia cyklu życia komponentów (created, destroyed) ● Zdarzenia związane z autentykacją ● Zdarzenia związane z transakcją ● i wiele innych...
  • 35. Metody fabrykujące
  • 36. Metody fabrukujące w Seam ● Seam posiada wbudowane wsparcie dla wzorca factory method ● Fabryka ma na celu dostarczenie konkretnych danych zamiast instancji komponentu ● Metody fabrykujące oznacza się adnotacją @Factory lub w deskryptorze komponentów ● Metody fabrykujące z założenia mają wypierać użycie „getterów”
  • 37. Metoda fabrykująca jest wykonywana tylko raz, kolejne wywołania zwracają utworzoną i umieszczoną w kontekście wcześniej wartość.
  • 38. Rezultat wywołania fabryki ● Rezultat metody fabrykującej może być przekazany na trzy sposoby: ● Przez zwrócenie wartości z metody ● Przez outjection (jako, że metoda fabrykująca znajduje się w komponencie to działa na nim bijection) ● Przez umieszczenie wartości bezpośrednio w kontekście
  • 39. Przykład metody fabrykujacej 1. @Name("currentUserFactory") 2. public void CurrentUserHome { 3. @In private EntityManager em; 4. 5. @In private Long currentUserId; 6. 7. @Factory("currentUser") 8. public User getCurrentUser() { 9. return em.find(User.class, currentUserId); 10. } 11. }
  • 40. Przykład metody fabrykujacej 1. @Name("currentUserFactory") 2. public void CurrentUserHome { 3. @In private EntityManager em; 4. 5. @In private Long currentUserId; 6. 7. @Out private User currentUser; 8. 9. @Factory("currentUser") 10. public User getCurrentUser() { 11. currentUser = 12. em.find(User.class, currentUserId); 13. } 14. }
  • 41. Unwrap
  • 42. Unwrap ● Seam pozwala dostarczać dane do kontekstu za pomocą metody oznaczonej adnotacją @Unwrap ● W odróżnieniu od metody fabrykującej taka metoda jest wywoływana za każdym razem, kiedy komponent pod konkretną nazwą jest żądany
  • 43. @Unwrap a @Factory ● Jest prawdziwym komponentem ● Można konfigurować w components.xml ● Można używać adnotacji @Create i @Destroy ● Metoda oznaczona @Unwrap jest wywoływana zawsze ● Komponent może przechowywać stan i obserwować zdarzenia
  • 44. Metody oznaczone @Unwrap można używać jako swoisty alias.
  • 45. @Unwrap w akcji 1. @Name("org.jboss.seam.faces.facesContext") 2. @Scope(ScopeType.APPLICATION) 3. public class FacesContext { 4. @Unwrap public FacesContext getContext() { 5. return FacesContext.getCurrentInstance(); 6. } 7. }
  • 46. Method interceptors
  • 47. Interceptory w Seam ● Seam rozszerza funkcjonalność interceptorów z EJB ● Przenosi ją ze świata Java EE to świata POJO ● Pozwala w deklaratywny sposób dodawać logikę AOP
  • 48. Definiowanie interceptora 1. @AroundInvoke 2. public Object methodName(InvocationContext ctx) 3. throws Exception { 4. // interceptor logic... 5. return ctx.proceed(); 6. }
  • 49. Definiowanie interceptora 1. @Interceptor(stateless = true, 2. type = InterceptorType.CLIENT 3. public class StatelessInterceptor { 4. 5. @AroundInvoke 6. public Object methodName(InvocationContext ctx) 7. throws Exception { 8. // interceptor logic... 9. return ctx.proceed(); 10. } 11. 12. }
  • 50. Cechy interceptora w Seam ● Interceptor może być stateful-owy lub stateless- owy ● Interceptory mogą być przypisywane do komponentów zarówno po stronie serwera jak i klienta ● Interceptory mogą być przypisywane do klas deklaratywnie (stereotypes)
  • 51. Przypisywanie interceptorów ● @Interceptors
  • 52. Przypisywanie interceptorów ● @Interceptors ● W Seamie, w odróżnieniu od EJB, adnotacja @Interceptors nie jest nakładana na klasy komponentów, które chcemy interceptować ● Adnotacja ta to meta adnotacja którą nakłada się na inne adnotacje
  • 53. Przypisywanie interceptorów 1. @Target(TYPE) 2. @Retention(RUNTIME) 3. @Interceptors(CurrentUserAccessInterceptor.class) 4. public @interface VerifyCurrentUserAccess {} 5. 6. @Name("offerAddAction") 7. @VerifyCurrentUserAccess 8. public class OfferAddAction { }
  • 54. Model kontekstowy w Seam
  • 55. Konteksty w Java Servlet API ● Request ● Session ● Application
  • 56. Konteksty w Seam ● Event (request) ● Page ● Conversation ● Session ● Application ● Business process
  • 57. Konteksty w Seam Przeglądarka Strona 1 Strona 1 Strona 2 Strona 3 event event event event page page page conversation conversation session
  • 58. Konwersacja
  • 59. Konwersacja w Seam ● Pozwala przechowywać stan komponentów pomiędzy kolejnymi żądaniami (nawet w przypadku występowania przekierowań) ● Jest bardziej ziarnista niż kontekst sesji ● W deklaratywny sposób można kontrolować zakresy konwersacji (oraz jej propagacje) ● Na czas konwersacji Seam rozpina transakcje (utrzymywana jest sesja połączenia z bazą danych)
  • 60. Konwersacja w Seam została pomyślana jako kontekst, który przechowuje stan komponentów w ramach konkretnego przypadku użycia.
  • 61. A czemu nie w sesji? ● Sesja jest zbyt długa i przechowywanie danych w tym kontekście może prowadzić do wycieków pamięci ● Sesja jest dzielona pomiędzy karty przeglądarki ● Sesja nie posiada żadnych mechanizmów obronnych przed współbieżnym dostępem do danych ● Błędy występujące przez nieprawidłowe wykorzystywanie kontekstu sesji mogą być trudne do reprodukcji w środowisku testowym
  • 62. Mimo wszystko rozwiązanie leży w... sesji. Trzeba ją tylko odpowiednio podzielić i zarządzać.
  • 63. Konwersacja to wydzielony segment sesji cid = 1 cid = 2 cid = 3 cid = 4 Sesja HTTP
  • 64. Seam zarządza konwersacją ● Każda konwersacja posiada określony czas trwania (timeout) ● Każda konwersacja toczy się w izolacji (nie trzeba się przejmować synchronizacją)
  • 65. Wymagania konwersacji ● Komponenty muszą implementować interfejs java.io.Serializable ● Czas trwania sesji musi być dłuższy niż czas trwania konwersacji
  • 66. Stany konwersacji ● Tymczasowa (temporary conversation) ● Długa (long-running conversation) ● Zagnieżdżona (nested conversation)
  • 67. Stany konwersacji ● Tymczasowa (temporary conversation) ● Długa (long-running conversation) ● Zagnieżdżona (nested conversation)
  • 68. Przejścia stanów konwersacji brak konwersacji kontynuacja konwersacji begin Temporary Long-running end koniec żądania sesja lub konwersacja wygasła Zniszczona Zniszczona
  • 69. Stany długiej konwersacji Long-running resumed concurrent conversation resumed begin resumed Foreground Background end session timeout conversation or session timeout Zniszczona
  • 70. Definiowanie zakresów długiej konwersacji
  • 71. Za pomocą adnotacji 1. @Name("bookingAction") 2. @Restrict("#{s:hasRole('Customer')}") 3. public class BookingAction { 4. 5. @Begin(join = true) 6. public void fetchRooms() { 7. // fetching rooms... 8. } 9. 10. @End(beforeRedirect = true) 11. public void confirm() { 12. // confirm booking... 13. } 14. 15. @End(beforeRedirect = true) 16. public void cancel() { 17. // cancel booking... 18. } 19. 20. }
  • 72. Za pomocą adnotacji 1. @Name("roomsFactory") 2. public void RoomsFactory { 3. @Begin(join = true) 4. public void fetchRooms() { 5. // fetching rooms... 6. } 7. } 8. 9. @Name("bookingAction") 10. public void BookingAction { 11. @End(beforeRedirect = true) 12. public void confirm() { 13. // confirmation action... 14. } 15. }
  • 73. W deskryptorze strony 1. <page view-id="/booking.xhtml"> 2. <begin-conversation join="true" /> 3. </page>
  • 74. W definicjach nawigacji 1. <page view-id="/booking.xhtml"> 2. <navigation 3. from-action="#{roomsFactory.fetchRooms}"> 4. <begin-conversation join="true" /> 5. </navigation> 6. 7. <navigation from-action="#{bookingAction.confirm}"> 8. <end-conversation before-redirect="true" /> 9. </navigation> 10. </page>
  • 75. Za pomocą komponentów JSF 1. <s:link view-id="/booking.xhtml" propagation="begin" /> 2. 3. <s:button action="#{bookingAction.confirm}" 4. propagation="end" /> 5. 6. <h:commandButton action="#{bookingAction.confirm}"> 7. <s:conversationPropagation type="end" /> 8. </h:commandButton>
  • 76. Zaawansowane zarządzanie stronami w Seam
  • 77. Cykl JSF JSF Servlet Render Restore Response View Invoke Apply Request Application Values Update Model Process Values Validations
  • 78. Cykl JSF (initial request) Przeglądarka JSF Servlet Render Restore Response View Invoke Apply Request Application Values Update Model Process Values Validations
  • 79. Cykl JSF (postback) Przeglądarka JSF Servlet Render Restore Response View Invoke Apply Request Application Values Update Model Process Values Validations
  • 80. Nawigacja w JSF 1. <navigation-rule> 2. <from-view-id>/login.xhtml</from-view-id> 3. <navigation-case> 4. <from-action> 5. #{authenticator.login} 6. </from-action> 7. <from-outcome>loggedIn</from-outcome> 8. <to-view-id>/home.xhtml</to-view-id> 9. <redirect/> 10. </navigation-case> 11. </navigation-rule>
  • 81. Problemy z JSF ● Skrócony cykl JSF ● Służy jako dostawca strony ● Zakłada, że nie potrzeba wykonywania żadnej logiki przed wyrenderowaniem strony ● Zakłada, że użytkownik posiada uprawnienia do żądanego zasobu ● Zorientowanie na żądania typu POST ● Mało rozwinięte reguły nawigacji ● Brak możliwości wykorzystania EL w regułach
  • 82. Seam page descriptor
  • 83. Do czego służy deskryptor strony ● Definiowania reguł nawigacji ● Generowania komunikatów (FacesMessages) ● Mapowania parametrów URL ● Dodawania parametrów URL (dla przekierowań) ● Uruchamiania akcji zanim widok zostanie wyrenderowany
  • 84. Do czego służy deskryptor strony cd... ● Sprawdzania reguł bezpieczeństwa ● Kontrolowania zakresów konwersacji ● Kontrolowania zakresów page flow ● Kontrolowania zakresów procesów biznesowych i zadań ● Wywoływanie eventów ● Obsługa wyjątków
  • 85. Deskryptor jest świadomy kontekstu aplikacji
  • 86. Inteligentna nawigacja w Seam ● Pozwala użyć dowolnej wartości (dostępnej za pomocą EL) do definiowania przekierowań ● Reguły nawigacji są warunkowe ● Definiuje jak powinna być propagowana konwersacja, czy proces biznesowy ● Pozwala dodawać komunikaty JSF przed wyrenderowaniem strony bądź przekierowaniem ● Pozwala dodawać parametry URL ● Pozwala wywoływać eventy
  • 87. Definiowanie nawigacji 1. <page view-id="/login.xhtml" scheme="https"> 2. <navigation> 3. <rule if="#{identity.loggedIn}"> 4. <redirect view-id="/home.xhtml" /> 5. </rule> 6. </navigation> 7. </page>
  • 88. Definiowanie nawigacji 1. <page view-id="/offer/add.xhtml" login-required="true"> 2. <navigation from-action="#{offerManager.addOffer}"> 3. 4. <rule if-outcome="offerAdded" 5. if="#{offerManager.addNext}"> 1 6. <redirect view-id="/offer/add.xhtml" /> 7. </rule> 8. 9. <rule if-outcome="offerAdded"> 10. <redirect view-id="/offer/list.xhtml"> 11. <param name="userId" 2 12. value="#{currentUserId}" /> 13. </redirect> 14. </rule> 15. 16. </navigation> 17. </page>
  • 89. Definiowanie nawigacji 1. <page view-id="*"> 2. <navigation from-action="#{identity.logout}"> 3. <end-conversation before-redirect="true" /> 1 4. <redirect view-id="/home.xhtml" /> 5. </navigation> 6. 7. <navigation 8. from-action="#{quickSearchAction.performSearch}"> 2 9. <redirect view-id="/offers/index.xhtml" /> 10. </navigation> 11. 12. <navigation> 13. <rule if-outcome="accessDenied"> 14. <redirect view-id="/denied.xhtml" /> 3 15. </rule> 16. </navigation> 17. </page>
  • 90. Definiowanie nawigacji 1. <pages login-view-id="/login.xhtml" 2. no-conversation-view-id="/home.xhtml"> 3. 4. <exception 5. class="org.jboss.seam.ConcurrentRequestTimeoutException"> 6. <http-error error-code="503" /> 1 7. </exception> 8. 9. <exception class="org.jboss.seam.security.AuthorizationException"> 10. <redirect view-id="/denied.xhtml" /> 2 11. </exception> 12. 13. <exception class="javax.persistence.OptimisticLockException"> 14. <end-conversation /> 3 15. <redirect view-id="/error.xhtml" /> 16. </exception> 17. 18. </pages>
  • 91. Definiowanie nawigacji 1. public String goToHome() { 2. return "/home.xhtml"; 3. }
  • 92. Mapowanie parametrów strony ● Seam pozwala na ustawianie wartości pól komponentu w skróconym cyklu JSF (JSF pozwala tylko w postbacku) ● Parametrem strony może być wartość z formularza (POST) jak i parametr URL (GET) ● Parametry mogą być przypisane do dowolnych pól każdego komponentu Seam (osiągalnego za pomocą EL)
  • 93. Mapowanie parametrów URL http://localhost:8080/profile.seam?userId=1 1. <page view-id="/profile.xhtml" login-required="true"> 2. <param name="userId" value="#{userManager.userId}" /> 3. </page>
  • 94. Właściwości parametrów ● Do każdego parametru można zdefiniować JSF-owe walidatory i konwertery takie jak definiuje się dla normalnego postbackowego cyklu ● Można zdefiniować, że parametr jest wymagany bądź opcjonalny ● Parametrów nie trzeba przypisywać do konkretnych pól komponentu, takie parametry mogą po prostu przechowywać dane między kolejnymi żądaniami
  • 95. URL rewrite ● Seam pozwala na przepisywanie adresów URL zgodnie z szablonem zdefiniowanym w deskryptorze strony ● Seam przepisuje URL-e zarówno żądań przychodzących jak i odpowiedzi aplikacji
  • 96. URL rewrite http://localhost:8080/users/1/profile 1. <page view-id="/profile.xhtml" login-required="true"> 2. <rewrite pattern="/users/{userId}/profile" /> 3. <param name="userId" value="#{userManager.userId}" /> 4. </page>
  • 97. Komponenty przepisujące URL-e ● <s:link> (<h:commandLink>) ● <s:button> (<h:commandButton>)
  • 98. Komponenty przepisujące URL-e ● <s:link> (<h:commandLink>) ● <s:button> (<h:commandButton>) ● <s:form>
  • 99. Akcje strony ● Seam pozwala na wykonywanie akcji dla danej strony (view-id) tuż przed jej wyrenderowaniem (nawet w skróconym przebiegu JSF) ● Są to standardowe akcje dla których można definiować reguły nawigacji (wywoływane jednak przed szóstą fazą JSF a nie w piątej!) ● Akcje te mogą służyć do zainicjalizowania widoku – załadowania danych potrzebnych do wyrenderowania strony ● Pozwala to na implementacje RESTful-owych URL-i
  • 100. Akcje strony http://localhost:8080/users/1/profile 1. <page view-id="/profile.xhtml" login-required="true"> 2. <rewrite pattern="/users/{userId}/profile" /> 3. <param name="userId" value="#{userManager.userId}" /> 4. <action execute="#{userManager.fetchUser}" /> 5. </page>
  • 101. Czego Seam nie poprawia ● Komunikatów JSF ● Walidacja i konwersja dotyczą tylko pojedynczych wartości, nie jest łatwo zaimplementować tych operacji na zależnych polach (i trzeba przenosić ten proces do piątej fazy) ● Wstrzykiwanie zależności do walidatorów i konwerterów (można je pobierać za pomocą metod statycznych)
  • 102. Czego nie omówiono w prezentacji? ● Deskryptor komponentów components.xml ● Seam-gen ● WebBeans (JSR-299) ● Workspace i pageflow w kontekście konwersacji ● Wsparcia Seam dla warstwy widoku ● Komponenty seamowe ● Wsparcie dla AJAX ● Testowanie integracyjne ● Symulacja cyklu JSF ● Kontekstu business process
  • 103. Czy Seam daje radę?
  • 104. Do poduszki
  • 105. Q&A
  • 106. Dziękuję za uwagę