Impressive.
I'd kill to work with people with this kind of passion and determination.
"We're not asking their permission."
"We don't accept things the way they are and we don't stop innovating. (...) So you can either get on board or get the fuck out."
"Where are we going?" "Recruiting."
Kohomologia
sobota, 31 sierpnia 2013
poniedziałek, 13 maja 2013
You won't understand
The need to fight rising in your chest with every breath. There's a goal before you and nothing else exists any more. Sweet smell of lilac filling the air. Cool, soft wind gently caressing your skin. The need to go. Now. Faster. Everything that could stop you seems distant and irrevelant. Your breath growing both deep and rapid. The need to fight almost filling your eyes with tears. One of the most beautiful feelings you can experience.
niedziela, 12 maja 2013
poniedziałek, 1 kwietnia 2013
Decisions, decision, Dan North
> Ręczne wykonywanie czynności, które można zautomatyzować, nie zawsze jest bezsensowne.
Uczymy się. Dostrzegamy, co zmienić, co można poprawić, co już nie ma sensu. Znając coś dobrze, szybko zauważymy niechciane zmiany. Kiedy automatyzować? Kiedy poznamy coś na tyle dobrze, że zaczniemy się nudzić.
> Spike and stabilize
Coś dla fanów TDD, którzy zapomnieli że można inaczej. TDD nie jest dobre do eksperymentowania. Eksperymentując, gdy jeszcze nie jesteśmy pewni, co i jak chcemy osiągnąć - po prostu piszmy i próbujmy. Jak już zrozumiemy, co i jak chcemy zrobić, można zacząć pisać testy. Tzn. kilka testów - trochę kodu, kilka testów - trochę kodu. Nie piszemy wpierw wszystkich testów, a później całego kodu. It's evil.
X: Writing tests at the begining *is* better, even with experimenting! How else do you fire it to see if it works?
D: I write main method.
X: But writing tests is faster!
D: Well, I'm pretty fast at writing main...
D: It's not always easy to get audience to join the discussion. When I was in Finland and tried the same thing, a guy came to me and said: 'Listen: we pay - you talk.'
> Nie spieszmy się z podziałem kodu na komponenty. Na wszystko przyjdzie odpowiedni moment. Na samym początku tylko utrudni to pracę. '10 for style, 0 for value.'
> Używamy obiektów, by pisać w sposób funkcyjny.
Co chcemy zrobić? Weź dane, przekształć, prześlij.
Co robimy? Weź dane... Czekaj, czekaj, nie jestem jeszcze gotowy. Konstruktor, zależności... o, ta jeszcze nie istnieje - kolejny konstruktor, pakujemy dane w dto, przesyłamy, rozpakowujemy, przetwarzamy, pakujemy ponownie, wysyłamy.
> Naucz się języka funkcyjnego nawet, jeśli nie zamierzasz go używać. Nauczysz się myśleć w inny sposób.
> Actors/CSP
D: Who understands thread based concurrency in Java? I guess we have Doug Lea here. If anyone alse has risen a hand, I won't believe him. It's really hard.
> Don'tRepeatYourself/Decoupled
'Sometimes just copy and paste. Let it mutate. You reuse idea, not code.' Dlaczego? By ograniczyć zależności. Coupling is evil.
> Podsumowując: 'Know what you're trading off and you can make decisions.'
Uczymy się. Dostrzegamy, co zmienić, co można poprawić, co już nie ma sensu. Znając coś dobrze, szybko zauważymy niechciane zmiany. Kiedy automatyzować? Kiedy poznamy coś na tyle dobrze, że zaczniemy się nudzić.
> Spike and stabilize
Coś dla fanów TDD, którzy zapomnieli że można inaczej. TDD nie jest dobre do eksperymentowania. Eksperymentując, gdy jeszcze nie jesteśmy pewni, co i jak chcemy osiągnąć - po prostu piszmy i próbujmy. Jak już zrozumiemy, co i jak chcemy zrobić, można zacząć pisać testy. Tzn. kilka testów - trochę kodu, kilka testów - trochę kodu. Nie piszemy wpierw wszystkich testów, a później całego kodu. It's evil.
X: Writing tests at the begining *is* better, even with experimenting! How else do you fire it to see if it works?
D: I write main method.
X: But writing tests is faster!
D: Well, I'm pretty fast at writing main...
D: It's not always easy to get audience to join the discussion. When I was in Finland and tried the same thing, a guy came to me and said: 'Listen: we pay - you talk.'
> Nie spieszmy się z podziałem kodu na komponenty. Na wszystko przyjdzie odpowiedni moment. Na samym początku tylko utrudni to pracę. '10 for style, 0 for value.'
> Używamy obiektów, by pisać w sposób funkcyjny.
Co chcemy zrobić? Weź dane, przekształć, prześlij.
Co robimy? Weź dane... Czekaj, czekaj, nie jestem jeszcze gotowy. Konstruktor, zależności... o, ta jeszcze nie istnieje - kolejny konstruktor, pakujemy dane w dto, przesyłamy, rozpakowujemy, przetwarzamy, pakujemy ponownie, wysyłamy.
> Naucz się języka funkcyjnego nawet, jeśli nie zamierzasz go używać. Nauczysz się myśleć w inny sposób.
> Actors/CSP
D: Who understands thread based concurrency in Java? I guess we have Doug Lea here. If anyone alse has risen a hand, I won't believe him. It's really hard.
> Don'tRepeatYourself/Decoupled
'Sometimes just copy and paste. Let it mutate. You reuse idea, not code.' Dlaczego? By ograniczyć zależności. Coupling is evil.
> Podsumowując: 'Know what you're trading off and you can make decisions.'
niedziela, 10 marca 2013
Zjedz tę żabę, Brian Tracy
A zatem pierwsza reguła połykania żab brzmi: Jeśli musisz połknąć dwie żaby, zacznij od tej, która budzi w tobie większą odrazę.
Druga reguła połykania żab brzmi: Jeśli musisz połknąć żywą żabę, nie warto siedzieć i przyglądać się jej zbyt długo.
Tytuł tej książki natychmiast zwrócił moją uwagę. Za każdym razem gdy wychodzę poza swoją strefę komfortu, czuję, jakbym połykała żywą, obślizgłą, podskakującą w gardle żabę. I muszę przyznać, że wyobrażenie sobie tej żaby pomaga.
Zawartość książki jest przewidywalna: Pytaj i naśladuj ludzi, którym się udało. Wyobraź sobie, że osiągnąłeś swój cel. Zidentyfikuj najważniejsze zadania i skup się na nich. Twórz sztuczne terminy i ich dotrzymuj. Myśl z ołówkiem w ręku. Twórz listy zadań i celów.
Wszystko prawdziwe, wszystko skuteczne, wszystko powtarzane po wielokroć w każdej podobnej książce.
poniedziałek, 4 marca 2013
Here is a ClassLoader. He is a little bit shy.
Jevgeni Kabanov, Do You Really Get ClassLoaders? (JavaOne Rock Star 2012)
Jevgeni Kabanov jest założycielem ZeroTurnaround - firmy odpowiedzialnej za takie produkty jak JRebel i LiveRebel. Prezentacja jest lekka i przystępna. Najistotniejsze informacje:
1. Każdy ClassLoader ma rodzica (ClassLoader WAR ClassLoader < EAR ClassLoader < Container ClassLoader). ClassLoader wpierw zapyta rodzica, czy ten nie może załadować klasy, a dopiero później spróbuje sam to zrobić. Za wyjątkiem ClassLoaderów WAR-a - te wpierw spróbują załadować klasę, a dopiero później przekażą zadanie rodzicowi.
2. Diagnozując problem z ClassLoaderami (ClassNotFoundException, NoClassDefFoundError, NoSuchMethodError, AbstractMethodError, ClassCastException, IllegalAccessError, LinkageError, ...) warto wyświetlić wyniki poniższych wywołań: Można też użyć argumentu jvm -verbose:class.
3. Obiekt posiada referencję do klasy, klasa posiada referencję do ClassLoadera, ClassLoader posiada referencję do załadowanych przez siebie klas, klasy posiadają referencje do swoich statycznych pól.
Prezentacja przedstawia, jak może to doprowadzić do wycieku pamięci przy redeployu. Tworzymy nowy ClassLoader, ładujemy klasy od nowa, kopiujemy jakiś stan, przy czym jedna z kopii zachowuje referencję do swojego oryginału - i w pamięci pozostają stare klasy, przykładowo z pokaźnymi statycznymi mapami robiącymi za cache.
Co za tym idzie - na produkcji robimy restarty a nie redeploye.
Jevgeni Kabanov jest założycielem ZeroTurnaround - firmy odpowiedzialnej za takie produkty jak JRebel i LiveRebel. Prezentacja jest lekka i przystępna. Najistotniejsze informacje:
1. Każdy ClassLoader ma rodzica (ClassLoader WAR ClassLoader < EAR ClassLoader < Container ClassLoader). ClassLoader wpierw zapyta rodzica, czy ten nie może załadować klasy, a dopiero później spróbuje sam to zrobić. Za wyjątkiem ClassLoaderów WAR-a - te wpierw spróbują załadować klasę, a dopiero później przekażą zadanie rodzicowi.
2. Diagnozując problem z ClassLoaderami (ClassNotFoundException, NoClassDefFoundError, NoSuchMethodError, AbstractMethodError, ClassCastException, IllegalAccessError, LinkageError, ...) warto wyświetlić wyniki poniższych wywołań: Można też użyć argumentu jvm -verbose:class.
3. Obiekt posiada referencję do klasy, klasa posiada referencję do ClassLoadera, ClassLoader posiada referencję do załadowanych przez siebie klas, klasy posiadają referencje do swoich statycznych pól.
Prezentacja przedstawia, jak może to doprowadzić do wycieku pamięci przy redeployu. Tworzymy nowy ClassLoader, ładujemy klasy od nowa, kopiujemy jakiś stan, przy czym jedna z kopii zachowuje referencję do swojego oryginału - i w pamięci pozostają stare klasy, przykładowo z pokaźnymi statycznymi mapami robiącymi za cache.
Co za tym idzie - na produkcji robimy restarty a nie redeploye.
wtorek, 26 lutego 2013
OutOfMemory Error
Opcje wymuszające utworzenie heap dumpa (.hprof) po wystąpieniu OutOfMemory:
- XX:+HeapDumpOnOutOfMemoryError
- XX:HeapDumpPath=[desired .hprof file location]
Plik .hprof można wygenerować na żądanie, programem jmap:
jmap -dump:file=[file name] [pid]
Plik przeanalizujemy np. Eclipse Memory Analyser-em (dostępnym jako wtyczka do eclipse oraz w wersji standalone).
Do podglądu działającej aplikacji można użyć narzędzia jvisualvm (lub jconsole), wchodzącego w skład JDK. Połączymy się zarówno z lokalnym procesem, jak i wirtualną maszyna działającą na innym serwerze (z pewnymi ograniczeniami).
Aby umożliwić zdalne połączenia do tomcata, dodajemy opcje:
-Dcom.sun.management.jmxremote.port=[np. 8086]
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
- XX:+HeapDumpOnOutOfMemoryError
- XX:HeapDumpPath=[desired .hprof file location]
Plik .hprof można wygenerować na żądanie, programem jmap:
jmap -dump:file=[file name] [pid]
Plik przeanalizujemy np. Eclipse Memory Analyser-em (dostępnym jako wtyczka do eclipse oraz w wersji standalone).
Do podglądu działającej aplikacji można użyć narzędzia jvisualvm (lub jconsole), wchodzącego w skład JDK. Połączymy się zarówno z lokalnym procesem, jak i wirtualną maszyna działającą na innym serwerze (z pewnymi ograniczeniami).
Aby umożliwić zdalne połączenia do tomcata, dodajemy opcje:
-Dcom.sun.management.jmxremote.port=[np. 8086]
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
GC overhead limit exceeded
Błąd "java.lang.OutOfMemoryError : GC overhead limit exceeded" jest wyrzucany w sytuacji, gdy większość czasu (98%) poświęcana jest na odzyskiwanie pamięci, przy czym udaje się uzyskać mniej niż 2% sterty. Co jest w pełni uzasadnione - gdy zużycie dostępnej pamięci niebezpiecznie zbliża się do 100% i niewiele z tego daje się odzyskać - aplikacja potrafi dogorywać w nieskończoność.
Parametrami (ilością czasu oraz odzyskanej pamięci) można sterować poprzez opcje:
-XX:GCTimeLimit=[time limit]
-XX:GCHeapFreeLimit=[space limit]
Funkcjonalność można wyłączyć, dodając: -XX:-UseGCOverheadLimit.
Źródła:
GC Tuning (Excessive GC Time and OutOfMemoryError)
GC Ergonomics
Parametrami (ilością czasu oraz odzyskanej pamięci) można sterować poprzez opcje:
-XX:GCTimeLimit=[time limit]
-XX:GCHeapFreeLimit=[space limit]
Funkcjonalność można wyłączyć, dodając: -XX:-UseGCOverheadLimit.
Źródła:
GC Tuning (Excessive GC Time and OutOfMemoryError)
GC Ergonomics
niedziela, 6 stycznia 2013
Tricky is, handling dates in Java. Joda Time, you shall use!
Java Date API jest dalekie od ideału. Przede wszystkim brakuje w nim metod dla podstawowych operacji, a napisanie ich wymaga absurdalnej ilości kodu i ostrożności.
Właśnie utworzyliśmy datę reprezentującą 6.02.3913. Miesiące liczymy od zera. A lata od 1900.
Tym razem dostaniemy 6.02.2013. Lepiej, choć wciąż nieidealnie.
Klasyczny przypadek - chcemy porównać dwie daty, z dokładnością do dni. Czas wyzerujemy w następujący sposób:
Wystarczy powtórzyć dla drugiej daty i możemy porównywać.
Inny klasyczny przypadek - chcemy obliczyć ilość dni między dwoma datami. Jedno z prostszych rozwiązań wygląda następująco:
Alternatywy?
Apache Commons Lang - DateUtils
Date4J
Malutka biblioteka, obejmuje zaledwie kilka klas. Tutaj znajdziemy krótkie porównanie z Joda Time.
Joda Time
Chyba najpopularniejsza, obszerna biblioteka do obsługi dat.
Właśnie utworzyliśmy datę reprezentującą 6.02.3913. Miesiące liczymy od zera. A lata od 1900.
Tym razem dostaniemy 6.02.2013. Lepiej, choć wciąż nieidealnie.
Klasyczny przypadek - chcemy porównać dwie daty, z dokładnością do dni. Czas wyzerujemy w następujący sposób:
Wystarczy powtórzyć dla drugiej daty i możemy porównywać.
Inny klasyczny przypadek - chcemy obliczyć ilość dni między dwoma datami. Jedno z prostszych rozwiązań wygląda następująco:
Alternatywy?
Apache Commons Lang - DateUtils
Date4J
Malutka biblioteka, obejmuje zaledwie kilka klas. Tutaj znajdziemy krótkie porównanie z Joda Time.
Joda Time
Chyba najpopularniejsza, obszerna biblioteka do obsługi dat.
sobota, 5 stycznia 2013
OCPBCD / SCBCD 5 / 1Z0-860 Study Notes
PersistenceContext
PC - PersistenceContext
EM - EntityManager
EMF - EntityManagerFactory
PC zarządzany przez aplikację ma zasięg rozszerzony. PC zarządzany przez kontener może mieć zasięg rozszerzony (tylko dla SFSB) lub zasięg transakcji.
PC rozpoczyna się:
- z chwilą, gdy EM zostanie wywołany w zasięgu aktywnej transakcji JTA (dla EM zarządzanego przez kontener i PC o zasięgu transakcji)
- gdy EM zostanie utworzony (dla EM zarządzanego przez aplikację, PC wówczas zawsze ma zasięg rozszerzony)
- gdy SFSB zostanie utworzony a PC do niego przypięty (dla EM zarządzanego przez kontener i PC o zasięgu rozszerzonym - który może występować tylko w ramach statefula)
Aby zakończyć PC, wywołujemy EM.close(). Nie można tego zrobić na EM zarządzanym przez kontener. Po wywołaniu tej metody, wszystkie metody EM poza isOpen() i getTransaction() wyrzucą IllegalStateException.
PC zarządzany przez kontener musi być JTA. Zarządzany przez aplikację może być JTA lub RESOURCE_LOCAL. (Domyślna wartość transaction-type dla środowisk Java EE to JTA, a dla Java SE - RESOURCE_LOCAL).
Jeżeli wstrzykujemy EM do beana (tzn. PC jest zarządzany przez kontener), to nie będziemy używać EntityTransaction, wykorzystywanego przy RESOURCE_LOCAL.
Jeżeli EM tworzymy ręcznie poprzez EMF.createEntityManager (tzn. PC jest zarządzany przez aplikację), to możemy używać zarówno EntityTransaction jak i JTA.
Jeżeli używamy JTA i utworzyliśmy EM poza zasięgiem transakcji, przed wykonaniem operacji należy wywołać em.joinTransaction().
Podsumowując: PC dzielimy na ContainerManaged/AppManaged, JTA/RESOURCE_LOCAL, TxScoped/Extended.
Domyślny FlushMode (Auto) zapewnia, że przed wykonaniem zapytania zmiany, które mogą go dotyczyć zostaną zrzucone do bazy. Jednak flush nie sprawi, że zmiany z niezatwierdzonej transakcji będą widoczne dla innych transakcji. Nadużywanie flusha ma wpływ na wydajność.
Encje mogą być w jednym z czterech stanów: new, managed, detached, removed. Wszystkie poza new mają persistent identity. Managed i removed są 'associated with PC'.
Remove i lock wymagają non-detached entity. Refresh wymaga managed entity. Merge oczekuje non-removed entity. Persist wymaga po prostu entity (choć wywołana na detached entity może skutkować wyrzuceniem EntityExistsException lub innego PersistenceException). Jak nie dostaną czego chcą, wyplują IllegalArgumentException.
Persist wywołane na removed entity zmieni ją w managed entity.
Persistence.xml jest obowiązkowy. Można w nim zdefiniować wiele PU. Jeden PU odpowiada jednemu datasource. Każdy PU musi mieć nazwę. Jeżeli mamy wiecej niż jeden PU, tworząc EM lub EMF należy podać nazwę konkretnego PU. Encje i klasy embedded muszą być (jawnie lub nie) uwzględnione w persistence.xml jako klasy zarządzane, by były uwzględnione w PU.
Dzięki propagacji PC nie trzeba przekazywać referencji do EM między beanami. Propagacja kontekstu dotyczy PC zarządzanego przez kontener. PC propagowany jest razem z transakcją (tzn. jeżeli transakcja nie jest propagowana, to PC również nie).
JPQL i operacje na bazie
Operacje modyfikujące dane w bazie wymagają transakcji (inaczej wyplują TransactionRequiredException), operacje odczytujące dane nie. Przykładowo update, flush, persist wymagają transakcji, natomiast clear i find już nie. Encje wyciągnięte poza transakcją będą detached (dla PC o zasięgu transakcji) lub managed (dla PC o zasięgu rozszerzonym). Jeżeli find zdarzy się splunąć wyjątkiem to najprawdopodobniej klasa klucza głównego się nie zgadza.
Po wykonaniu executeUpdate załadowane encje, których zmiany dotyczą, nie zostaną odświeżone. Próba wywołania executeUpdate z zapytaniem typu SELECT spowoduje wyrzucenie IllegalStateException. Operacje masowe - DELETE, UPDATE w JPQL mogą się sypnąć na constraintach, rzucając PersistenceException.
Persist będzie kaskadowany przy Cascade.PERSIST i ALL. Remove przy REMOVE i ALL ale tylko dla relacji OneToOne i OneToMany (zachowanie dla pozostałych nie jest określone). Remove na nowej encji nie usunie jej z bazy (jeszcze jej tam nie ma) - ale jeżeli mamy cascade, to spowoduje usunięcie encji wskazywanych przez tę encję.
Zapytania JPQL można zdefiniować za pomocą adnotacji @NamedQuery lub elementu named-query w xml-u. Zapytania sql-owe analogicznie - poprzez @NamedNativeQuery. Wynikiem zapytań mogą być encje, ale można też zdefiniować bardziej skomplikowane mapowania.
Zapytanie "SELECT k FROM Klasa k INNER JOIN k.uczniowie u" zwróci pojedyncze klasy, a nie po 30 sztuk każdej. Co innego, gdybyśmy dodali FETCH.
W zapytaniach można używać konstruktorów. Przykładowo: "SELECT NEW Integer(MAX(k.uczniowie)) FROM Klasa k".
Elementy uwzględnione w ORDER BY muszą występować w klauzuli SELECT i muszą być szeregowalne (tzn. liczby, stringi, znaki lub daty).
SIZE używamy w klauzuli WHERE, natomiast COUNT w klauzuli SELECT. Podzapytań używamy w klauzuli WHERE. ALL, ANY, SOME, EXISTS stosujemy do podzapytań. MEMBER OF stosujemy do kolekcji. MAX, AVG również do kolekcji.
Używając LIKE mamy do dyspozycji dwa wildcardy: _ zastępuje jeden znak, % dowolnie wiele znaków. BETWEEN jest dwustronnie inclusive.
Find() zwraca nulla, jeżeli nic nie znajdzie. GetRefence() wyrzuca EntityNotFoundException - ale getReference nie musi strzelać do bazy (wówczas wyjątek zostanie wyrzucony dopiero przy próbie dobrania się do pola encji).
Contains() zwróci true tylko dla managed entity - dla detached, removed i new zwróci false.
Encje
PP - PersistenceProvider
Encje umieszczamy w roocie PU lub w jarze znajdującym się w classpath PU.
Próba zapisu encji z istniejącym kluczem zakończy się rollbackiem.
Pole trwałe to takie, które nie jest transient ani @Transient. Pole trwałe o "złożonym" typie w encji nie musi być oznaczone jako @Lob, ale musi być serializowalne. (Dokładniej: musi być prymitywem, Stringiem, wrapperem, BigDecimal/Interger, Calendar, java.util/sql.Date, java.sql.Time/Timestamp, enumem, encją, kolekcją encji, klasą @Embeddable, byte[], Byte[], char[], Character[] albo Serializable.)
Określenie pola @Version sprawi, że PP użyje go do zapewnienia optimistic lockingu. @Version powinno być określone na głównej tabeli encji. Dopuszczalne typy: int, Integer, s/Short, l/Long, Timestamp.
@Basic można zawsze dać na polu, ale jest opcjonalna. Ma elementy fetch i optional.
Nazwę tabeli dla encji określamy poprzez @Table("TABLE_NAME") lub poprzez <entity ...> <table name="TABLE_NAME">. Nazw tabel nie nadpisujemy w persistence.xml - do tego służą pliki mapowań. Pliki mapowań to META-INF/orm.xml lub xml-e określone elementem mapping-file w persistence.xml. Domyślna nazwa tabeli przy złączeniach z użyciem JoinTable (gdy nie określono atrybutu name) to połączenie nazw tabel, oddzielonych podkreśleniem, przy czym pierwsza to owning side.
Klucz główny definiujemy w korzeniu hierarchii encji - czy to encja, czy mapped superclass.
Złożone klucze główne można zmapować na dwa sposoby:
- adnotacja @IdClass(SomePKClass.class) na poziomie encji + adnoracje @Id na polach encji odpowiadających polom z SomePKClass;
- adnotacja @EmbeddedId na polu o typie oznaczonym jako @Embeddable.
IdClass musi definiować equals i hashCode zgodne z porównywaniem encji po stronie bazy.
Strategię dziedziczenia określamy poprzez @Inheritance(strategy=[JOINED/SINGLE_TABLE/TABLE_PER_CLASS]). JOINED oznacza, że każda encja, również pośrednia, ma osobną tabelę. TABLE_PER_CLASS nie musi być wspierana w EJB 3.0.
@MappedSuperclass nie może występować w zapytaniach. Niezależnie od strategii, nie posiada osobnej tabeli w bazie. Może natomiast występować w dowolnym miejscu w hierarchii encji.
W relacjach dwustronnych owning side to strona posiadająca klucz obcy i jest to ta strona, po której nie ma mappedBy. W relacjach jednostronnych jedyna istniejąca strona jest owning side. W ManyToMany każda ze stron może być owning side. To operajce wykonywane na owning side mają znaczenie.
@OneToMany oznacza "jeden obiekt klasy, w której znajduje się ta adnotacja do wielu obiektów klasy zdefiniowanej przez pole (kolekcję), na którym się znajduje".
Definiując relacje, atrybut targetEntity jest wymagany jeżeli adnotujemy kolekcję bez generycznego zawężenia.
Gettery/settery dla encji używając dostępu opartego o te metody powinny być publiczne lub chronione. Encja musi mieć bezargumentowy konstruktor. Jeżeli ma być przekazywana przez interfejs zdalny, powinna być również Serializable.
Klucz główny może być prymitywem (ale nie typem numerycznym przybliżonym - double, float), wrapperem, Stringiem, java.sql.Date lub java.util.Date. Dla java.util.Date musi mieć temporal type ustawiony na DATE. (@Temporal musi być określony dla typów java.util.Date i java.util.Calendar.) Musi być serializowalny. Musi definiować equals i hashCode w sposób zgodny ze sposobem porównywania tych wartości w bazie.
Klasy abstrakcyjne mogą być encjami.
Typ dostępu (pola/akcesory) dotyczy całej konkretnej hierarchii encji.
Timery
Chcąc wykonać operację po określonym czasie, używamy Timerów - albo oznaczająć metodę jako @Timeout albo implementując interfejs TimedObject. Bean może mieć tylko jedną metodę timeout.
Callbacki
Callbacki mogą być prywatne, ale nie mogą być statyczne i muszą zwracać void.
Callbacki encji zdefiniowane w listenerach muszą przyjąć Object albo obiekt encji jako argument. Callbacki encji nie powinny wywoływać operacji na EntityManager ani Query, odwoływać się do innych encji ani modyfikować relacji.
Callbacki nie powinny pluć checked exception. Zdefiniowane w klasie, której dotyczą, w większości muszą być bezargumentowe. @PreDestroy w Statelessie wykonuje się w nieokreślonym kontekście transakcji i bezpieczeństwa.
@PostActivate, @PrePassivate - dobre miejsce by inicjować i niszczyć resourcy, które wymagają ręcznej obsługi. Z uwagi na timeouty, w @PreDestroy też warto zająć się niszczeniem resourców. Nieserializowalne pola powinny zostać znullowane w @PrePassivate (dokładniej - pola, które nie są Timerami, SessionContextem, referencjami do beanów, nie są serializowalne. Można pominąć też pola, które staną się "serializowalne" poprzez zastosowanie tych zasad do ich składowych.).
Obowiązki kontenera i restrykcje dla programisty EJB
Kontener musi zapewnić (choćby częściowo) API: JAX-WS, JavaMail, JNDI, JDBC, JAXB i sporo innych (RMI-IIOP, JAXP, Java IDL, EJB 3.0 + JPA, JTA, JMS, JAF, JAXR, JAX_RPC, SAAJ, Connector, Web Services, Web Services Metadata, Common Annotations, StAX).
Kontener nie musi zapewnić load-balancingu ani klastrowania. Nie musi też niczego gwarantować w przypadku awarii serwera.
EJB nie używają interfejsów graficznych. Nie dobierają się do plików za pomocą java.io. Nie ładują bibliotek natywnych. Nie tworzą SecurityManagerów ani Classloaderów. Nie słuchają na gnieździe, ale mogą być klientem gniazda. Nie zajmują się wątkami (w EJB 3.1 ograniczenie to nie dotyczy Singletona z współbieżnością zarządzaną przez beana). Nie zmieniają wartości pól statycznych (dlatego najlepiej od razu oznaczyć je jako final).
Nie używają obiektów związanych z bezpieczeństwem (Policy, Securyty, Provider, Signer, Identity). Nie dobierają się refleksją do elementów prywatnych. Nie używają AWT. Nie pobierają danych z klawiatury. Itd.
Integracja EJB 2.1/3.0
Adnotacja @Init pozwala określić metodę inicjalizującą w 3.0, odpowiadającą metodom createXXX w interfejsach domowych.
Aby wywołać 2.1 z 3.0 można wstrzyknąć referencję do HomeInterface za pomocą adnotacji @EJB, a następnie wywołać na tym obiekcie metodę create().
Aby wywołać 3.0 z 2.1 można użyć adnotacji @RemoteHome i @LocalHome.
Role
Role określone w specyfikacji to: Persistence Provider, Application Assembler, EJB Container Provider, Enterprise Bean Provider, System Administrator, EJB Server Provider, Deployer.
Admin przykładowo konfiguruje LDAP-a.
Deployer mapuje role na grupy użytkowników (wszystkie role - z @RolesAllowed, @DeclareRoles i z XML-a). Ale same role i referencje do ról określaja Bean Provider i Assembler, deployer ich nie zmienia.
Bean Provider i Assembler mogą określać atrybuty transakcji i kolejność interceptorów w deskryptorze wdrożenia.
EJB-JAR jest edytowany przez Bean Providera, Assemblera i Deployera. Jego format jest kontraktem między tą trójką.
Bezpieczeństwo
Metodę można oznaczyć jako unchecked - tzn. każdy ma do niej dostęp. Jeżeli poza elementem unchecked wymieniono również kilka ról, nadal każdy ma do niej dostęp.
@RunAs("SomeRole") na beanie sprawi, że metody wywoływane z jego metod wywołają się z rolą "SomeRole".
Jeżeli role-name w security-role-ref jest taka sama jak nazwa w security-role, element role-link nie jest potrzebny.
Metoda getCallerPrincipal nie zwróci nulla, tylko obiekt reprezentujący 'UNAUTHENTICATED identity'. Obiekt Principal nie zawiera informacji o rolach. Principal.getName zależy od security realm użytego do autentykacji.
Wyjątki
Wyjątki aplikacyjne definiujemy poprzez @ApplicationException. Nie mogą rozszerzać @RemoteException. Wyjątki aplikacyjne są propagowane bez zmian. Runtimy domyślnie są wyjątkami systemowymi. Wyjątki systemowe są opakowywane w EJBException lub w EJBTransactionRolledbackException (gdy metoda wykonywała się w transakcji klienta). Jeżeli bean nie może pozbierać się po checked exception, należy opakować go w EJBException. NoSuchEJBException, EJBException, EJBTransactionRolledbackException i EJBTransactionRequiredException to wyjatki systemowe.
PersistenceExceptions to Runtimy. NonUniqueResultEx (przy getSingleResult) i NoResultEx (wyrzucane przez getSingleResult) nie powodują rollbacka. Pozostałe to EntityExistsEx, EntityNotFoundEx, RollbackEx, OptimisticLockingEx, TransactionRequiredEx.
Wyjątki javax.ejb.CreateException, javax.ejb.RemoveException, javax.ejb.FinderException i ich podklasy to wyjątki aplikacyjne.
Adnotacje i zależności
Rejestrując referencje w ENC (na poziomie klasy) określamy jej nazwę i typ. Na poziomie pola nie jest to konieczne.
Do wstrzykiwania EntityManagerFactory służy @PersistenceUnit. Do wstrzyknięcia EntityManager służy @PersistenceContext.
Dostęp do UserTransaction można uzyskać z JNDI pod nazwą "java:comp/UserTransaction", przez metodę EJBContext.getUserTransaction lub poprzez wstrzyknięcie adnotacją @Resource.
W konstruktorze beana nie dobieramy się do innych beanów. W callbakach statelessa też nie. W callbackach statefula już można. W timeoucie też można.
XML jest zawsze istotniejszy od adnotacji i zazwyczaj je nadpisuje. Może je uzupełniać. W XML-u nie możemy jednak nadpisać wzsystkiego - np. typu beana.
@EJB i @Resource można umieścić na poziomie klasy (dodając tym samym wpisy w ENC beana), pola (wstrzykując zależność) lub metody (jw., na setterze). @RolesAllowed można umieścić na poziomie klasy lub metody (nie przyznajemy uprawnień do pól).
Referencje do destynacji można wstrzyknąć adnotacją @Resource, np. @Resource(mappedName="topic/MyTopic") private javax.jms.Topic myTopic;. Można też to zrobić na poziomie klasy: @Stateless @Resource(name="jms/MyTopic", type=javax.jms.Topic, lookup="topic/MyTopic").
Wstrzykiwanie zależności dostępne jest dla EJB, Interceptorów, Servletów, Filtrów, ServletListenerów, JSF ManagedBeanów, WSEndpointów i Handlerów.
Nie wstrzykujemy do staticów ani pól final. Można wstrzykiwać do pól elementów prywatnych.
Lookup zwraca zawsze nową instancję, chyba że obiekt jest immutable, jest singletonem lub może być współdzielony.
Transakcje
Propagacja transakcji. Notacja:
[metoda_wywołana_w_transakcji;metoda_wywołana_bez_transakcji]
[1-wykona się w istniejącej transakcji, 2-zostanie utworzona nowa transakcja, 0-wykona się bez transakcji,
!-zostanie wyrzucony wyjątek]
- NOT_SUPPORTED [0;0]
- REQUIRED [1;2]
- SUPPORTS [1;0]
- REQUIRES_NEW [2;2]
- MANDATORY [1;!]
- NEVER [!;0]
MANDATORY i NEVER mają wymagania co do kontekstu, w którym są wołane i rzucają wyjątkami, gdy wymagania te nie są spełnione (np. EJBTransactionRequiredException).
NOT_SUPPORTED i REQUIRES_NEW nie zależą od kontekstu, w którym są wywoływane i wykonują się odpowiednio bez transakcji / w nowej transakcji.
REQUIRED i SUPPORTS przyłączają się do istniejącej transakcji; a gdy jej nie ma odpowiednio tworzą nową lub wykonują się bez transakcji.
Klient używający CMT wie, że nie ma co kontynuować transakcji, jeżeli getRollbackOnly zwróci true lub gdy otrzyma EJBTransactionRolledbackException.
Jeżeli SLSB lub MDB nie zakończą transakcji w metodzie biznesowej, kontener ją zrollbackuje. Nie dotyczy to SFSB.
Sposób zarządzania transakcjami określamy adnotacją @TransactionManagement(TransactionManagementType.BEAN) na poziomie beana.
Bean nie może rozpocząć nowej transakcji przed zakończeniem poprzedniej.
Commit transakcji oznaczonej do zrollbackowania spowoduje wyrzucenie wyjątku.
Przy BMT mamy do czynienia z interfejsem UserTransaction. Transakcje obslugujemy metodami getStatus/rollback. W przypadku CMT jest to get/setRollbackOnly. Nie ma problemu, by wywołać CMT z BMT. Po wywołaniu status transakcji możemy spokojnie sprawdzić metodą getStatus.
Wywołanie EJBContext.get/setRollbackOnly gdy nie ma aktywnej transakcji spowoduje wyrzucenie IllegalStateException. UserTransaction.setRollbackOnly również.
Transakcja może zostać zrollbackowana, jeżeli wywołano setRollbackOnly lub wyrzucono wyjątek systemowy lub wyrzucono wyjątek aplikacyjny z rollback=true.
Klient używający CMT wie, że nie ma co kontynuować transakcji, jeżeli getRollbackOnly zwróci true lub gdy otrzyma EJBTransactionRolledbackException.
Jeżeli metoda zostaje nadpisana w klasie dziedziczącej, atrybuty transakcji z klasy bazowej są ignorowane. Tzn. jeżeli po przesłonięciu nie definiujemy atrybutu, to jest REQUIRED.
W sytuacji, gdy adnotacjami określono TransactionManagement na konkretniej metodzie, a w xml-u określono TManagement dla wszystkich metod beana - pod uwagę jest brana wartość z xml-a.
Beany
Klasy beanów muszą być publiczne, top-level, nieabstrakcyjne, niefinalne.
Dwa kolejne lookupy statefula przez tego samego klienta spowodują utworzenie dwóch różnych instancji.
Dwie instancje statelessów przejdą test na identyczność (equals). Statefulli już nie.
Przekazywanie argumentów poprzez zdalne interfejsy jest zgodne z Java RMI-IIOP. Nawet, jeżeli wykorzystywane są lokalnie. Przy interfejsach @Remote przekazujemy argumenty przez wartość, przy @Local przez referencję.
Jeżeli bean implementuje więcej niż jeden interfejs (pomijając Serializable, Externalizable i interfejsy z pakietu javax.ejb), wszystkie interfejsy muszą być zaadnotowane jako @Local lub @Remote. Jeżeli ma tylko jeden interfejs, nie musi mieć on adnotacji - domyślnie przyjmuje się, że jest to interfejs lokalny. Interfejs nie może być jednocześnie oznaczony jako @Local i @Remote.
Adnotacje można spokojnie umieszczać na klasie, po której bean dziedziczy.
Nazwa beana jest brana z nazwy klasy, jeżeli nie określono atrybutu name adnotacji @Stateful/@Stateless.
Element <ejb-ref-name> odpowiada @EJB(name=...). <injection-target-name> odpowiada nazwie pola. @EJB(beanName=...) odpowiada elementowi <ejb-link>. Typ zmiennej odpowiada interfejsowi, np <local>.
Wywołanie metodę na usuniętej instancji statefula spowoduje wyrzucenie NoSuchEJBException.
Interfejs SessionSynchronization przeznaczony jest dla statefuli.
Stan statefula jest utrzymywany między wywołaniami metod i transakcjami. Pola interceptortów statefula są częścią jego stanu.
Metody wystawione przez WS nie powinny zwracać referencji, które nie mają sensu poza JVM, w tym interfejsów lokalnych/zdalnych ani timerów.
Metody getEJBObject() i getEJBLocalObject() są przesztarzałe. Referencję do beana uzyskamy metodą getBusinessObject().
MDB
Chcąc się dobrać do MessageDrivenContext, po prostu deklarujemy do niego zależność.
MDB JMS-owe implementują javax.jms.MessageListener, z metodą onMessage(Message message). Metoda onMessage nie może deklarować checked exceptions (RemoteException to też checked exception).
Można zawęzić rodzaj komunikatów odbieranych przez jMS poprzez message selector declarations. Przypisane beana do kolejki lub tematu odbywa się poprzez atrybut activationConfig adnotacji @MessageDriven.
Ustawienie subscriptionDurability=Durable na temacie (topic) sprawi, że MDB nie przegapi żadnej wiadomości, nawet w przypadku awarii serwera. Jeżeli chodzi o kolejki (queue), wysyłane komunikaty podczas awarii serwera zostaną dostarczone po restarcie.
Przy CMT i REQUIRED otrzymanie komunikatu zostanie zrollbackowane, jeżeli metoda wyrzuci wyjątek (jest częścią transakcji).
Kontener zajmuje się potwierdzeniem odbioru komunikatu, nawet przy BMT.
Instancja MDB obsługuje co najwyżej jeden wątek na raz. Kolejność komunikatów nie musi zostać zachowana.
Można określić adres zwrotny w atrybucie JMSReplyTo komunikatu.
Źródła
Specyfikacja
Enterprise JavaBeans 3.1, Andrew Lee Rubinger and Bill Burke
EJB 3 in Action, Debu Panda, Reza Rahman, Derek Lane
Mikalai Zaikin SCBCD Study Guide
PC - PersistenceContext
EM - EntityManager
EMF - EntityManagerFactory
PC zarządzany przez aplikację ma zasięg rozszerzony. PC zarządzany przez kontener może mieć zasięg rozszerzony (tylko dla SFSB) lub zasięg transakcji.
PC rozpoczyna się:
- z chwilą, gdy EM zostanie wywołany w zasięgu aktywnej transakcji JTA (dla EM zarządzanego przez kontener i PC o zasięgu transakcji)
- gdy EM zostanie utworzony (dla EM zarządzanego przez aplikację, PC wówczas zawsze ma zasięg rozszerzony)
- gdy SFSB zostanie utworzony a PC do niego przypięty (dla EM zarządzanego przez kontener i PC o zasięgu rozszerzonym - który może występować tylko w ramach statefula)
Aby zakończyć PC, wywołujemy EM.close(). Nie można tego zrobić na EM zarządzanym przez kontener. Po wywołaniu tej metody, wszystkie metody EM poza isOpen() i getTransaction() wyrzucą IllegalStateException.
PC zarządzany przez kontener musi być JTA. Zarządzany przez aplikację może być JTA lub RESOURCE_LOCAL. (Domyślna wartość transaction-type dla środowisk Java EE to JTA, a dla Java SE - RESOURCE_LOCAL).
Jeżeli wstrzykujemy EM do beana (tzn. PC jest zarządzany przez kontener), to nie będziemy używać EntityTransaction, wykorzystywanego przy RESOURCE_LOCAL.
Jeżeli EM tworzymy ręcznie poprzez EMF.createEntityManager (tzn. PC jest zarządzany przez aplikację), to możemy używać zarówno EntityTransaction jak i JTA.
Jeżeli używamy JTA i utworzyliśmy EM poza zasięgiem transakcji, przed wykonaniem operacji należy wywołać em.joinTransaction().
Podsumowując: PC dzielimy na ContainerManaged/AppManaged, JTA/RESOURCE_LOCAL, TxScoped/Extended.
Domyślny FlushMode (Auto) zapewnia, że przed wykonaniem zapytania zmiany, które mogą go dotyczyć zostaną zrzucone do bazy. Jednak flush nie sprawi, że zmiany z niezatwierdzonej transakcji będą widoczne dla innych transakcji. Nadużywanie flusha ma wpływ na wydajność.
Encje mogą być w jednym z czterech stanów: new, managed, detached, removed. Wszystkie poza new mają persistent identity. Managed i removed są 'associated with PC'.
Remove i lock wymagają non-detached entity. Refresh wymaga managed entity. Merge oczekuje non-removed entity. Persist wymaga po prostu entity (choć wywołana na detached entity może skutkować wyrzuceniem EntityExistsException lub innego PersistenceException). Jak nie dostaną czego chcą, wyplują IllegalArgumentException.
Persist wywołane na removed entity zmieni ją w managed entity.
Persistence.xml jest obowiązkowy. Można w nim zdefiniować wiele PU. Jeden PU odpowiada jednemu datasource. Każdy PU musi mieć nazwę. Jeżeli mamy wiecej niż jeden PU, tworząc EM lub EMF należy podać nazwę konkretnego PU. Encje i klasy embedded muszą być (jawnie lub nie) uwzględnione w persistence.xml jako klasy zarządzane, by były uwzględnione w PU.
Dzięki propagacji PC nie trzeba przekazywać referencji do EM między beanami. Propagacja kontekstu dotyczy PC zarządzanego przez kontener. PC propagowany jest razem z transakcją (tzn. jeżeli transakcja nie jest propagowana, to PC również nie).
JPQL i operacje na bazie
Operacje modyfikujące dane w bazie wymagają transakcji (inaczej wyplują TransactionRequiredException), operacje odczytujące dane nie. Przykładowo update, flush, persist wymagają transakcji, natomiast clear i find już nie. Encje wyciągnięte poza transakcją będą detached (dla PC o zasięgu transakcji) lub managed (dla PC o zasięgu rozszerzonym). Jeżeli find zdarzy się splunąć wyjątkiem to najprawdopodobniej klasa klucza głównego się nie zgadza.
Po wykonaniu executeUpdate załadowane encje, których zmiany dotyczą, nie zostaną odświeżone. Próba wywołania executeUpdate z zapytaniem typu SELECT spowoduje wyrzucenie IllegalStateException. Operacje masowe - DELETE, UPDATE w JPQL mogą się sypnąć na constraintach, rzucając PersistenceException.
Persist będzie kaskadowany przy Cascade.PERSIST i ALL. Remove przy REMOVE i ALL ale tylko dla relacji OneToOne i OneToMany (zachowanie dla pozostałych nie jest określone). Remove na nowej encji nie usunie jej z bazy (jeszcze jej tam nie ma) - ale jeżeli mamy cascade, to spowoduje usunięcie encji wskazywanych przez tę encję.
Zapytania JPQL można zdefiniować za pomocą adnotacji @NamedQuery lub elementu named-query w xml-u. Zapytania sql-owe analogicznie - poprzez @NamedNativeQuery. Wynikiem zapytań mogą być encje, ale można też zdefiniować bardziej skomplikowane mapowania.
Zapytanie "SELECT k FROM Klasa k INNER JOIN k.uczniowie u" zwróci pojedyncze klasy, a nie po 30 sztuk każdej. Co innego, gdybyśmy dodali FETCH.
W zapytaniach można używać konstruktorów. Przykładowo: "SELECT NEW Integer(MAX(k.uczniowie)) FROM Klasa k".
Elementy uwzględnione w ORDER BY muszą występować w klauzuli SELECT i muszą być szeregowalne (tzn. liczby, stringi, znaki lub daty).
SIZE używamy w klauzuli WHERE, natomiast COUNT w klauzuli SELECT. Podzapytań używamy w klauzuli WHERE. ALL, ANY, SOME, EXISTS stosujemy do podzapytań. MEMBER OF stosujemy do kolekcji. MAX, AVG również do kolekcji.
Używając LIKE mamy do dyspozycji dwa wildcardy: _ zastępuje jeden znak, % dowolnie wiele znaków. BETWEEN jest dwustronnie inclusive.
Find() zwraca nulla, jeżeli nic nie znajdzie. GetRefence() wyrzuca EntityNotFoundException - ale getReference nie musi strzelać do bazy (wówczas wyjątek zostanie wyrzucony dopiero przy próbie dobrania się do pola encji).
Contains() zwróci true tylko dla managed entity - dla detached, removed i new zwróci false.
Encje
PP - PersistenceProvider
Encje umieszczamy w roocie PU lub w jarze znajdującym się w classpath PU.
Próba zapisu encji z istniejącym kluczem zakończy się rollbackiem.
Pole trwałe to takie, które nie jest transient ani @Transient. Pole trwałe o "złożonym" typie w encji nie musi być oznaczone jako @Lob, ale musi być serializowalne. (Dokładniej: musi być prymitywem, Stringiem, wrapperem, BigDecimal/Interger, Calendar, java.util/sql.Date, java.sql.Time/Timestamp, enumem, encją, kolekcją encji, klasą @Embeddable, byte[], Byte[], char[], Character[] albo Serializable.)
Określenie pola @Version sprawi, że PP użyje go do zapewnienia optimistic lockingu. @Version powinno być określone na głównej tabeli encji. Dopuszczalne typy: int, Integer, s/Short, l/Long, Timestamp.
@Basic można zawsze dać na polu, ale jest opcjonalna. Ma elementy fetch i optional.
Nazwę tabeli dla encji określamy poprzez @Table("TABLE_NAME") lub poprzez <entity ...> <table name="TABLE_NAME">. Nazw tabel nie nadpisujemy w persistence.xml - do tego służą pliki mapowań. Pliki mapowań to META-INF/orm.xml lub xml-e określone elementem mapping-file w persistence.xml. Domyślna nazwa tabeli przy złączeniach z użyciem JoinTable (gdy nie określono atrybutu name) to połączenie nazw tabel, oddzielonych podkreśleniem, przy czym pierwsza to owning side.
Klucz główny definiujemy w korzeniu hierarchii encji - czy to encja, czy mapped superclass.
Złożone klucze główne można zmapować na dwa sposoby:
- adnotacja @IdClass(SomePKClass.class) na poziomie encji + adnoracje @Id na polach encji odpowiadających polom z SomePKClass;
- adnotacja @EmbeddedId na polu o typie oznaczonym jako @Embeddable.
IdClass musi definiować equals i hashCode zgodne z porównywaniem encji po stronie bazy.
Strategię dziedziczenia określamy poprzez @Inheritance(strategy=[JOINED/SINGLE_TABLE/TABLE_PER_CLASS]). JOINED oznacza, że każda encja, również pośrednia, ma osobną tabelę. TABLE_PER_CLASS nie musi być wspierana w EJB 3.0.
@MappedSuperclass nie może występować w zapytaniach. Niezależnie od strategii, nie posiada osobnej tabeli w bazie. Może natomiast występować w dowolnym miejscu w hierarchii encji.
W relacjach dwustronnych owning side to strona posiadająca klucz obcy i jest to ta strona, po której nie ma mappedBy. W relacjach jednostronnych jedyna istniejąca strona jest owning side. W ManyToMany każda ze stron może być owning side. To operajce wykonywane na owning side mają znaczenie.
@OneToMany oznacza "jeden obiekt klasy, w której znajduje się ta adnotacja do wielu obiektów klasy zdefiniowanej przez pole (kolekcję), na którym się znajduje".
Definiując relacje, atrybut targetEntity jest wymagany jeżeli adnotujemy kolekcję bez generycznego zawężenia.
Gettery/settery dla encji używając dostępu opartego o te metody powinny być publiczne lub chronione. Encja musi mieć bezargumentowy konstruktor. Jeżeli ma być przekazywana przez interfejs zdalny, powinna być również Serializable.
Klucz główny może być prymitywem (ale nie typem numerycznym przybliżonym - double, float), wrapperem, Stringiem, java.sql.Date lub java.util.Date. Dla java.util.Date musi mieć temporal type ustawiony na DATE. (@Temporal musi być określony dla typów java.util.Date i java.util.Calendar.) Musi być serializowalny. Musi definiować equals i hashCode w sposób zgodny ze sposobem porównywania tych wartości w bazie.
Klasy abstrakcyjne mogą być encjami.
Typ dostępu (pola/akcesory) dotyczy całej konkretnej hierarchii encji.
Timery
Chcąc wykonać operację po określonym czasie, używamy Timerów - albo oznaczająć metodę jako @Timeout albo implementując interfejs TimedObject. Bean może mieć tylko jedną metodę timeout.
Callbacki
Callbacki mogą być prywatne, ale nie mogą być statyczne i muszą zwracać void.
Callbacki encji zdefiniowane w listenerach muszą przyjąć Object albo obiekt encji jako argument. Callbacki encji nie powinny wywoływać operacji na EntityManager ani Query, odwoływać się do innych encji ani modyfikować relacji.
Callbacki nie powinny pluć checked exception. Zdefiniowane w klasie, której dotyczą, w większości muszą być bezargumentowe. @PreDestroy w Statelessie wykonuje się w nieokreślonym kontekście transakcji i bezpieczeństwa.
@PostActivate, @PrePassivate - dobre miejsce by inicjować i niszczyć resourcy, które wymagają ręcznej obsługi. Z uwagi na timeouty, w @PreDestroy też warto zająć się niszczeniem resourców. Nieserializowalne pola powinny zostać znullowane w @PrePassivate (dokładniej - pola, które nie są Timerami, SessionContextem, referencjami do beanów, nie są serializowalne. Można pominąć też pola, które staną się "serializowalne" poprzez zastosowanie tych zasad do ich składowych.).
Obowiązki kontenera i restrykcje dla programisty EJB
Kontener musi zapewnić (choćby częściowo) API: JAX-WS, JavaMail, JNDI, JDBC, JAXB i sporo innych (RMI-IIOP, JAXP, Java IDL, EJB 3.0 + JPA, JTA, JMS, JAF, JAXR, JAX_RPC, SAAJ, Connector, Web Services, Web Services Metadata, Common Annotations, StAX).
Kontener nie musi zapewnić load-balancingu ani klastrowania. Nie musi też niczego gwarantować w przypadku awarii serwera.
EJB nie używają interfejsów graficznych. Nie dobierają się do plików za pomocą java.io. Nie ładują bibliotek natywnych. Nie tworzą SecurityManagerów ani Classloaderów. Nie słuchają na gnieździe, ale mogą być klientem gniazda. Nie zajmują się wątkami (w EJB 3.1 ograniczenie to nie dotyczy Singletona z współbieżnością zarządzaną przez beana). Nie zmieniają wartości pól statycznych (dlatego najlepiej od razu oznaczyć je jako final).
Nie używają obiektów związanych z bezpieczeństwem (Policy, Securyty, Provider, Signer, Identity). Nie dobierają się refleksją do elementów prywatnych. Nie używają AWT. Nie pobierają danych z klawiatury. Itd.
Integracja EJB 2.1/3.0
Adnotacja @Init pozwala określić metodę inicjalizującą w 3.0, odpowiadającą metodom createXXX w interfejsach domowych.
Aby wywołać 2.1 z 3.0 można wstrzyknąć referencję do HomeInterface za pomocą adnotacji @EJB, a następnie wywołać na tym obiekcie metodę create().
Aby wywołać 3.0 z 2.1 można użyć adnotacji @RemoteHome i @LocalHome.
Role
Role określone w specyfikacji to: Persistence Provider, Application Assembler, EJB Container Provider, Enterprise Bean Provider, System Administrator, EJB Server Provider, Deployer.
Admin przykładowo konfiguruje LDAP-a.
Deployer mapuje role na grupy użytkowników (wszystkie role - z @RolesAllowed, @DeclareRoles i z XML-a). Ale same role i referencje do ról określaja Bean Provider i Assembler, deployer ich nie zmienia.
Bean Provider i Assembler mogą określać atrybuty transakcji i kolejność interceptorów w deskryptorze wdrożenia.
EJB-JAR jest edytowany przez Bean Providera, Assemblera i Deployera. Jego format jest kontraktem między tą trójką.
Bezpieczeństwo
Metodę można oznaczyć jako unchecked - tzn. każdy ma do niej dostęp. Jeżeli poza elementem unchecked wymieniono również kilka ról, nadal każdy ma do niej dostęp.
@RunAs("SomeRole") na beanie sprawi, że metody wywoływane z jego metod wywołają się z rolą "SomeRole".
Jeżeli role-name w security-role-ref jest taka sama jak nazwa w security-role, element role-link nie jest potrzebny.
Metoda getCallerPrincipal nie zwróci nulla, tylko obiekt reprezentujący 'UNAUTHENTICATED identity'. Obiekt Principal nie zawiera informacji o rolach. Principal.getName zależy od security realm użytego do autentykacji.
Wyjątki
Wyjątki aplikacyjne definiujemy poprzez @ApplicationException. Nie mogą rozszerzać @RemoteException. Wyjątki aplikacyjne są propagowane bez zmian. Runtimy domyślnie są wyjątkami systemowymi. Wyjątki systemowe są opakowywane w EJBException lub w EJBTransactionRolledbackException (gdy metoda wykonywała się w transakcji klienta). Jeżeli bean nie może pozbierać się po checked exception, należy opakować go w EJBException. NoSuchEJBException, EJBException, EJBTransactionRolledbackException i EJBTransactionRequiredException to wyjatki systemowe.
PersistenceExceptions to Runtimy. NonUniqueResultEx (przy getSingleResult) i NoResultEx (wyrzucane przez getSingleResult) nie powodują rollbacka. Pozostałe to EntityExistsEx, EntityNotFoundEx, RollbackEx, OptimisticLockingEx, TransactionRequiredEx.
Wyjątki javax.ejb.CreateException, javax.ejb.RemoveException, javax.ejb.FinderException i ich podklasy to wyjątki aplikacyjne.
Adnotacje i zależności
Rejestrując referencje w ENC (na poziomie klasy) określamy jej nazwę i typ. Na poziomie pola nie jest to konieczne.
Do wstrzykiwania EntityManagerFactory służy @PersistenceUnit. Do wstrzyknięcia EntityManager służy @PersistenceContext.
Dostęp do UserTransaction można uzyskać z JNDI pod nazwą "java:comp/UserTransaction", przez metodę EJBContext.getUserTransaction lub poprzez wstrzyknięcie adnotacją @Resource.
W konstruktorze beana nie dobieramy się do innych beanów. W callbakach statelessa też nie. W callbackach statefula już można. W timeoucie też można.
XML jest zawsze istotniejszy od adnotacji i zazwyczaj je nadpisuje. Może je uzupełniać. W XML-u nie możemy jednak nadpisać wzsystkiego - np. typu beana.
@EJB i @Resource można umieścić na poziomie klasy (dodając tym samym wpisy w ENC beana), pola (wstrzykując zależność) lub metody (jw., na setterze). @RolesAllowed można umieścić na poziomie klasy lub metody (nie przyznajemy uprawnień do pól).
Referencje do destynacji można wstrzyknąć adnotacją @Resource, np. @Resource(mappedName="topic/MyTopic") private javax.jms.Topic myTopic;. Można też to zrobić na poziomie klasy: @Stateless @Resource(name="jms/MyTopic", type=javax.jms.Topic, lookup="topic/MyTopic").
Wstrzykiwanie zależności dostępne jest dla EJB, Interceptorów, Servletów, Filtrów, ServletListenerów, JSF ManagedBeanów, WSEndpointów i Handlerów.
Nie wstrzykujemy do staticów ani pól final. Można wstrzykiwać do pól elementów prywatnych.
Lookup zwraca zawsze nową instancję, chyba że obiekt jest immutable, jest singletonem lub może być współdzielony.
Transakcje
Propagacja transakcji. Notacja:
[metoda_wywołana_w_transakcji;metoda_wywołana_bez_transakcji]
[1-wykona się w istniejącej transakcji, 2-zostanie utworzona nowa transakcja, 0-wykona się bez transakcji,
!-zostanie wyrzucony wyjątek]
- NOT_SUPPORTED [0;0]
- REQUIRED [1;2]
- SUPPORTS [1;0]
- REQUIRES_NEW [2;2]
- MANDATORY [1;!]
- NEVER [!;0]
MANDATORY i NEVER mają wymagania co do kontekstu, w którym są wołane i rzucają wyjątkami, gdy wymagania te nie są spełnione (np. EJBTransactionRequiredException).
NOT_SUPPORTED i REQUIRES_NEW nie zależą od kontekstu, w którym są wywoływane i wykonują się odpowiednio bez transakcji / w nowej transakcji.
REQUIRED i SUPPORTS przyłączają się do istniejącej transakcji; a gdy jej nie ma odpowiednio tworzą nową lub wykonują się bez transakcji.
Klient używający CMT wie, że nie ma co kontynuować transakcji, jeżeli getRollbackOnly zwróci true lub gdy otrzyma EJBTransactionRolledbackException.
Jeżeli SLSB lub MDB nie zakończą transakcji w metodzie biznesowej, kontener ją zrollbackuje. Nie dotyczy to SFSB.
Sposób zarządzania transakcjami określamy adnotacją @TransactionManagement(TransactionManagementType.BEAN) na poziomie beana.
Bean nie może rozpocząć nowej transakcji przed zakończeniem poprzedniej.
Commit transakcji oznaczonej do zrollbackowania spowoduje wyrzucenie wyjątku.
Przy BMT mamy do czynienia z interfejsem UserTransaction. Transakcje obslugujemy metodami getStatus/rollback. W przypadku CMT jest to get/setRollbackOnly. Nie ma problemu, by wywołać CMT z BMT. Po wywołaniu status transakcji możemy spokojnie sprawdzić metodą getStatus.
Wywołanie EJBContext.get/setRollbackOnly gdy nie ma aktywnej transakcji spowoduje wyrzucenie IllegalStateException. UserTransaction.setRollbackOnly również.
Transakcja może zostać zrollbackowana, jeżeli wywołano setRollbackOnly lub wyrzucono wyjątek systemowy lub wyrzucono wyjątek aplikacyjny z rollback=true.
Klient używający CMT wie, że nie ma co kontynuować transakcji, jeżeli getRollbackOnly zwróci true lub gdy otrzyma EJBTransactionRolledbackException.
Jeżeli metoda zostaje nadpisana w klasie dziedziczącej, atrybuty transakcji z klasy bazowej są ignorowane. Tzn. jeżeli po przesłonięciu nie definiujemy atrybutu, to jest REQUIRED.
W sytuacji, gdy adnotacjami określono TransactionManagement na konkretniej metodzie, a w xml-u określono TManagement dla wszystkich metod beana - pod uwagę jest brana wartość z xml-a.
Beany
Klasy beanów muszą być publiczne, top-level, nieabstrakcyjne, niefinalne.
Dwa kolejne lookupy statefula przez tego samego klienta spowodują utworzenie dwóch różnych instancji.
Dwie instancje statelessów przejdą test na identyczność (equals). Statefulli już nie.
Przekazywanie argumentów poprzez zdalne interfejsy jest zgodne z Java RMI-IIOP. Nawet, jeżeli wykorzystywane są lokalnie. Przy interfejsach @Remote przekazujemy argumenty przez wartość, przy @Local przez referencję.
Jeżeli bean implementuje więcej niż jeden interfejs (pomijając Serializable, Externalizable i interfejsy z pakietu javax.ejb), wszystkie interfejsy muszą być zaadnotowane jako @Local lub @Remote. Jeżeli ma tylko jeden interfejs, nie musi mieć on adnotacji - domyślnie przyjmuje się, że jest to interfejs lokalny. Interfejs nie może być jednocześnie oznaczony jako @Local i @Remote.
Adnotacje można spokojnie umieszczać na klasie, po której bean dziedziczy.
Nazwa beana jest brana z nazwy klasy, jeżeli nie określono atrybutu name adnotacji @Stateful/@Stateless.
Element <ejb-ref-name> odpowiada @EJB(name=...). <injection-target-name> odpowiada nazwie pola. @EJB(beanName=...) odpowiada elementowi <ejb-link>. Typ zmiennej odpowiada interfejsowi, np <local>.
Wywołanie metodę na usuniętej instancji statefula spowoduje wyrzucenie NoSuchEJBException.
Interfejs SessionSynchronization przeznaczony jest dla statefuli.
Stan statefula jest utrzymywany między wywołaniami metod i transakcjami. Pola interceptortów statefula są częścią jego stanu.
Metody wystawione przez WS nie powinny zwracać referencji, które nie mają sensu poza JVM, w tym interfejsów lokalnych/zdalnych ani timerów.
Metody getEJBObject() i getEJBLocalObject() są przesztarzałe. Referencję do beana uzyskamy metodą getBusinessObject().
MDB
Chcąc się dobrać do MessageDrivenContext, po prostu deklarujemy do niego zależność.
MDB JMS-owe implementują javax.jms.MessageListener, z metodą onMessage(Message message). Metoda onMessage nie może deklarować checked exceptions (RemoteException to też checked exception).
Można zawęzić rodzaj komunikatów odbieranych przez jMS poprzez message selector declarations. Przypisane beana do kolejki lub tematu odbywa się poprzez atrybut activationConfig adnotacji @MessageDriven.
Ustawienie subscriptionDurability=Durable na temacie (topic) sprawi, że MDB nie przegapi żadnej wiadomości, nawet w przypadku awarii serwera. Jeżeli chodzi o kolejki (queue), wysyłane komunikaty podczas awarii serwera zostaną dostarczone po restarcie.
Przy CMT i REQUIRED otrzymanie komunikatu zostanie zrollbackowane, jeżeli metoda wyrzuci wyjątek (jest częścią transakcji).
Kontener zajmuje się potwierdzeniem odbioru komunikatu, nawet przy BMT.
Instancja MDB obsługuje co najwyżej jeden wątek na raz. Kolejność komunikatów nie musi zostać zachowana.
Można określić adres zwrotny w atrybucie JMSReplyTo komunikatu.
Źródła
Specyfikacja
Enterprise JavaBeans 3.1, Andrew Lee Rubinger and Bill Burke
EJB 3 in Action, Debu Panda, Reza Rahman, Derek Lane
Mikalai Zaikin SCBCD Study Guide
środa, 2 stycznia 2013
wtorek, 1 stycznia 2013
poniedziałek, 31 grudnia 2012
Miecz Prawdy, Terry Goodkind
"It was an odd-looking vine. Dusky variegated leaves hunkered against a stem that wound in a stranglehold around the smooth trunk of a balsam fir. Sap drooled down the wounded bark, and dry limbs slumped, making it look as if the tree were trying to voice a moan into the cool, damp morning air. Pods stuck out from the vine here and there along its length, almost seeming to look warily about for witnesses."
Te cztery zdania zachęciły mnie do przeczytania książki. Obiecywała wyzwanie, przynajmniej pod względem językowym. I przeczytałam. Fragment pochodzi z pierwszego tomu serii, "Wizard's First Rule". Zaraz potem sięgnęłam po "Stone of Tears", "Blood of the Fold", "Soul of Fire" i "Faith of the Fallen".
Pominąwszy zacytowany fragment, czytając praktycznie zapomniałam, w jakim języku jest książka. Pierwszy tom zaskoczył mnie pozytywnie sposobem prowadzenia narracji. O, jest piękna, zdeterminowana dziewczyna, pomykająca z gracją w prostej, białej sukni po lesie. Dziewczyna ma sporo tajemnic i autor z powodzeniem rozbudza ciekawość czytelnika, podrzucając mu szczodre kawałki informacji i pozwalając układać je w całość. W momencie gdy czytelnik poskłada puzzle w spójny obrazek (i spodziewa się, że główny bohater będzie do tego dochodził przez całą książkę), bohaterowie siadają przy stole i w jednej chwili odkrywają wszystkie karty. Ciekawe.
Książka okazała się przyjemną, lekką lekturą, w sam raz by usiąść w fotelu i odprężyć się po pracy. Zdarzyło mi się trafić na fragmenty, które wprawiły mnie w osłupienie. Terry zwrócił uwagę na elementy życia i otaczającej nas rzeczywistości, które wydają się naturalne, a dopiero z odpowiedniej perspektywy widać ich absurdalność. Nic jednak w szczególny sposób nie zapadło mi w pamięć. Poza Nicci, która praktycznie zdominowała tom Faith of the Fallen.
Te cztery zdania zachęciły mnie do przeczytania książki. Obiecywała wyzwanie, przynajmniej pod względem językowym. I przeczytałam. Fragment pochodzi z pierwszego tomu serii, "Wizard's First Rule". Zaraz potem sięgnęłam po "Stone of Tears", "Blood of the Fold", "Soul of Fire" i "Faith of the Fallen".
Pominąwszy zacytowany fragment, czytając praktycznie zapomniałam, w jakim języku jest książka. Pierwszy tom zaskoczył mnie pozytywnie sposobem prowadzenia narracji. O, jest piękna, zdeterminowana dziewczyna, pomykająca z gracją w prostej, białej sukni po lesie. Dziewczyna ma sporo tajemnic i autor z powodzeniem rozbudza ciekawość czytelnika, podrzucając mu szczodre kawałki informacji i pozwalając układać je w całość. W momencie gdy czytelnik poskłada puzzle w spójny obrazek (i spodziewa się, że główny bohater będzie do tego dochodził przez całą książkę), bohaterowie siadają przy stole i w jednej chwili odkrywają wszystkie karty. Ciekawe.
Książka okazała się przyjemną, lekką lekturą, w sam raz by usiąść w fotelu i odprężyć się po pracy. Zdarzyło mi się trafić na fragmenty, które wprawiły mnie w osłupienie. Terry zwrócił uwagę na elementy życia i otaczającej nas rzeczywistości, które wydają się naturalne, a dopiero z odpowiedniej perspektywy widać ich absurdalność. Nic jednak w szczególny sposób nie zapadło mi w pamięć. Poza Nicci, która praktycznie zdominowała tom Faith of the Fallen.
Nicci straightened, feeling a hollow disappointment. She always did. She sometimes found herself looking into people's eyes, like this, and then wondering why. If she was searching for something, she didn't know what it was.
On occasion, for reason or not, Jagang would become furious at her and would heatedly order her to the tents for a month-to teach her a lesson, he would say. Nicci would obediently bow and pledge it would be as he wished. He knew she was not bluffing; it would have been a lesser torment. Before she could be out the door to the tents, he would turn moody, command her to return to face him, and then angrily retract the orders.
The fact that she was sincere was her safety-and her peril. She was a fawn among wolves, safe in her coat of indifference. The fawn was in danger only if it ran. She did not view her captivity as a conflict with her interests; she had no interests. Time and again she had the opportunity to run, but didn't.
środa, 19 grudnia 2012
Niniejszy suplement do dyplomu oparty jest na modelu...
Z uwagi na nieoczekiwaną zmianę planów, trafił mi się dzień wolnego w środku tygodnia.
Zabrałam dokumenty, które swoje już w teczce odleżały i pojechałam na uczelnię.
Spacer po znajomych, przestronnych korytarzach zrobił na mnie niezwykłe wrażenie. Przez chwilę przypomniałam sobie, że byłam kiedyś innym człowiekiem. I w którymś momencie dałam się wcisnąć do ciasnej przestrzeni za zastawionym monitorami biurkiem.
Formalności zajęły znacznie mniej czasu, niż się spodziewałam. Wszystkie brakujące podpisy uzyskałam w jednym budynku, a panie w dziekanacie swoim nastawieniem przeczyły wszelkim popularnym stereotypom.
Spotkałam na korytarzu dawnego kolegę. Studiowaliśmy razem. Teraz jest tam pracownikiem. Spojrzał na mnie z nieskrywanym zdziwieniem:
- Co ty tu robisz?!
- Mam dzień wolnego, załatwiam zaległe formalności. Przyszłam odebrać dyplom - uśmiechnęłam się. - Kiedyś trzeba.
- Dyplom, dopiero teraz?! Cóż, najwyższa pora...
Uśmiechnęłam się ponownie.
Zrobiłam zakupy, zjadłam kilka kanapek i zanurzyłam się w jednej z ostatnio nabytych powieści. Trafiwszy na opis zapuszczonego do granic możliwości mieszkania odłożyłam książkę, sięgnęłam po ścierkę i profilaktycznie ogarnęłam własne. Sprawdziłam służbą pocztę. Z korespondencji wynikało, że muszą za mną tęsknić. Cóż, poradzą sobie. Położyłam się pod miękkim kocem i wyspałam do woli.
Moje ambitne plany na wykorzystanie tego wolnego czasu poszły tańczyć, śpiewać i urządzać orgie.
Zabrałam dokumenty, które swoje już w teczce odleżały i pojechałam na uczelnię.
Spacer po znajomych, przestronnych korytarzach zrobił na mnie niezwykłe wrażenie. Przez chwilę przypomniałam sobie, że byłam kiedyś innym człowiekiem. I w którymś momencie dałam się wcisnąć do ciasnej przestrzeni za zastawionym monitorami biurkiem.
Formalności zajęły znacznie mniej czasu, niż się spodziewałam. Wszystkie brakujące podpisy uzyskałam w jednym budynku, a panie w dziekanacie swoim nastawieniem przeczyły wszelkim popularnym stereotypom.
Spotkałam na korytarzu dawnego kolegę. Studiowaliśmy razem. Teraz jest tam pracownikiem. Spojrzał na mnie z nieskrywanym zdziwieniem:
- Co ty tu robisz?!
- Mam dzień wolnego, załatwiam zaległe formalności. Przyszłam odebrać dyplom - uśmiechnęłam się. - Kiedyś trzeba.
- Dyplom, dopiero teraz?! Cóż, najwyższa pora...
Uśmiechnęłam się ponownie.
Zrobiłam zakupy, zjadłam kilka kanapek i zanurzyłam się w jednej z ostatnio nabytych powieści. Trafiwszy na opis zapuszczonego do granic możliwości mieszkania odłożyłam książkę, sięgnęłam po ścierkę i profilaktycznie ogarnęłam własne. Sprawdziłam służbą pocztę. Z korespondencji wynikało, że muszą za mną tęsknić. Cóż, poradzą sobie. Położyłam się pod miękkim kocem i wyspałam do woli.
Moje ambitne plany na wykorzystanie tego wolnego czasu poszły tańczyć, śpiewać i urządzać orgie.
środa, 7 listopada 2012
EJB 3.1 [8]
Timer Service
A timer is associated with the bean that created it and it calls it's ejbTimeout(Timer timer)/@Timeout method when it goes off.
Since EJB 3.1 there is a ScheduleExpression class that allows to define when timer should be fired. There is also @Schedule annotation, that alows to achieve the same in a declarative manner.
EJB must implement TimedObject interface to use Timer Service.
TimerService can be accessed with sessionContext.getTimerService() method. You can create a timer with timerService.createXxxTimer() call (it can create SingleAction, Interval ands Calendar timers).
Alternatively, you can do it in declarative manner with @Schedule annotation:
Timers are persistent - they will be restored if the system crashes. It isn't clear what will happen with the interval timers that would go off several times while the system is down (they may catch up just after the startup).
Timers can be cancelled. To reschedule a timer you cancel it and create a new one. Timer created in the rolledback transaction scope will get uncreated.
Web Services
WIth JAX-RPC there is a lot to define (WSDL, JAX_RPC mapping file and webservices.xml). with JAX-WS all you need is @WebService and @WebMethod annotations.
When there is no @WebMethod annotation - all methods of bean annotated with @WebService are exposed.
@SOAPBinding annotation allows you to customize WS: style: DOCUMENT/RPC, use: LITERAL/ENCODED(do not use), parameterStyle: BARE/WRAPPED.
@WebParam can be placed on parameters (with name and mode: IN/OUT/INOUT attributes). @WebResult is the same for return value.
@OneWay annotation for methods that do not return response allows server to call it asynchronously (if it wishes to).
@WebService annotation has endpointInterface attribute, that allows to separate interface from implementation. We plece @WebService annotation on both the interface and the implementation then.
There is a @WebServiceRef that allows to inject a service class or an endpoint (the annotation would take the service class as an argument then).
A timer is associated with the bean that created it and it calls it's ejbTimeout(Timer timer)/@Timeout method when it goes off.
Since EJB 3.1 there is a ScheduleExpression class that allows to define when timer should be fired. There is also @Schedule annotation, that alows to achieve the same in a declarative manner.
EJB must implement TimedObject interface to use Timer Service.
TimerService can be accessed with sessionContext.getTimerService() method. You can create a timer with timerService.createXxxTimer() call (it can create SingleAction, Interval ands Calendar timers).
Alternatively, you can do it in declarative manner with @Schedule annotation:
Timers are persistent - they will be restored if the system crashes. It isn't clear what will happen with the interval timers that would go off several times while the system is down (they may catch up just after the startup).
Timers can be cancelled. To reschedule a timer you cancel it and create a new one. Timer created in the rolledback transaction scope will get uncreated.
Web Services
WIth JAX-RPC there is a lot to define (WSDL, JAX_RPC mapping file and webservices.xml). with JAX-WS all you need is @WebService and @WebMethod annotations.
When there is no @WebMethod annotation - all methods of bean annotated with @WebService are exposed.
@SOAPBinding annotation allows you to customize WS: style: DOCUMENT/RPC, use: LITERAL/ENCODED(do not use), parameterStyle: BARE/WRAPPED.
@WebParam can be placed on parameters (with name and mode: IN/OUT/INOUT attributes). @WebResult is the same for return value.
@OneWay annotation for methods that do not return response allows server to call it asynchronously (if it wishes to).
@WebService annotation has endpointInterface attribute, that allows to separate interface from implementation. We plece @WebService annotation on both the interface and the implementation then.
There is a @WebServiceRef that allows to inject a service class or an endpoint (the annotation would take the service class as an argument then).
Subskrybuj:
Posty (Atom)