J2ee Project

Transkrypt

J2ee Project
J2EE Project
PRZEMYSŁAW SOŁTAN
e-mail: [email protected]
(1.1 RC2– build 03.01.2005)
Dokumentacja
Proces tworzenia niniejszego dokumentu zrealizowano przy użyciu darmowego
oprogramowania OpenOffice – http://www.openoffice.org .
Historia projektu
✔
✔
✔
✔
✔
✔
✔
✔
✔
✔
✔
✔
✔
03.01.2005 – opublikowanie wersji 1.1 RC2 (relase candidate)– http://j2ee.ie.tu.koszalin.pl;
03.01.2005 – dodanie przykładu na kod klienta komunikatów JMS;
26.12.2004 – dodanie wstepnej wersji opisu EJB-QL;
16.12.2004 – opracowanie listy tematów projektu;
04.11.2004 – dodanie przykładu obsługi serwera LDAP oraz opis wykorzystania biblioteki log4j;
27.11.2004 – dodanie opisu przykładu komponentu ZoneFacadeBean zawierającego kod obsługi referencji do sesyjnego
komponentu ZoneBean;
20.11.2004 – dodanie opisu wykorzystania obiektu Properties oraz parametryzacji komponentów EJB;
16.11.2005 – dodanie przykładu komponentu entity bean CMP 2.0 oraz opisanie wzorca obiektu transferu danych DTO
(wersja wstępna);
06.11.2004 – aktualizacja kodu wzorca wyszukiwania usług – ServiceLocator o obsługę wyszukiwania lokalnych
komponentów EJB (metoda getLocalHome), zmiana nazwy JNDI komponentu fasady z ejb/FacadeBean na ejb/Facade,
dodanie opisu wzorca Singleton;
22.10.2004 - dołączenie dodatku na temat ciekawej biblioteki MockEJB http://www.mockejb.org (atrapy kontenera EJB) za
pomocą której można testować kod komponentów EJB bez użycia serwera J2EE;
05.10.2004 – umieszczenie przykładu realizacji wzorców delegata biznesowego i wyszukiwania usług.
04.10.2004 – opublikowanie wersji 1.0;
29.09.2004 – zainicjowanie projektu i ukończenie wersji 1.0 alpha niniejszej dokumentacji do wzorcowego projektu
realizowanego w technologii J2EE.
Plany rozwojowe
•
•
•
•
•
opis projektu przy użyciu serwera Apache Geronimo i platformy Eclipse
rozszerzenie projektu o nowe elementy platformy 1.4 (głównie WebServices) oraz stworzenie wzorcowej aplikacji cienkiego
klienta w JSF;
rozbudowa projektu o realizację klientów SOA (np. na platformie .NET);
rozszerzenie przykładów z wykorzystaniem wzorców projektowych J2EE;
implementacja projektu dla serwera JBOSS 4.0 – rozszerzenie opisu o XDoclet;
http://j2ee.ie.tu.koszalin.pl
-2-
Spis treści
I. Wstęp........................................................................................................................................... 7
1.1. Literatura.............................................................................................................................7
1.2. Oprogramowanie...............................................................................................................7
II. Serwer aplikacji J2EE.............................................................................................................. 8
2.1. Instalacja..............................................................................................................................8
2.2. Uruchomienie serwera......................................................................................................9
III. Sesyjny komponent EJB......................................................................................................12
3.1. Zaprojektowanie klasy SessionBean............................................................................. 12
3.1.1. Klasa komponentu sesyjnego EJB – FacadeBean.java..............................................................13
3.2. Zaprojektowanie interfejsu domowego........................................................................14
3.2.1. Interfejs domowy - FacadeHome.java...................................................................................... 14
3.3. Zaprojektowanie interfejsu zdalnego........................................................................... 14
3.3.1. Interfejs zdalny - Facade.java...................................................................................................14
3.4. Klasowy diagram UML...................................................................................................15
3.5. Tworzenie nowej aplikacji EAR.....................................................................................16
3.5.1. Deskryptor application.xml..................................................................................................... 17
3.5.2. Deskryptor sun-j2ee-ri.xml......................................................................................................17
3.6. Instalowanie komponentu EJB.......................................................................................17
3.7. Deskryptory......................................................................................................................21
3.7.1. Deskryptor application.xml..................................................................................................... 21
3.7.2. Deskryptor sun-j2ee-ri.xml......................................................................................................21
3.7.3. Deskryptor ejb-jar.xml............................................................................................................. 22
3.8. Deploy aplikacji EAR...................................................................................................... 22
IV. Komunikacja klienta z komponentem EJB..................................................................... 25
4.1. Przykład prostego klienta...............................................................................................25
4.1.1. Klasa klienta - SimpleClient.java.............................................................................................25
4.2. Wzorzec Singleton........................................................................................................... 28
4.2.1. Klasa wzorca singleton - Singleton.java................................................................................. 28
4.2.2. Klasa testowa - TestSingleton.java.......................................................................................... 28
4.3. Wzorzec Lokalizatora Usług.......................................................................................... 29
4.3.1. Klasa lokalizatora usługi – ServiceLocator.java.......................................................................30
4.3.2. Klasa wyjątków lokalizatora usługi – ServiceLocatorException.java...................................... 30
4.3.3. Zmodyfikowana klasa klienta - ServiceLocatorClient.java...................................................... 31
4.4. Klasa właściwości - Properties.......................................................................................32
4.4.1. Fragment kodu z klasy SimpleClient.java............................................................................... 32
4.4.2. Plik właściwości jndi.properies................................................................................................ 32
4.4.3. Zmodyfikowany fragment kodu z klasy SimpleClient.java..................................................... 32
4.5. Wzorzec Delegata Biznesowego....................................................................................33
4.5.1. Klasa delegata biznesowego – BusinessDelegate.java..............................................................34
4.5.2. Klasa klienta – BusinessDelegateClient.java........................................................................... 34
V. Referencje EJB ....................................................................................................................... 36
5.0.1. Klasa komponentu sesyjnego - ZoneBean.java........................................................................ 36
5.0.2. Interfejs domowy - ZoneHome.java......................................................................................... 37
5.0.3. Interfejs zdalny - Zone.java..................................................................................................... 37
5.0.4. Interfejs lokalny-domowy ZoneLocalHome.java......................................................................37
http://j2ee.ie.tu.koszalin.pl
-3-
5.0.5. Interfejs lokalny - ZoneLocal.java............................................................................................ 37
5.0.6. Klasa komponentu SessionBean - ZoneFacadeBean.java.........................................................38
5.0.7. Interfejs domowy - ZoneFacadeHome.java.............................................................................. 39
5.0.8. Interfejs zdalny - ZoneFacade.java.......................................................................................... 39
5.0.9. Klasa klienta – ZoneClient.java............................................................................................... 43
5.1. Wzorzec adaptera............................................................................................................ 44
5.1.1. Klasa adaptera SessionBeanAdapter.java................................................................................ 44
5.2. Parametryzacja komponentów EJB............................................................................... 45
5.2.1. Fragment kodu z klasy FacadeBean.java..................................................................................45
5.2.2. Zmodyfikowany fragment kodu z klasy FacadeBean.java........................................................45
5.3. Aplikacja webowa WAR.................................................................................................46
VI. Komponenty Entity EJB...................................................................................................... 47
6.1. Utrwalanie danych.......................................................................................................... 47
6.2. Komponenty CMP 2.X ................................................................................................... 47
6.2.1. Klasa komponetnu Entity EJB (CMP) – UserBean.java......................................................... 47
6.2.2. Interfejs zdalny - User.java......................................................................................................47
6.2.3. Interfejs domowy - UserHome.java..........................................................................................48
6.2.4. Interfejs lokalny - UserLocal.java............................................................................................ 48
6.2.5. Interfejs lokalny-domowy - UserLocalHome.java.................................................................... 48
6.3. GUID .................................................................................................................................49
6.3.1. Klasa Guid.java........................................................................................................................ 49
6.4. Wzorzec Obiektu Transferu Danych............................................................................ 51
6.4.1. Klasa do transferu danych użytkownika - UserData.java....................................................... 51
6.5.
6.6.
6.7.
6.8.
6.9.
Wzorzec Facade............................................................................................................... 53
Wzorzec Lokalizatora Usług.......................................................................................... 54
Relacje CMR......................................................................................................................55
Metody Finder i Select.................................................................................................... 56
EJB-QL............................................................................................................................... 56
6.9.1. Składnia zapytania EJB-QL..................................................................................................... 56
6.9.2. Przykładowe metody findXXX................................................................................................ 56
6.9.3. Przykładowe metody selectXxx i selectXxxInEntity............................................................... 56
VII. Transakcje............................................................................................................................ 58
7.1. Model ACID w komponentach EJB.............................................................................. 58
7.2. Wycofanie transakcji....................................................................................................... 58
7.3. Mapowanie metod komponentów EJB.........................................................................58
7.4. Poziomy izolacji transakcji............................................................................................. 59
7.4.1. Fragment desktyptora - ejb-jar.xml..........................................................................................59
VIII. JNDI..................................................................................................................................... 60
8.1. Interfejs Context............................................................................................................... 60
8.1.1. Fragment pliku – SimpleClient.java........................................................................................60
8.2. Interfejs DirContext......................................................................................................... 61
IX. Ldap......................................................................................................................................... 62
9.1. Konfiguracja serwera OpenLdap.................................................................................. 62
9.1.1. Plik konfiguracyjny serwera OpenLDAP - slap.conf.............................................................. 62
9.2. Aplikacja klienta - LdapBrowser................................................................................... 63
9.3. Komunikacja z serwerem............................................................................................... 64
9.3.1. Przykład prostego klienta – LdapClient.java........................................................................... 64
http://j2ee.ie.tu.koszalin.pl
-4-
X. Komunikaty JMS....................................................................................................................65
10.1. Konfiguracja JMS na serwerze J2EE RI.......................................................................65
10.2. Komponent MDB...........................................................................................................66
10.2.1. Klasa wzorca adaptera dla MDB – MessageDrivenBean.java...............................................66
10.2.2. Klasa komponentu MDB – LogBean.java.............................................................................. 66
10.3. Prosty klient wysyłający komunikaty JMS.................................................................68
10.4. ServiceLocator – rozszerzenie wyszukiwania o kolejki JMS................................... 69
XI. Web Services..........................................................................................................................70
11.1. AXIS................................................................................................................................. 70
XII. Autentykacja i Autoryzacja............................................................................................... 71
12.1. Role użytkowników...................................................................................................... 71
12.2. Komunikacja SSL........................................................................................................... 72
XIII. Testy jednostkowe.............................................................................................................73
13.1. JUnit................................................................................................................................. 73
13.2. Projekt Cactus – osadzanie testów jednostkowych na serwerze J2EE................... 75
XIV. Komponent?!.......................................................................................................................76
14.1. Projekt CUBA................................................................................................................. 76
XV. Log4j.......................................................................................................................................77
15.1. Poziomy rejestracji logów.............................................................................................77
15.2. Przekierowanie logów.................................................................................................. 77
15.3. Definiowanie wzorca ................................................................................................... 77
15.3.1. Kod klasy Log4jClient.java.................................................................................................... 78
15.3.2. Plik właściwości biblioteki log4j – log4j.properties................................................................78
XVI. ANT i MAVEN...................................................................................................................79
16.1. Ant................................................................................................................................... 79
16.1.1. Skrypt ANT'a z J2EE Project – build.xml............................................................................ 79
16.2. Maven.............................................................................................................................. 81
XVII. JBoss i XDoclet..................................................................................................................82
17.1. JBoss.................................................................................................................................82
17.2. XDoclet............................................................................................................................ 82
XVIII. Geronimo......................................................................................................................... 83
XIX. Atrapa EJB ? - MockEJB................................................................................................... 84
19.1. Aplikcja klienta.............................................................................................................. 84
19.1.1. Zmodyfikawana klasa klienta - SimpleMockClient.java........................................................84
XX. Systemy kontroli wersji - Cvs i Svn................................................................................. 86
20.1. CVS.................................................................................................................................. 86
20.2. SVN..................................................................................................................................86
20.2.1. Tworzenie repozytorium SVN...............................................................................................87
XXI. UML...................................................................................................................................... 88
21.1. Diagramy przypadków użycia.................................................................................... 88
XXII. Projekt.................................................................................................................................89
22.1. Założenia nazewnicze................................................................................................... 89
22.2. Diagram klas projektu...................................................................................................90
http://j2ee.ie.tu.koszalin.pl
-5-
22.3. Lista tematów................................................................................................................. 91
22.4. Zagadnienia podstawowe............................................................................................ 97
XXIII. Zasoby WWW.................................................................................................................. 98
XXIV. Schematy deskryptorów................................................................................................ 99
XXV. J2EE RI 1.3.1– poprawki i aktualizacje....................................................................... 104
25.1. Ścieżka do bazy Cloudscape...................................................................................... 104
25.1.1. Plik setenv.bat...................................................................................................................... 104
25.2. Bibiblioteka klienta CloudView.................................................................................105
25.2.1. Plik cloudview.bat................................................................................................................ 105
25.3. Obsługa serwera w Win98..........................................................................................105
25.4. Gramatyka sun-j2ee-ri_1_3.dtd..................................................................................105
http://j2ee.ie.tu.koszalin.pl
-6-
I.Wstęp
Niniejszy dokument stanowi opis szkieletu wzorcowego projektu J2EE
wykorzystywanego podczas zajęć z przedmiotu “Systemy Rozproszone” realizowanego
od 2002 roku w Politechnice Koszalińskiej na Wydziale Elektroniki i Informatyki.
W dalszym opisie zastosowano przyrostowy napływ wiedzy przyswajanej wraz z
rozbudową opisywanego projektu.
Uwaga! Aktualnie jako bazę projektową wykorzystano serwer J2EE RI 1.3.1 ze względu na
mniejsze wymagania sprzętowe komputerów w porównaniu z J2EE 1.4 bazującym na serwerze
SunOne. Z tego względu część platformy 1.4 nie jest poruszana w tym dokumencie.
Dokument nie zawiera opisu poszczególnych typów komponentów EJB
uzupełnienie moich wykładów dostępnych pod adresami:
i stanowi
http://kik.ie.tu.koszalin.pl/portal (jsp, servlet)
oraz http://kik.ie.tu.koszalin.pl/systemy (ejb, jndi, ldap, jms, web services)
Przemysław Sołtan
1.1. Literatura
Na polskim rynku dostępne są trzy wartościowe pozycje dotyczące poruszanych
zagadnień (wszystkie wydane przez http://helion.pl):
•
•
•
Ed Roman, Scott W. Ambler, Tyler Jewell, “Enterprise JavaBean”.
Deepak Alur, John Crupi, Dan Malks, “J2EE Wzorce projektowe – wydanie drugie”;
William Crawford, Jonathan Kaplan, “J2EE Stosowanie wzorców projektowych”;
Adresy internetowe z wartościowymi materiałami dotyczącymi J2EE:
• http://java.sun.com
• http://theservletside.com
• http://www.javapasion.com
1.2. Oprogramowanie
Wszelkie wymagane oprogramowanie jest dostępne na stronie domowej przedmiotu
“Systemy Rozproszone”
•
•
http://www.eclipse.org
http://jakarta.apache.org
http://j2ee.ie.tu.koszalin.pl
-7-
II.Serwer aplikacji J2EE
2.1. Instalacja
Serwer zainstalowano w katalogu d:\java\j2ee (można wybrać także lokalizację domyślną).
Po instalacji należy dołączyć zmienną środowiskową J2EE_HOME wskazującą jego
lokalizację.
Rys. 1. Ustawienie zmiennej środowiskowej J2EE_HOME (Windows 2000)
Dodatkowo w zmiennej PATH dopisano lokalizację katalogu %J2EE_HOME%\bin
serwera w celu łatwiejszego uruchamiania znajdujących się tam skryptów.
Rys. 2. Dodanie ścieżki przeszukiwania katalogu %J2EE_HOME%\bin
http://j2ee.ie.tu.koszalin.pl
-8-
Uwaga! Do prawidłowej pracy serwera aplikacji J2EE RI 1.3.1 wymagana jest poprawka
dostępna na stronie autora. Umieszczono w niej poprawną biblioteką kliencką do obsługi bazy
Cloudscape (IBM) oraz wsparcie w uruchamianiu serwera na systemie Windows98.
Uwaga! Występują problemy przy uruchamianiu serwera przy pomocy javy 1.5. Podczas
projektowania wykorzystywano java 1.4.1_2 sdk. W przypadku instalacji dwóch wersji java
programy należy uruchamiać z poziomu katalogu bin javy 1.4.
Od tego momentu można z konsoli DOS wywoływać poszczególne skrypty wymagane
przez serwer.
Info! Serwer można również uruchamiać z poziomu innych systemów operacyjnych np.
Linux'a (ze strony www.java.sun.com dostępne są odpowiednie wersje instalacyjne)
2.2. Uruchomienie serwera
Pierwszym etapem jest uruchomienie serwera baz danych. W implementacji J2EE RI
1.3.1 zastosowano serwer Cloudscape (w wersji J2EE 1.4 zmieniono serwer aplikacji na
SunOne, a serwer baz danych na PointBase).
Otwieramy konsolę DOS (w Windows2000 jest to polecenie cmd.exe) i wpisujemy:
cloudscape – start
Rys. 3. Konsola dos z uruchomionym serwerem bazy danych Cloudscape
Po otwarciu kolejnej konsoli wpisujemy:
j2ee -verbose
i następuje uruchomienie serwera aplikacyjnego J2EE.
Info! Podczas uruchamiania serwera wyświetlane zostają informacje o dowiązaniach źródeł baz
danych (Binding DataSource) oraz kolejek i fabryk komunikatów (Binding: < JMS). W dalszej
części projektu będziemy wykorzystywali źródło bazy danych CloudscapeDB powiązanego
nazwą jdbc/Cloudscape w celu utrwalania komponentów Entity Bean.
http://j2ee.ie.tu.koszalin.pl
-9-
Rys. 4. Konsola dos z uruchomionym serwerem aplikacyjnym J2EE
Serwer udostepnia testową stronę www pod adresem http://localhost:8000
Rys. 5. Strona startowa serwera J2EE
Do zarządzania serwerem wykorzystuje się aplikację grubego klienta uruchomienie
programu:
deploytool
http://j2ee.ie.tu.koszalin.pl
-10-
Rys. 6. Deploytool – program do zarządzania serwerem J2EE RI 1.3.1
Dla ułatwienia pracy z serwerem można stworzyć odnośniki na pulpicie do najczęściej
używanych skryptów wraz z wymaganymi parametrami.
Rys. 7. Przykładowy folder ze standardowymi skrótami do obsługi serwera J2EE
http://j2ee.ie.tu.koszalin.pl
-11-
III.Sesyjny komponent EJB
Zadanie:
• zaprojektować komponent sesyjny SessionBean składający się z trzech plików źródłowych
(dwóch interfejsów – domowego FacadeHome i zdalnego Facade oraz klasy FacadeBean)
• wywołać
przykładową metodę biznesową test() komponentu sesyjnego
FacadeBean za pomocą klasy klienta i usługi JNDI.
3.1. Zaprojektowanie klasy SessionBean
Jako środowisko projektowe wykorzystano darmową platformę Eclipse. Stworzono
przykładowy projekt j2ee_project i dodano bibliotekę j2ee.jar zawierającą niezbedne
klasy i interfejsy dla platformy J2EE.
Info! Projekt j2ee_project to w rzeczywistości zestaw projektów j2ee_projectX, gdzie X określa
numer projektu. Zastosowano numerację przyrostową liczoną od zera w celu porównywania
zmian pomiędzy poszczególnymi fazami rozwijanego projektu.
Uwaga! Biblioteka j2ee.jar jest dostępna w katalogu %J2EE_HOME%\lib zainstalowanego
serwera J2EE RI 1.3.1
Rys. 8. Pusty projekt JAVA z dołączoną biblioteką J2EE
Info! Dla platformy Eclipse istnieje kilka projektów wspierających tworzenie aplikacji w J2EE:
(darmowe Lomboz i JBoss-IDE, czy też komercyjne projekty Omondo ze wsparciem UML,
MyEclipse). W ramach zajęć będziemy jednak korzystać ze standardowych narzędzi Eclipse.
http://j2ee.ie.tu.koszalin.pl
-12-
Klasa FacadeBean budowana jest na podstawie interfejsu SessionBean zawartego w
bibliotece javax.ejb.SessionBean.
Rys. 9. Hierarchia klas i interfejsów dla klasy FacadeBean (
- klasa,
-interfejs)
Ze względu na zastosowanie interfejsu w klasie muszą zostać zadeklarowane wszystkie
metody z nim związane (metody z ramki):
setSessionContext(SessionContext),ejbRemote(),ejbActivate(),ejbPasivate().
Info! Dla lepszego zaobserwowania kolejności wywołana metod w projekcie w niektórych
miejscach dodano kod wysyłania komunikaty na System.out:
np. System.out.println("[INFO] FacadeUserBean: ejbRemove()");
3.1.1. Klasa komponentu sesyjnego EJB – FacadeBean.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package systemy.session;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
public class FacadeBean implements SessionBean {
public FacadeBean(){}
public void ejbCreate() {
System.out.println("[INFO] FacadeUserBean: ejbCreate()");
}
public void ejbActivate() {
System.out.println("[INFO] FacadeUserBean: ejbActivate()");
}
public void ejbPassivate() {
System.out.println("[INFO] FacadeUserBean: ejbPassivate()");
}
public void ejbRemove() {
System.out.println("[INFO] FacadeUserBean: ejbRemove()");
}
public void setSessionContext(SessionContext ctx) {
System.out.println("[INFO] FacadeBean: setEntityContext(SessionContext "+ctx+")");
}
//======================================================================
//metoda biznesowa test()
//======================================================================
public String test() {
System.out.println("[INFO] FacadeBean: test()");
return "test";
}
//======================================================================
}
Dodatkowo w klasie zdefiniowano jedną testową metodę biznesową test(), której
wywołanie powoduje zwrócenie obiektu Stringg zawierajacego tekst “test”.
Info! W dalszych etapach projektowania będziemy dodawać do klasy FacadeBean inne metody
bisnesowe podobne jak przykładowa metoda test().
http://j2ee.ie.tu.koszalin.pl
-13-
3.2. Zaprojektowanie interfejsu domowego
Rys. 10. Hierarchia interfejsów dla interfejsu domowego FacadeHome
3.2.1. Interfejs domowy - FacadeHome.java
40
41
42
43
44
45
46
47
48
49
50
package systemy.session;
import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.ejb.EJBHome;
public interface FacadeHome extends EJBHome {
Facade create() throws RemoteException, CreateException;
}
W interfejsie domowym umieszczono metodę Facade create() która będzie zdalnie
wywoływana przez kod klienta.
3.3. Zaprojektowanie interfejsu zdalnego
Rys. 11. Hierarchia interfejsów dla interfejsu zdalnego Facade
3.3.1. Interfejs zdalny - Facade.java
51
52
53
54
55
56
57
58
59
60
package systemy.session;
import java.rmi.RemoteException;
import javax.ejb.EJBObject;
public interface Facade extends EJBObject {
public String test() throws RemoteException;
//test
}
W interfejsie zdalnym umieszczono metodę biznesową String test() wywoływaną
zdalnie przez klienta.
Info! W interfejsie zdalnym umieszcza się deklaracje metod biznesowych zawartych w klasie
komponentu EJB.
Nie jest konieczne umieszczanie deklaracji dla wszystkich metod biznesowych – część z nich
może być dostępna prywatnie w obszarze komponentu lub udostępniona przy pomocy interfejsu
lokalnego (omówienie interfejsów lokalnych zostanie dokonane w dalszej części projektu) innym
klientom uruchamianym przy pomocy jej samej maszyny wirtualnej JAVA.
http://j2ee.ie.tu.koszalin.pl
-14-
3.4. Klasowy diagram UML
Zaprojektowano trzy pliki (interfejs domowy, interfejs zdalny oraz klasę komponentu).
Pomiędzy interfejsami FacadeHome i Face istnieje zależność <<use>> ponieważ metoda
create() zadeklarowana w interfejsie FacadeHome zwraca obiekt zdalny budowany na
podstawie interfejsu zdalnego Facade.
Reszta zależności nie jest realizowana na poziomie kodu, ale opisywana przy
pomocy dodatkowych plików XML – deskryptorów.
Rys. 12. Diagram UML przedstawiający zaprojektowany komponent EJB (Omondo)
Rys. 13. Widok drzewa projektu (Eclipse IDE)
Uwaga! Komponet został nazwany FacadeBean (w wykładzie WitajBean) ponieważ w
dalszej części opisu na jego bazie będzie realizowany wzorzec Fasady (Facade).
Proces projektowania klas jest zakończony. Reszta operacji instalacji komponentu polega
na jego konfiguracji przy pomocy deskryptorów. W przypadku serwera J2EE RI
wykorzystuje się do tego celu program Deploytool.
Info! W przypadku innych serwerów (np. JBOSS) proces generacji deskryptorów i plików Java
wraz z instalacją całej aplikacji może być przyspieszony przez użycie narzędzi Xdoclet oraz
Ant. Niestety dla serwera J2EE RI 1.3.1 brak jest wtyczki umożliwiającej takie rozwiązanie.
http://j2ee.ie.tu.koszalin.pl
-15-
3.5. Tworzenie nowej aplikacji EAR
Proces instalacji polega na stworzeni aplikacji EAR. W tym celu wybieramy z menu
File→New→Application i podajemy nazwę archiwum ear np. systemy.ear.
Rys. 14. Tworzenie nowej aplikacji - archiwum EAR (Deploytool)
Rys. 15. Aplikacja EAR i jej desktyptory (Deploytool)
Aplikacja EAR posiada dwa deskryptory: standardowy application.xml or deskryptor
określonego serwera – dla J2EE RI jest to sun-j2ee-ri.xml (w dodatkowym deskryptorze
można deklarować specyficzne właściwości serwera J2EE udostepnione przez danego producenta).
http://j2ee.ie.tu.koszalin.pl
-16-
3.5.1. Deskryptor application.xml
61
62
63
64
65
66
67
68
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE application PUBLIC '-//Sun Microsystems, Inc.//DTD J2EE Application 1.3//EN'
'http://java.sun.com/dtd/application_1_3.dtd'>
<application>
<display-name>systemy</display-name>
<description>Application description</description>
</application>
3.5.2. Deskryptor sun-j2ee-ri.xml
69
70
71
72
73
74
75
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE j2ee-ri-specific-information PUBLIC '-//Sun Microsystems Inc.//DTD J2EE Reference
Implementation 1.3//EN' 'http://localhost:8000/sun-j2ee-ri_1_3.dtd'>
<j2ee-ri-specific-information>
<rolemapping />
</j2ee-ri-specific-information>
Oba deskryptory są budowane zgodnie z gramatyką zawartą w ich dokumentach DTD.
3.6. Instalowanie komponentu EJB
Proces instalacji komponentu EJB polega na mapowaniu zaprojektowanych klas w
wyniku czego powstaje deskryptor rozmieszczenia. W tym celu wykorzystuje się
wizarda New Enterprise Bean Wizard wywoływany z menu File→New→Enterprise
Bean.
Rys. 16. Enterprise Bean Wizard (Deploytool)
W procesie mapowania komponentu dokonuje się wyboru plików java, które mają
wchodzić w skład naszego komponentu. W tym przypadku będą to: Facade.class,
FacadeHome.class oraz FacadeBean.class.
http://j2ee.ie.tu.koszalin.pl
-17-
Uwaga! Należy pamiętać, że dodajemy skompilowany kod naszych klas (bytecode) *.class, a
nie ich źródła *.java.
Rys. 17. Dodawanie plików klas komponentu EJB (Deploytool)
Dodane pliki muszą mieć zachowaną hierarchię pakietów w postaci odpowiednich
katalogów (np. systemy.session.Facade.class).
Rys. 18. Wizard tworzący mapowanie komponentu EJB (Deploytool)
http://j2ee.ie.tu.koszalin.pl
-18-
W przykładzie zamapowano komponet sesyjny jako stanowy – Stateful. Taki komponent
będzie mógł reprezentować kod klienta na serwerze J2EE (każdy klient będzie posiadał
własną instancję tego komponentu).
Info! W przykładzie jest wywoływana prosta metoda test() dla której wystarczy zastosować
komponent sesyjny bezstanowy – Stateless, ale ze względu na rozbudowę projektu w dalszej
części zastosowano odpowiednik stanowy Stateful.
Dalsze ustawienia Wizarda pozostawiamy jako domyśle. Są to głównie opcje dotyczące
transakcji, konfigurowania parametrów uzytkownika, referencji do innych
komponentów EJB, czy zasobów określanych przez nazwy JNDI oraz bezpieczeństwa.
Do tych elementów powrócimy w dalszym opisie projektu.
Rys. 19. Mapowanie klas komponentu FacadeBean (Deploytool)
Uwaga! Należy zwrócić uwagę, żę mapowanie klas komponentów dotyczy nie tylko nazwy
klas, ale całej hierarchi pakietów. Ma to szczególne znaczenie podczas definiowania referencji
do innych komponentów EJB. Problem ten zostanie omówiony podczas opisu wzorca Fasady
Sesji.
Ostatnią operacją przed umieszczeniem całego kodu aplikacji EAR na serwerze jest
nadanie naszemu komponentowi nazwy JNDI. Gdy zapomnimy to zrobić to program
deploytool przypomni nam o tym podczas wywoływania opcji deploy.
http://j2ee.ie.tu.koszalin.pl
-19-
Rys. 20. Wiązanie komponentu z nazwą JNDI (Deploytool)
Nazwa JNDI może być dowolna, ale warto zastosować dodatkowe konteksty dla
różnych typów zasobów w celu łatwiejszej ich identyfikacji (np. ejb/FacadeBean). W ten
sposób na serwerze zdefiniowane są również inne zasoby np. źródła baz danych (np.
jdbc/Cloudscape), czy też kolejki komunikatów (np. jms/Topic).
Dodatkowo poprawność ustawień oraz kod java można sprawdzić przy pomocy
weryfikatora (Verifier) poprzez wybór z menu opcji Edit→Verifer...
Rys. 21. Weryfikacja komponentu (Deploytool – Verifier)
http://j2ee.ie.tu.koszalin.pl
-20-
3.7. Deskryptory
3.7.1. Deskryptor application.xml
76
77
78
79
80
81
82
83
84
85
86
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE application PUBLIC '-//Sun Microsystems, Inc.//DTD J2EE Application 1.3//EN'
'http://java.sun.com/dtd/application_1_3.dtd'>
<application>
<display-name>systemy</display-name>
<description>Application description</description>
<module>
<ejb>ejb-jar-ic.jar</ejb>
</module>
</application>
Deskryptor application.xml zawiera informację, że w aplikacji występuje dodatkowy
moduł ejb-jar-ic.jar
3.7.2. Deskryptor sun-j2ee-ri.xml
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE j2ee-ri-specific-information PUBLIC '-//Sun Microsystems Inc.//DTD J2EE Reference
Implementation 1.3//EN' 'http://localhost:8000/sun-j2ee-ri_1_3.dtd'>
<j2ee-ri-specific-information>
<rolemapping />
<enterprise-beans>
<module-name>ejb-jar-ic.jar</module-name>
<unique-id>0</unique-id>
<ejb>
<ejb-name>FacadeBean</ejb-name>
<jndi-name>ejb/FacadeBean</jndi-name>
<ior-security-config>
<transport-config>
<integrity>supported</integrity>
<confidentiality>supported</confidentiality>
<establish-trust-in-target>supported</establish-trust-in-target>
<establish-trust-in-client>supported</establish-trust-in-client>
</transport-config>
<as-context>
<auth-method>username_password</auth-method>
<realm>default</realm>
<required>false</required>
</as-context>
<sas-context>
<caller-propagation>supported</caller-propagation>
</sas-context>
</ior-security-config>
<gen-classes />
</ejb>
</enterprise-beans>
</j2ee-ri-specific-information>
Deskryptor sun-j2ee-ri.xml zawiera dodatkowe informacje. Najważniejszą z nich jest
mapowanie komponentu FacadeBean jako nazwa JNDI – ejb/FacadeBean. Reszta
informacji na razie nie jest istotna i dotyczy dodatkowych ustawień serwera
(bezpieczeństwo).
Wewnątrz archiwum ejb-jar-ir.jar znajduje się kolejny deskryptor zawierający więcej
informacji o przechowywanym komponencie EJB.
http://j2ee.ie.tu.koszalin.pl
-21-
3.7.3. Deskryptor ejb-jar.xml
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ejb-jar PUBLIC '-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN'
'http://java.sun.com/dtd/ejb-jar_2_0.dtd'>
<ejb-jar>
<display-name>SystemyEjb</display-name>
<enterprise-beans>
<session>
<display-name>FacadeBean</display-name>
<ejb-name>FacadeBean</ejb-name>
<home>systemy.session.FacadeHome</home>
<remote>systemy.session.Facade</remote>
<ejb-class>systemy.session.FacadeBean</ejb-class>
<session-type>Stateful</session-type>
<transaction-type>Bean</transaction-type>
<security-identity>
<description></description>
<use-caller-identity></use-caller-identity>
</security-identity>
</session>
</enterprise-beans>
<assembly-descriptor>
<method-permission>
...
</method-permission>
</assembly-descriptor>
</ejb-jar>
3.8. Deploy aplikacji EAR
Proces rozmieszczenia wywołyje się z menu: Tools→Deploy.
Rys. 22. Eksportowanie biblioteki jar dla aplikacji klienckiej
Podczas procesu rozmieszczania można wybrać opcję eksportowania kodu biblioteki
JAR służącej do zdalnego wywoływania komponentu.
http://j2ee.ie.tu.koszalin.pl
-22-
Podczas długotrwałego procesu rozmieszczania można przeglądać komunikaty
pojawiające się podczas tego procesu na konsoli serwera J2EE oraz programu
Deploytool.
Rys. 23. Konsola serwera J2EE RI
Na podstawie przygotowanego kodu java w procesie rozmieszczania następuje
generacja klas. Infrastruktura komunikacji zdalnego wywoływania kodu klienta
realizowana jest przy pomocy protokołu RMI-IIOP. W celu generacji wymaganego kodu
wykorzystuje się program rmic standardowo dostępny z JDK.
Info! Więcej informacji na temat RMI można odnaleźć na witrynie przedmiotu
“Programowanie dla Sieci” - http://java.ie.tu.koszalin.pl
Rys. 24. Konsola programu Deploytool
Rys. 25. Zakończenie rozmieszczania aplikacji (Deploytool – Deploy)
http://j2ee.ie.tu.koszalin.pl
-23-
Serwer aplikacji J2EE RI 1.3.1 na porcie 9191 udostępnia stronę WWW z której można
pobrać archiwum jar z klasami potrzebnymi aplikacjom klienckim do zdalnego
komunikowania się z komponentem EJB (stub'y dla komunikacji RMI-IIOP).
Rys. 26. Strona www udostępniająca kliencki kod dostępu do komponentu EJB
Rys. 27. Podgląd listy aplikacji EAR uruchomionych na serwerze (Deploytool – Deploy)
Po rozmieszczeniu aplikacji można ją odinstalować bez restartu serwera – opcja
Undeploy.
http://j2ee.ie.tu.koszalin.pl
-24-
IV.Komunikacja klienta z
komponentem EJB
Komponent EJB został zainstalowany na serwerze. Serwer ochrania komponent
stosując określone zasady bezpieczeństwa (różne poziomy ochrony transakcji oraz
autoryzację dostępu do metod komponentu za pomocą ról użytkowników).
W przypadku, gdy dla komponentu EJB zdefiniowano interfejsy: domowy i
zdalny (np. FacadeHome i Facade) można się z nim skomunikować przy pomocy
protokołu RMI-IIOP. W tym celu serwer udostępnia serwer nazewniczy JNDI
nasłuchujący na porcie 1050.
4.1. Przykład prostego klienta
Zaprezentowany prosty kod klienta realizuje komunikację z komponentem EJB.
Następuje wywołanie kodu komunikującego się z serwerem JNDI nasłuchującym na
porcie 1050. Serwer odnajduje komponent (referencję do obiektu domowego Home) poprzez
podanie nazwy JNDI (np. otrzymuję obiekt FacadeHome po podaniu nazwy
“ejb/FacadeBean”).
4.1.1. Klasa klienta - SimpleClient.java
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
package systemy.client;
import java.util.Properties;
import
import
import
import
import
javax.naming.Context;
javax.naming.InitialContext;
javax.rmi.PortableRemoteObject;
systemy.session.FacadeHome;
systemy.session.Facade;
public class SimpleClient {
public static void main(String[] args) {
Properties env = new Properties();
//J2EE RI 1.3.1
env.put("java.naming.factory.initial","com.sun.enterprise.naming.SerialInitContextFactory");
env.put("java.naming.provider.url", "iiop://localhost:1050");
try {
Context ctx = new InitialContext(env);
Object objref = ctx.lookup("ejb/FacadeBean"); //nazwa JNDI
FacadeHome home = (FacadeHome) PortableRemoteObject.narrow(objref,FacadeHome.class);
Facade w = home.create();
System.out.println(w.test()); //test
} catch (Exception e) {
System.err.println(e);
}
}
}
http://j2ee.ie.tu.koszalin.pl
-25-
Rys. 28. Pakiet aplikacji klienta i aplikacji J2EE
4.1.2.
Rys. 29. Diagram UML przedstawiający zaprojektowany komponent EJB (Omondo) z klasą
klienta
Info! Serwery aplikacyjne posiadają serwer nazw JNDI do którego dostęp realizowany jest przy
pomocy tzw. Fabryk. Dodatkowo każdy z serwerów posiada lokalizację i numer port na którym
działa usługa nazewnicza JNDI.
//JBoss
env.put("java.naming.factory.initial","org.jnp.interfaces.NamingContextFactory");
env.put("java.naming.provider.url","localhost:1099");
//SunOne 8
env.put("java.naming.factory.initial","com.sun.jndi.cosnaming.CNCtxFactory");
env.put("java.naming.provider.url", "iiop://localhost:3700");
Do przetestowania kodu klasy klienta stworzono nowy projekt j2ee_projectX_client. Do
prawidłowej pracy wymagana jest biblioteka j2ee.jar tak jak w przypadku poprzedniego
projektu oraz plik systemyClient.jar wygenerowany przez serwer J2EE w procesie
rozmieszczenia aplikacji (Deploy).
http://j2ee.ie.tu.koszalin.pl
-26-
Rys. 30. Klasa klienta wywołana z poziomu Eclipse IDE
Po wywołaniu kodu klienta na konsoli pojawia się wynik wywołania metody witaj()
komponentu EJB.
Rys. 31. Konsola serwera J2EE wyświetla komunikaty System.out zawarte w klasie FacadeBean
(wywołanie metod setEntityContext, ejbCreate oraz test)
Aplikacja klienta może zostać zrealizowana jako zwykła klasa Java lub też kod może
zostać umieszczony w aplikacji web'owej WAR (jako strona JSP, servlet, lub JavaBean).
Kod klienta może zostać wywołany zdalnie z innego komputera (innej wirtualnej
maszyny Java).
http://j2ee.ie.tu.koszalin.pl
-27-
4.2. Wzorzec Singleton
Podczas tworzenia projektów przy użyciu języka java istnieją sytuacje, w których
wymagana jest klasa na podstawie której będziemy można tworzyć tylko pojedynczy
obiekt. W tym celu można skorzystać z wzorca projektowego singleton.
4.2.1. Klasa wzorca singleton - Singleton.java
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
public class Singleton {
private static Singleton instance;
static {
instance = new Singleton();
}
public static Singleton getInstance() {
return instance;
}
private String test;
public String getTest() {
return test;
}
public void setTest(String test) {
this.test = test;
}
}
4.2.2. Klasa testowa - TestSingleton.java
207
208
209
210
211
212
213
214
215
216
217
public class TestSingleton {
public static void main(String[] args) {
Singleton s1 = Singleton.getInstance();
s1.setTest("test");
}
}
Singleton s2 = Singleton.getInstance();
System.out.println(s2.getTest());
W przykładzie metody setTest(String test) i getTest() wykonywane są na tej samej
instancji klasy Singleton.java mimo, że nie zostały zdefiniowane jako statyczne.
Zaprezentowany wzorzec zostanie użyty przy projektowaniu lokalizatora usług
(ServiceLocator).
http://j2ee.ie.tu.koszalin.pl
-28-
4.3. Wzorzec Lokalizatora Usług
Budowa kodu prostego klienta SimpleClient.java obarczona była koniecznością
znajomości obsługi lokalizowania usług przy pomocy JNDI. Aby dokonać izolacji klienta
od problemów z obsługą JNDI stosuje się wzorzec lokalizatora usług (Service Locator).
http://j2ee.ie.tu.koszalin.pl
-29-
4.3.1. Klasa lokalizatora usługi – ServiceLocator.java
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
package systemy.client;
import
import
import
import
import
import
import
import
java.util.Collections;
java.util.HashMap;
java.util.Map;
java.util.Properties;
javax.ejb.EJBHome;
javax.naming.InitialContext;
javax.naming.NamingException;
javax.rmi.PortableRemoteObject;
public class ServiceLocator {
private InitialContext initialContext;
private Map cache;
private static ServiceLocator instance;
static {
try {
}
instance = new ServiceLocator();
}catch(ServiceLocatorException e){
System.err.println(e);
}
public static ServiceLocator getInstance() {
System.out.println(" ServiceLocator: getInstance()");
return instance;
}
public ServiceLocator() throws ServiceLocatorException {
System.out.println(" ServiceLocator: konstruktor ServiceLocator()");
Properties env = new Properties(); //kod mozna przeniesc do pliku properties
//J2EE RI 1.3.1
env.put("java.naming.factory.initial","com.sun.enterprise.naming.SerialInitContextFactory");
env.put("java.naming.provider.url", "iiop://localhost:1050");
try {
}
}
initialContext = new InitialContext(env);
cache = Collections.synchronizedMap(new HashMap());
}catch(NamingException e){
throw new ServiceLocatorException(e);
}catch(Exception e){
throw new ServiceLocatorException(e);
}
Występowanie wyjątków NamingException związanych z obsługą JNDI zostało przejęte
w klasie ServiceLocator w ten sposób, że ich wystąpienie powoduje wywołanie nowych
wyjątków ServiceLocatorException zdefiniowanych przy pomocy własnej klasy. W ten
sposób klient nie musi importować obsługi javax.naming.NamingException.
Podobna sytuacja dotyczy komunikacji przy pomocy RMI. Klasa ServiceLocator jest dla
klienta widziana jako klasa lokalna i klient nie potrzebuje importować
javax.rmi.PortableRemoteObject.
4.3.2. Klasa wyjątków lokalizatora usługi – ServiceLocatorException.java
270
271
272
273
274
275
276
277
package systemy.client;
public class ServiceLocatorException extends Exception {
public ServiceLocatorException(Throwable t) {
super(t);
}
}
http://j2ee.ie.tu.koszalin.pl
-30-
4.3.3. Zmodyfikowana klasa klienta - ServiceLocatorClient.java
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
package systemy.client;
import systemy.session.Facade;
import systemy.session.FacadeHome;
import systemy.util.ServiceLocator;
public class ServiceLocatorClient {
public static void main(String[] args) {
try {
FacadeHome home =
(FacadeHome) ServiceLocator.getInstance().getRemoteHome("ejb/Facade", FacadeHome.class)
Facade facade = home.create();
//mamy obiekt domowy wiec tworzymy obiekt zdalny
String str = facade.test();
System.out.println(str);
}
}
} catch (Exception e) {
System.err.println(e);
}
Z klasy klienta usunięto kod komunikacji z serwerem JNDI, który został przeniesiony do
klasy lokalizatora usług ServiceLocator.
http://j2ee.ie.tu.koszalin.pl
-31-
4.4. Klasa właściwości - Properties
Podczas projektowania kodu klienta SimpleClient.java oraz lokalizatora usług
ServiceLocator.java zastosowano klasę Properties.
Rys. 32. Hierarchia klas i interfejsów oraz lista publicznych metod dla klasy Properties
Klasa Properties udostępnia metody ładowania, pobierania, wyświetlania oraz zapisu
zawartych danych przechowywanych w obiekcie w postaci par klucz=wartość.
4.4.1. Fragment kodu z klasy SimpleClient.java
303
304
305
306
307
Properties env = new Properties();
//J2EE RI 1.3.1
env.put("java.naming.factory.initial","com.sun.enterprise.naming.SerialInitContextFactory");
env.put("java.naming.provider.url", "iiop://localhost:1050");
Umożliwia ona przechowywanie danych w postaci klucza i jego wartości. Stosowanie w
kodzie java danych konfiguracyjnych utrudnia ich modyfikację, ponieważ przy ich
zmianie należy ponownie skompilować kod java.
Z tego względu zawartośc obiektu env klasy Properties, zamiast wypełniać przy
pomocy metody put(klucz,wartość), można pobrać z zewnętrznego pliku.
4.4.2. Plik właściwości jndi.properies
308
309
310
311
312
#==============================================================
#J2EE RI 1.3.1
#==============================================================
java.naming.factory.initial=com.sun.enterprise.naming.SerialInitContextFactory
java.naming.provider.url=iiop://localhost:1050
4.4.3. Zmodyfikowany fragment kodu z klasy SimpleClient.java
313
314
315
316
317
318
319
320
321
Properties env = new Properties();
try {
env.load(new FileInputStream("systemy/client/jndi.properties"));
} catch (IOException e) {
System.err.println(e);
}
http://j2ee.ie.tu.koszalin.pl
-32-
4.5. Wzorzec Delegata Biznesowego
Celem stosowania wzorca delegata biznesowego jest izolacja kodu klienta od
konieczności obsługi kodu związanego z daną technologią. W rozpatrywanym
przypadku izolacji poddana zostanie odsługa komponentów EJB w ten sposób, że klient
nie będzie miał pojęcia o technologicznych aspektach zahermetyzowanych operacji.
Wzorzec delegata biznesowego przypomina współpracę klienta i maklera giełdowego. Klienta
interesuje dokonywanie podstawowych operacji biznesowych, a makler jest pośrednikem, który
zna szczegóły dokonywania operacji.
Rys. 33. Diagram UML aplikacji klienta wykorzystującej wzorzec Delegata Biznesowego i
Lokalizatora Usługi
http://j2ee.ie.tu.koszalin.pl
-33-
4.5.1. Klasa delegata biznesowego – BusinessDelegate.java
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
package systemy.client;
import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.resource.ResourceException;
import systemy.session.Facade;
import systemy.session.FacadeHome;
public class BusinessDelegate {
private Facade facade;
public BusinessDelegate() throws ResourceException {
System.out.println(" BusinessDelegate: konstruktor BusinessDelegate()");
try {
FacadeHome home = (FacadeHome) DelegateServiceLocator.getInstance()
.getRemoteHome("ejb/FacadeBean", FacadeHome.class);
//mamy obiekt domowy wiec tworzymy obiekt zdalny
facade = home.create();
} catch (DelegateServiceLocatorException e) {
throw new ResourceException("Error: DelegateServiceLocatorException");
}catch(CreateException e){
throw new ResourceException("Error: Ejb CreateException");
}catch(RemoteException e){
throw new ResourceException("Error: Ejb RemoteException");
}
}
//========================================================================================
// metody biznesowe
//========================================================================================
public String getTest() throws ResourceException {
System.out.println(" BusinessDelegate: getTest()");
try {
return facade.test(); //wywolanie metody biznesowej w fasadzie
}catch (RemoteException e){
throw new ResourceException(e.toString());
}
}
//========================================================================================
}
4.5.2. Klasa klienta – BusinessDelegateClient.java
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
package systemy.client;
import javax.resource.ResourceException;
public class Client {
public static void main(String[] args) {
System.out.println("Client: main(String[] args)");
try {
BusinessDelegate delegate = new BusinessDelegate();
System.out.println(delegate.getTest());
//pośrednie wywolanie metody test() komponentu FasadyBean
}
}
}catch (ResourceException e) {
System.err.println(e);
}
http://j2ee.ie.tu.koszalin.pl
-34-
Rys. 34. Konsola klienta z dodatkowymi komunikatami podczas wywołania metody
test() komponentu FacadeBean
http://j2ee.ie.tu.koszalin.pl
-35-
V.Referencje EJB
5.0.1. Klasa komponentu sesyjnego - ZoneBean.java
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
package systemy.session.zone;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.TimeZone;
import
import
import
import
import
javax.ejb.EJBException;
javax.ejb.SessionBean;
javax.ejb.SessionContext;
javax.naming.InitialContext;
javax.naming.NamingException;
public class ZoneBean implements SessionBean {
private static final long serialVersionUID = 3L;
private SessionContext context = null;
//======================================================================
//metoda biznesowa getTimeZoneString
//======================================================================
private String getTimeZoneString(String zone) {
System.out.println("ZoneBean: getTimeZoneString()");
Calendar cal = new GregorianCalendar(TimeZone.getTimeZone(zone));
return cal.get(Calendar.HOUR_OF_DAY)+":"+cal.get(Calendar.MINUTE);
}
//======================================================================
//metoda biznesowa getLocalTimeString
//======================================================================
public String getLocalTimeZoneString() {
System.out.println("ZoneBean: getLocalTimeZoneString()");
Calendar cal = new GregorianCalendar();
return cal.get(Calendar.HOUR_OF_DAY)+":"+cal.get(Calendar.MINUTE);
}
//======================================================================
//metoda biznesowa getPolandTimeZoneString
//======================================================================
public String getPolandTimeZoneString() {
}
System.out.println("ZoneBean: getPolandZoneTimeString()");
return getTimeZoneString("Europe/Warsaw");
public String getContextTimeZoneString() {
System.out.println("ZoneBean: getContextTimeZoneString()");
String timeZone = null;
try {
InitialContext initialContext = new InitialContext();
timeZone = (String) initialContext.lookup("java:comp/env/timeZone");
System.out.println("java:comp/env/timeZone=" + timeZone);
}
} catch (NamingException e) {
throw new EJBException(e);
}
return getTimeZoneString(timeZone);
//======================================================================
public void ejbCreate() {
System.out.println("ZoneBean: ejbCreate()");
}
public void ejbRemove() {
System.out.println("ZoneBean: ejbRemove()");
}
public void ejbActivate() {
System.out.println("ZoneBean: ejbActivate()");
http://j2ee.ie.tu.koszalin.pl
-36-
468
469
470
471
472
473
474
475
476
477
478
479
}
public void ejbPassivate() {
System.out.println("ZoneBean: ejbPassivate()");
}
public void setSessionContext(SessionContext ctx) {
System.out.println("ZoneBean: setEntityContext(ctx)");
context = ctx;
}
//======================================================================
}
5.0.2. Interfejs domowy - ZoneHome.java
480
481
482
483
484
485
486
487
488
489
package systemy.session.zone;
import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.ejb.EJBHome;
public interface ZoneHome extends EJBHome {
Zone create() throws RemoteException, CreateException;
}
5.0.3. Interfejs zdalny - Zone.java
490
491
492
493
494
495
496
497
498
499
package systemy.session.zone;
import java.rmi.RemoteException;
import javax.ejb.EJBObject;
public interface Zone extends EJBObject {
//deklaracja wybranych metod biznesowych zdefiniowanych w klasie ZoneBean
public String getPolandTimeZoneString() throws RemoteException;
}
5.0.4. Interfejs lokalny-domowy ZoneLocalHome.java
500
501
502
503
504
505
506
507
508
package systemy.session.zone;
import javax.ejb.CreateException;
import javax.ejb.EJBLocalHome;
public interface ZoneLocalHome extends EJBLocalHome {
ZoneLocal create() throws CreateException;
}
5.0.5. Interfejs lokalny - ZoneLocal.java
509
510
511
512
513
514
515
516
517
518
package systemy.session.zone;
import javax.ejb.EJBLocalObject;
public interface ZoneLocal extends EJBLocalObject {
//deklaracja wybranych metod biznesowych zdefiniowanych w klasie ZoneBean
public String getLocalTimeZoneString();
public String getContextTimeZoneString();
}
http://j2ee.ie.tu.koszalin.pl
-37-
5.0.6. Klasa komponentu SessionBean - ZoneFacadeBean.java
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
package systemy.session.zone;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.TimeZone;
import
import
import
import
import
javax.ejb.EJBException;
javax.ejb.SessionBean;
javax.ejb.SessionContext;
javax.naming.InitialContext;
javax.naming.NamingException;
public class ZoneBean implements SessionBean {
private static final long serialVersionUID = 3L;
private SessionContext context = null;
//======================================================================
//metoda biznesowa getTimeZoneString
//======================================================================
private String getTimeZoneString(String zone) {
System.out.println("ZoneBean: getTimeZoneString()");
Calendar cal = new GregorianCalendar(TimeZone.getTimeZone(zone));
return cal.get(Calendar.HOUR_OF_DAY)+":"+cal.get(Calendar.MINUTE);
}
//======================================================================
//metoda biznesowa getLocalTimeString
//======================================================================
public String getLocalTimeZoneString() {
System.out.println("ZoneBean: getLocalTimeZoneString()");
Calendar cal = new GregorianCalendar();
return cal.get(Calendar.HOUR_OF_DAY)+":"+cal.get(Calendar.MINUTE);
}
//======================================================================
//metoda biznesowa getPolandTimeZoneString
//======================================================================
public String getPolandTimeZoneString() {
System.out.println("ZoneBean: getPolandZoneTimeString()");
return getTimeZoneString("Europe/Warsaw");
}
//======================================================================
//metoda biznesowa getContextTimeZoneString
//======================================================================
public String getContextTimeZoneString() {
System.out.println("ZoneBean: getContextTimeZoneString()");
String timeZone = null;
try {
InitialContext initialContext = new InitialContext();
timeZone = (String) initialContext.lookup("java:comp/env/timeZone");
System.out.println("java:comp/env/timeZone="+timeZone);
}catch(NamingException e){
throw new EJBException(e);
}
return getTimeZoneString(timeZone);
}
//======================================================================
public void ejbCreate() {
System.out.println("ZoneBean: ejbCreate()");
}
public void ejbRemove() {
System.out.println("ZoneBean: ejbRemove()");
}
public void ejbActivate() {
System.out.println("ZoneBean: ejbActivate()");
}
public void ejbPassivate() {
System.out.println("ZoneBean: ejbPassivate()");
}
public void setSessionContext(SessionContext ctx) {
System.out.println("ZoneBean: setEntityContext(ctx)");
context = ctx;
}
}
http://j2ee.ie.tu.koszalin.pl
-38-
5.0.7. Interfejs domowy - ZoneFacadeHome.java
601
602
603
604
605
606
607
608
609
610
611
package systemy.session.zoneFacade;
import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.ejb.EJBHome;
public interface ZoneFacadeHome extends EJBHome {
ZoneFacade create() throws RemoteException, CreateException;
}
5.0.8. Interfejs zdalny - ZoneFacade.java
612
613
614
615
616
617
618
619
620
621
622
623
624
package systemy.session.zoneFacade;
import java.rmi.RemoteException;
import javax.ejb.EJBObject;
import javax.resource.ResourceException;
public interface ZoneFacade extends EJBObject {
//metody biznesowe ZoneFacade-->Zone
public String getServerTimeZoneString() throws RemoteException, ResourceException;
public String getApplicationTimeZoneString() throws RemoteException, ResourceException;
}
Rys. 35. Klasowy diagram UML komponentu ZoneBean
Na diagramie z rysunku 35 przedstawiono klasę ZoneBean implementującą interfejs
SessionBean. Klasa zawiera jedną metodę prywatną (getTimeZoneString) dostępną tylko
wewnątz klasy oraz trzy publiczne metody biznesowe (getLocalTimeZoneString,
getPolandTimeZoneString, getContextTimeZoneString), które mogą zostać zadeklarowane
w interfejsie zdalnym i lokalnym.
http://j2ee.ie.tu.koszalin.pl
-39-
Rys. 36. Klasowy diagram UML komponentu ZoneFacadeBean
Komponenty ZoneFacadeBean, którego diagram klas przedstawiono na rysunku 36, jest
“klientem” klasy komponentu ZoneBean. Ponieważ oba komponenty są tworzone w
ramach jednej wirtualnej maszyny javy to do komunikacji kodu ZoneFacadeBean z
komponentem ZoneBean wykorzystano jego interfejsy lokalne ZoneLocalHome i
ZoneLocal.
Rys. 37. Mapowanie klas komponentu sesyjnego ZoneBean
http://j2ee.ie.tu.koszalin.pl
-40-
Rys. 38. Mapowanie klas komponentu sesyjnego ZoneFacadeBean
Rys. 39. Mapowanie nazw JNDI dla komponentów ZoneBean i jego fasady ZoneFacadeBean
http://j2ee.ie.tu.koszalin.pl
-41-
Rys. 40. Mapowanie refernecji komponentu ZoneBean dla klas komponentu ZoneFacadeBean
http://j2ee.ie.tu.koszalin.pl
-42-
5.0.9. Klasa klienta – ZoneClient.java
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
package systemy.client;
import java.util.Properties;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.rmi.PortableRemoteObject;
import
import
import
import
systemy.session.zone.Zone;
systemy.session.zone.ZoneHome;
systemy.session.zoneFacade.ZoneFacade;
systemy.session.zoneFacade.ZoneFacadeHome;
public class ZoneClient {
public static void main(String[] args) {
Properties env = new Properties();
//J2EE RI 1.3.1
env.put("java.naming.factory.initial","com.sun.enterprise.naming.SerialInitContextFactory");
env.put("java.naming.provider.url", "iiop://localhost:1050");
//======================================================================
// bezpośrednia obsługa komponentu ZoneBean poprzez interfejsy zdalne
// ZoneHome i Zone
//======================================================================
try {
Context ctx = new InitialContext(env);
Object objref = ctx.lookup("ejb/Zone"); //nazwa JNDI
ZoneHome home = (ZoneHome) PortableRemoteObject.narrow(objref,ZoneHome.class);
Zone zone = home.create();
System.out.println(zone.getPolandTimeZoneString()+" <= Poland Time Zone");
} catch (Exception e) {
System.err.println(e);
}
//======================================================================
// pośrednia obsługa komponentu ZoneBean poprzez interfejsy lokalne
// ZoneLocalHome i ZoneLocal za pośrednictwem komponentu
// ZoneFacadeBean z interfejsami zdalnymi ZoneFacadeHome i ZoneFacade
//======================================================================
try {
Context ctx = new InitialContext(env);
Object objref = ctx.lookup("ejb/ZoneFacade"); //nazwa JNDI fasady
ZoneFacadeHome home = (ZoneFacadeHome) PortableRemoteObject.narrow
(objref,ZoneFacadeHome.class);
ZoneFacade zoneFacade = home.create();
System.out.println(zoneFacade.getApplicationTimeZoneString()+" <= Application Time Zone");
System.out.println(zoneFacade.getServerTimeZoneString()+" <= Server Time Zone");
}
}
} catch (Exception e) {
System.err.println(e);
}
//======================================================================
http://j2ee.ie.tu.koszalin.pl
-43-
5.1. Wzorzec adaptera
Tworząc klasy komponentów EJB programista jest zmuszony do implementacji
dodatkowych metod wymaganych przez interfejs SessionBean, EntityBean lub
MessageDrivenBean w zależności od typu komponentu. Aby usprawnić projektowanie
stosuje się odpowiednie klasy adaptacyjne dla każdego z typów komponentów.
Np. dla komponentów sesyjnych taka klasa będzie miała następującą postać:
5.1.1. Klasa adaptera SessionBeanAdapter.java
683
684
685
686
687
688
689
690
691
692
693
694
695
696
package project.adapter;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
public abstract class SessionBeanAdapter implements SessionBean {
protected SessionContext context = null;
public void setSessionContext(SessionContext ctx) { context = ctx;}
public void ejbActivate() {}
public void ejbPassivate() {}
public void ejbCreate() {}
public void ejbRemove() {}
}
Tak przygotowana klasa może być wykorzystana przez projektowany komponent
sesyjny.
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
package project.session;
import project.adapter.SessionBeanAdapter;
...
public class FacadeBean extends SessionBeanAdapter {
public void metodaBiznesowa1(...) {
...
}
public String metodaBiznesowa2(...) {
...
}
...
}
//nadpisanie metody ejbCreate z klasy rodzica
public void ejbCreate() {
...
}
Stosując ogólne zasady dziedziczenia uzyskujemy klasę naszego komponentu sesyjnego,
który posiada metody biznesowe. W przypadku potrzeby wykorzystania jakiejś metody
rodzica (w przykładzie z klasy SessinAdapterBean) wystarczy ją ponownie zdefiniować.
http://j2ee.ie.tu.koszalin.pl
-44-
5.2. Parametryzacja komponentów EJB
W przykładowej metodzie test() komponentu FacadeBean zastosowano pobieranie
obiektu String “test”, którego zawartość była przypisana na stałe. Kontener EJB
umożliwia definiowanie właściwości dla komponentów EJB w ten sposób, że ich zmiana
nie wymaga ponownej kompilacji kodu java.
5.2.1. Fragment kodu z klasy FacadeBean.java
720
721
722
723
724
725
726
727
//======================================================================
//metoda biznesowa test()
//======================================================================
public String test() {
}
System.out.println("[INFO] FacadeBean: test()");
return "test";
Zmodyfikowany kod wyszukuje lokalnie zawartości klucza “message”. Nic nie stoi na
przeszkodzie , aby nazwa była pobierana zdalnie z innego systemu , ponieważ wszystko
oparte jest o usługę JNDI.
5.2.2. Zmodyfikowany fragment kodu z klasy FacadeBean.java
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
//======================================================================
//metoda biznesowa test()
//======================================================================
public String test() {
System.out.println("[INFO] FacadeBean: test()");
String message = null;
try {
InitialContext initialContext = new InitialContext();
message = (String) initialContext.lookup("java:comp/env/message");
}catch(NamingException e){
throw new EJBException(e);
}
return message;
}
Ostatnim etapem jest ustawienie klucza i wartości dla naszej aplikacji EAR.
Rys. 41. Ustawianie właściwości dla komponentu FacadeBean – zakładka Env. Entries
http://j2ee.ie.tu.koszalin.pl
-45-
5.3. Aplikacja webowa WAR
Opis w przygotowaniu...iu...
http://j2ee.ie.tu.koszalin.pl
-46-
VI.Komponenty Entity EJB
6.1. Utrwalanie danych
6.2. Komponenty CMP 2.X
Uwaga! Dla komponentów Entity EJB typu CPM 2.0 (zarządzanych trwałością przez
kontener) należy budować klasy abstrakcyjne - abstract.
6.2.1. Klasa komponetnu Entity EJB (CMP) – UserBean.java
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
package systemy.entity;
import javax.ejb.CreateException;
import javax.ejb.EntityBean;
import javax.ejb.EntityContext;
public abstract class UserBean implements EntityBean {
private EntityContext ctx;
public abstract void setLogin(String login);
public abstract String getLogin();
public abstract void setPass(String pass);
public abstract String getPass();
public abstract void setEmail(String email);
public abstract String getEmail();
public void setEntityContext(EntityContext ctx) { this.ctx = ctx; }
public void unsetEntityContext() { this.ctx = null; }
public String ejbCreate(String login, String pass, String email) throws CreateException {
setLogin(login);
setPass(pass);
setEmail(email);
}
return null;
public void ejbPostCreate(String login, String pass, String email) { }
}
public
public
public
public
public
void
void
void
void
void
ejbRemove() { }
ejbActivate() { }
ejbPassivate() { }
ejbLoad() { }
ejbStore() { }
6.2.2. Interfejs zdalny - User.java
784
785
786
787
788
789
790
791
792
793
794
795
796
797
package systemy.entity;
import java.rmi.RemoteException;
import javax.ejb.EJBObject;
public interface User extends EJBObject {
public String getLogin() throws RemoteException;
public void setLogin(String login) throws RemoteException;
public String getPass() throws RemoteException;
public void setPass(String pass) throws RemoteException;
http://j2ee.ie.tu.koszalin.pl
-47-
798
799
800
801
public String getEmail() throws RemoteException;
public void setEmail(String email) throws RemoteException;
}
6.2.3. Interfejs domowy - UserHome.java
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
package systemy.entity;
import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.ejb.EJBHome;
import javax.ejb.FinderException;
public interface UserHome extends EJBHome {
public User create(String login, String pass, String email) throws
RemoteException,CreateException;
public User findByPrimaryKey(String primaryKey) throws FinderException, RemoteException;
}
Info! W pierwszej specyfikacji przewidziano jedynie interfejs zdalny i domowy dla
komponentów EJB. Ze względów wydajnościowych w kolejnych wersjach J2EE zastosowano
dodatkowo dwa interfejsy lokalne: lokalny i domowy-lokalny.
6.2.4. Interfejs lokalny - UserLocal.java
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
package systemy.entity;
import javax.ejb.EJBLocalObject;
public interface UserLocal extends EJBLocalObject {
public String getLogin();
public String getPass();
public void setPass(String pass);
public String getEmail();
public void setEmail(String email);
}
6.2.5. Interfejs lokalny-domowy - UserLocalHome.java
832
833
834
835
836
837
838
839
840
841
842
package systemy.entity;
import javax.ejb.CreateException;
import javax.ejb.EJBLocalHome;
import javax.ejb.FinderException;
public interface UserLocalHome extends EJBLocalHome {
}
public UserLocal create(String login, String pass, String email) throws CreateException;
public UserLocal findByPrimaryKey(String primaryKey) throws FinderException;
http://j2ee.ie.tu.koszalin.pl
-48-
6.3. GUID
Podczas projektowania komponentów Entity Bean występuje problem ustalenia
wartości klucza głównego wstawianych danych. Każdy obiekt Entity musi być
unikatowy, a jak wiadomo ich utrwalanie jest realizowane poprzez wstawienie nowego
rekordu do bazy danych. Skąd jednak wziąć wartość klucza głównego? Jest kilka
możliwości. Pierwsza i najprostsza to wykorzystanie pewnych unikalnych danych
biznesowych np. dla komponentu opisującego podatnika w urzędzie skarbowym takim
elementem może być jego NIP.
Co jednak zrobić, gdy nie możemy określić takiego parametru? Można skorzystać
z auto-inkrementacji klucza głównego danej bazy danych. Niestety taka obsługa nie jest
uwzględniana w specyfikacji J2EE i każdy serwer J2EE realizuje to w swój sposób
poprzez dodatkowe wpisy we własnych deskryptorach.
Innym sposobem jest stworzenie własnego komponentu, który będzie sam
zwiększał swój licznik. Wiąże się to jednak z problemami synchronizacji wielu
komponentów EJB, co automatycznie spowalnia pracę systemu tym bardziej, że
komponenty mogą istnieć na innych komputerach.
Sposobem uniknięcia wyżej wymienionego problemu jest takie wygenerowanie
identyfikatora, aby był on zależny od takich parametrów jak:
• czas,
• adres komputera w sieci jako adres IP,
• typ obiektu na rzecz którego generuje się identyfikator.
Ostatni element ma za zadanie wymusić unikalność wartości identyfikatora w
przypadku, gdy w tym samym czasie, na tym samym komputerze w dwóch różnych
wątkach nastąpi próba generacji identyfikatora.
6.3.1. Klasa Guid.java
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
package project.util;
// Kod klasy wygenerowany przy użyciu XDolcet
public class Guid {
private static String hexServerIP = null;
// initialise the secure random instance
private static final java.security.SecureRandom seeder = new java.security.SecureRandom();
/**
* A 32 byte GUID generator (Globally Unique ID). These artificial keys
* SHOULD <strong>NOT </strong> be seen by the user, not even touched by the
* DBA but with very rare exceptions, just manipulated by the database and
* the programs.
*
* Usage: Add an id field (type java.lang.String) to your EJB, and add
* setId(XXXUtil.generateGUID(this)); to the ejbCreate method.
*/
public static final String generateGUID(Object o) {
StringBuffer tmpBuffer = new StringBuffer(16);
if (hexServerIP == null) {
java.net.InetAddress localInetAddress = null;
try {
// get the inet address
localInetAddress = java.net.InetAddress.getLocalHost();
} catch (java.net.UnknownHostException uhe) {
System.err.println("Could not get the local IP address using InetAddress.getLocalHost()!");
http://j2ee.ie.tu.koszalin.pl
-49-
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
// todo: find better way to get around this...
uhe.printStackTrace();
return null;
}
byte serverIP[] = localInetAddress.getAddress();
hexServerIP = hexFormat(getInt(serverIP), 8);
}
String hashcode = hexFormat(System.identityHashCode(o), 8);
tmpBuffer.append(hexServerIP);
tmpBuffer.append(hashcode);
long timeNow = System.currentTimeMillis();
int timeLow = (int) timeNow & 0xFFFFFFFF;
int node = seeder.nextInt();
}
StringBuffer guid = new StringBuffer(32);
guid.append(hexFormat(timeLow, 8));
guid.append(tmpBuffer.toString());
guid.append(hexFormat(node, 8));
return guid.toString();
private static int getInt(byte bytes[]) {
int i = 0;
int j = 24;
for (int k = 0; j >= 0; k++) {
int l = bytes[k] & 0xff;
i += l << j;
j -= 8;
}
return i;
}
private static String hexFormat(int i, int j) {
String s = Integer.toHexString(i);
return padHex(s, j) + s;
}
private static String padHex(String s, int i) {
StringBuffer tmpBuffer = new StringBuffer();
if (s.length() < i) {
for (int j = 0; j < i - s.length(); j++) {
tmpBuffer.append('0');
}
}
return tmpBuffer.toString();
}
}
http://j2ee.ie.tu.koszalin.pl
-50-
6.4. Wzorzec Obiektu Transferu Danych
Wielokrotne wywoływanie kolejnych metod setXXX i getXXX dla ustalania zawartości
poszczególnych pól komponentów Entity EJB jest zajęciem czasochłonnym. Ma to
szczególne znaczenie przy połączeniach zdalnych, które w takim przypadku są
nadmiernie obciążane. Sposobem na to jest stworzenie nowej klasy zawierającej
wszystkie wymagane pola i zbiorczy transfer wszystkich danych jednego obiektu przy
pomocy jednego połączenia.
Zaprojektowana klasa UserData jest bardzo pomocna przy przenoszeniu danych
pomiędzy warstwą biznesową (komponenty EJB), a warstwą prezentacji (kod klienta,
aplikacja webowa).
6.4.1. Klasa do transferu danych użytkownika - UserData.java
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
package systemy.entity;
import java.io.Serializable;
public class UserData implements Serializable {
private String login;
private String password;
private String email;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public UserData() { }
public UserData(String login, String password, String email) {
setLogin(login);
setPassword(password);
setEmail(email);
}
public String toString() {
return "login="+getLogin()+" password="+getPassword()+" email="+getEmail();
}
public boolean equals(Object o) {
if(o instanceof UserData ) {
UserData test = (UserData)o;
boolean equals = true;
if(login == null){ equals = equals && (test.login == null); }
else { equals = equals && login.equals(test.login);}
if(password == null){ equals = equals && (test.password == null); }
else { equals = equals && password.equals(test.password); }
if(email == null){ equals = equals && (test.email == null); }
else { equals = equals && email.equals(test.email); }
return equals;
http://j2ee.ie.tu.koszalin.pl
-51-
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
}
}
else {
return false;
}
public int hashCode() {
int result = 17;
}
}
result
result
result
return
= 37*result + ((login != null) ? login.hashCode() : 0);
= 37*result + ((password != null) ? password.hashCode() : 0);
= 37*result + ((email != null) ? email.hashCode() : 0);
result;
Do klasy dodano konstruktor z trzema paramtrami (login, password, email) ułatwiający
wypełnianie obiektów UserData podczas ich tworzenia.
Dodatkowo do klasy UserData można dodać metody pomocnicze. Przykładem takich
metod może być walidacja przechowywanych danych, klonowanie, czy też
porównywanie zawartości obiektów pomocne np. przy ich sortowaniu w listach.
Weryfikacja (validate) w procesie wstawiania i/lub modyfikacji danych jest
bardzo ważnym czynnikiem. Proces ten realizuje się na ogół po stronie serwera w
aplikacjach webowych wspomaganych dodatkowo skryptami java w przeglądarkach
klienta. Jeśli z naszego systemy mają korzystać również w sposób bezpośredni inne
aplikacje klienta to proces weryfikacji należy umieścić albo w kodzie delegata
biznesowego, ale najlepsze rozwiązanie to fasada sesji – delegat biznesowy może być
umieszczony poza serwerem i możemy utracić kontrolę nad jego kodem.
http://j2ee.ie.tu.koszalin.pl
-52-
6.5. Wzorzec Facade
Aby zaprezentować sposób budowania fasady zaprojektowano dwie klasy.
http://j2ee.ie.tu.koszalin.pl
-53-
6.6. Wzorzec Lokalizatora Usług
Wzorzec Lokalizatora Usług został już omówiony podczas opisu tworzenia kodu
klient komunikującego się z komponentami EJB. Komponenty EJB zawarte w kontenerze
EJB także mogą pełnić funkcję klienta dla innych komponentów EJB lokalnych danego
kontenera lub zdalnych na innym serwerze J2EE.
http://j2ee.ie.tu.koszalin.pl
-54-
6.7. Relacje CMR
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
<?xml version="1.0" encoding="UTF-8"?>
...
<ejb-jar>
...
<relationships>
<ejb-relation>
<ejb-relationship-role>
<ejb-relationship-role-name>FirmaBean</ejb-relationship-role-name>
<multiplicity>One</multiplicity>
<relationship-role-source>
<ejb-name>FirmaBean</ejb-name>
</relationship-role-source>
<cmr-field>
<cmr-field-name>pracownicy</cmr-field-name>
<cmr-field-type>java.util.Collection</cmr-field-type>
</cmr-field>
</ejb-relationship-role>
<ejb-relationship-role>
<ejb-relationship-role-name>PracownikBean</ejb-relationship-role-name>
<multiplicity>Many</multiplicity>
<cascade-delete />
<relationship-role-source>
<ejb-name>PracownikBean</ejb-name>
</relationship-role-source>
<cmr-field>
<cmr-field-name>firma</cmr-field-name>
</cmr-field>
</ejb-relationship-role>
</ejb-relation>
</relationships>
...
</ejb-jar>
Rys. 42. Definiowanie relacji (rysunek do wymiany)
http://j2ee.ie.tu.koszalin.pl
-55-
6.8. Metody Finder i Select
6.9. EJB-QL
6.9.1. Składnia zapytania EJB-QL
EJB QL ::=
select_clause from_clause
[ where_clause]
Where_clause ::= WHERE conditional_expression
SELECT [DISTINCT] {single_valued_path_expression | OBJECT
(identification_variable)
abstract-schema-name
ejb-name
Lista identyfikatorów:
• SELECT, FROM, WHERE, DISTINCT,IN, AS, OF
• BETWEEN, IS, LIKE
• TRUE, FALSE
• NOT, AND, OR
• NULL, UNKNOWN, MEMBER, EMPTY, OBJECT
6.9.2. Przykładowe metody findXXX
Metody findXxx będą wywoływane przez kod klienta dlatego ich deklaracje należy
umieszczać wewnątrz interfejsów domowych. Metody wyszukiwania nie są realizowane
ma rzecz pojedynczej instancji komponentu, ale na całej grupie komponentów. Z tego
względu deklaracja metody wyszukiwania znajduje się w interfejsie domowym, w tym
samym w którym zadeklarowano metody create.
1040 public Order findByPrimaryKey(int orderId) throws FinderException;
1041 public Order findBiggestOrder() throws FinderException;
1042 public java.util.Collection findAllOrders(String supplierName) throws FinderException;
6.9.3. Przykładowe metody selectXxx i selectXxxInEntity
Metody selectXxx dotyczą wewnętrznego wywoływania metod w komponencie Entity
dlatego deklaruje się je wewnątrz abstrakcyjnych klasy komponentów EntityBean.
1043 <query>
1044
<description></description>
1045
<query-method>
1046
<method-name>findByAll</method-name>
1047
<method-params />
http://j2ee.ie.tu.koszalin.pl
-56-
1048
</query-method>
1049
<ejb-ql>SELECT Object(o) from PracownikBean as o</ejb-ql>
1050 </query>
Info! W sieci można odnaleźć ciekawy artykuł na temat EJB-QL. Znajduje się on na serwerze
OnJava.com pod adresem http://www.onjava.com/lpt/a/1152
http://j2ee.ie.tu.koszalin.pl
-57-
VII.Transakcje
7.1. Model ACID w komponentach EJB
Opis w przygotowaniu...
7.2. Wycofanie transakcji
Opis w przygotowaniu...
Opracowanie komponentu Entiry KontoBean oraz jego komponentu fasady
KontoFacadeBean zawierającego metody transferu gotówki (w fasadzie zastosować
dwie kopie metod z deklaratywną i programową obsługą transakcji – symulacja metod
przy wypłacie gotówki i wywoływanie metody setRolbackTransaction przy zerowym
stanie konta ).
Do tego wszystkiego trzeci sposób - prosty klient SimpleTransactionClient z obsługą
transakcji poza komponentem EJB.
W perspektywie.... Można umieścić porównanie wydajności różnych ustawień transakcji
przy ich testowaniu – np. narzędziem JMETER przez WWW.
7.3. Mapowanie metod komponentów EJB
Podczas tworzenia komponentów EJB projektant ma możliwość zadeklarowania
wymaganego stanu transakcji dla danej metody.
http://j2ee.ie.tu.koszalin.pl
-58-
7.4. Poziomy izolacji transakcji
Poziom izolacji transakcji
Dirty NonPhantom
repeatable
TRANSACTION_READ_UNCOMMITTED brak izolacji
Tak
Tak
Tak
TRANSACTION_READ_COMMITTED
częściowa
izolacja
Nie
Tak
Tak
TRANSACTION_REPEATABLE_READ
częściowa
izolacja
Nie
Nie
Tak
TRANSACTION_SERIALIZABLE
Pełna izolacja Nie
Nie
Nie
Wymagany stan jest opisywany przy pomocy określonego atrybutu:
• NotSupported
• Supports
• Required
• RequiresNew
• Mandatory
• Never
Typ zarządzania transakcjami:
• Bean
• Container
7.4.1. Fragment desktyptora - ejb-jar.xml
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
<?xml version="1.0" encoding="UTF-8"?>
...
<ejb-jar>
...
<assembly-descriptor>
<container-transaction>
<method>
<ejb-name>FacadeBean</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
<container-transaction>
<method>
<ejb-name>PracownikBean</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
<container-transaction>
<method>
<ejb-name>FirmaBean</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
</assembly-descriptor>
</ejb-jar>
http://j2ee.ie.tu.koszalin.pl
-59-
VIII.JNDI
8.1. Interfejs Context
Podczas tworzenia kodu klienta w przykładzie SimpleClient.java wykorzystano interfejs
kontekstu.
8.1.1. Fragment pliku – SimpleClient.java
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
Properties env = new Properties();
//J2EE RI 1.3.1
env.put("java.naming.factory.initial","com.sun.jndi.cosnaming.CNCtxFactory");
env.put("java.naming.provider.url", "iiop://localhost:1050");
try {
Context ctx = new InitialContext(env);
Object objref = ctx.lookup("ejb/Simple"); //nazwa JNDI
...
} catch (Exception e) {
System.err.println(e);
}
http://j2ee.ie.tu.koszalin.pl
-60-
Info! Interfejs Context jak i cały pakiet javax.naming.* do obsługi JNDI należy do
standardowej specyfikacji javy (biblioteka rt.jar z JRE System Library).
1102
1103
1104
1105
1106
env.put("java.naming.factory.initial","com.sun.jndi.cosnaming.CNCtxFactory");
env.put("java.naming.provider.url", "iiop://localhost:1050");
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.cosnaming.CNCtxFactory");
env.put(Context.PROVIDER_URL, "iiop://localhost:1050");
8.2. Interfejs DirContext
Opis w przygotowaniu...
http://j2ee.ie.tu.koszalin.pl
-61-
IX.Ldap
Serwer OpenLdap jest tworzony głównie na systemach Unixowych i istnieje
prawie w każdej dystrybucji systemu Linux w postaci źródeł, czy też spakowanych
paczek. Do pracy serwera w systemie Windows należy użyć skompilowanej wersji. W
ramach zajęć będziemy korzystać z takiej wersji. Serwer posiada plik konfiguracyjny,
który należy odpowiednio zmodyfikować i dostosować do określonej lokalizacji na
dysku.
9.1. Konfiguracja serwera OpenLdap
9.1.1. Plik konfiguracyjny serwera OpenLDAP - slap.conf
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
# $OpenLDAP: pkg/ldap/servers/slapd/slapd.conf
include
include
include
include
c:/java/openLDAP/schema/core.schema
c:/java/openLDAP/schema/cosine.schema
c:/java/openLDAP/schema/inetorgperson.schema
c:/java/openLDAP/schema/java.schema
#######################################################################
# ldbm database definitions
#######################################################################
database
suffix
rootdn
rootpw
directory
ldbm
"o=JNDITutorial"
"cn=admin,o=JNDITutorial"
portal
c:/java/openLDAP/ldbm/ldbm_jndi
Aby uruchomić serwer OpenLDAP należy wywołać polecenie slapd.exe. Serwer
nasłuchuje na porcie 389.
http://j2ee.ie.tu.koszalin.pl
-62-
9.2. Aplikacja klienta - LdapBrowser
Rys. 43. Aplikacja klienta – LdapBrowser (java)
http://j2ee.ie.tu.koszalin.pl
-63-
9.3. Komunikacja z serwerem
9.3.1. Przykład prostego klienta – LdapClient.java
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
package systemy.client;
import java.util.Properties;
import javax.naming.Context;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
public class LdapClient {
public static void main(String[] args) {
Properties env = new Properties();
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://localhost:389/o=JNDITutorial");
env.put(Context.SECURITY_PRINCIPAL, "cn=admin,o=JNDITutorial");
env.put(Context.SECURITY_CREDENTIALS, "portal");
try {
DirContext ctx = new InitialDirContext(env);
DirContext ctx2 = (DirContext)ctx.lookup("ou=people");
System.out.println(ctx2.getNameInNamespace());
Attributes attrs = ctx2.getAttributes("");
System.out.println(attrs);
}
}
} catch (Exception e) {
System.err.println(e);
}
http://j2ee.ie.tu.koszalin.pl
-64-
X.Komunikaty JMS
10.1. Konfiguracja JMS na serwerze J2EE RI
Rys. 44. Konfiguracja fabryk JMS
Rys. 45. Konfiguracja kolejek JMS typu Topic i Queue
http://j2ee.ie.tu.koszalin.pl
-65-
10.2. Komponent MDB
Podstawową właściwością odróżniającą komponenty MDB od Session i entity jest brak
interfejsów. Komponent zbudowany jest jedynie z klasy rozszerzającej interfejs
MessageDrivenBean. Powodem braku interfejsów jest brak możliwości bezpośredniej
komunikacji z komponentem zewnętrznych klientów. Klientem komponentu jest kolejka
komunkatów JMS, której mapowanie odbywa się przy konfiguracji EAR na serwerze.
10.2.1. Klasa wzorca adaptera dla MDB – MessageDrivenBean.java
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
package project.adapter;
import javax.ejb.MessageDrivenBean;
import javax.ejb.MessageDrivenContext;
public abstract class MessageBeanAdapter implements MessageDrivenBean {
protected MessageDrivenContext context = null;
}
public void setMessageDrivenContext(MessageDrivenContext ctx) { context = ctx; }
public void ejbCreate(){}
public void ejbRemove(){}
10.2.2. Klasa komponentu MDB – LogBean.java
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
package project.message;
import
import
import
import
import
javax.jms.JMSException;
javax.jms.Message;
javax.jms.MessageListener;
javax.jms.ObjectMessage;
javax.jms.TextMessage;
import project.adapter.MessageBeanAdapter;
public class LogBean extends MessageBeanAdapter implements MessageListener {
private static final long serialVersionUID = 5L;
public void onMessage(Message msg) {
System.out.println("-------------------------------------------------");
// pobranie parametru z komunikatu - przydatne do dalszego przekierowania
try {
System.out.println("parametr info: "+msg.getStringProperty("info"));
}
catch(JMSException e) {
}
if(msg instanceof TextMessage) {
TextMessage tm = (TextMessage)msg;
try {
}
String text = tm.getText();
System.out.println("Komunikat TextMessage: "+text);
}
catch(JMSException e) {
System.err.println(e);
}
if(msg instanceof ObjectMessage) {
ObjectMessage tm = (ObjectMessage)msg;
try {
}
}
}
Object obj = tm.getObject();
System.out.println("Komunikat ObjectMessage: "+obj.getClass()+" "+obj);
}
catch(JMSException e) {
System.err.println(e);
}
http://j2ee.ie.tu.koszalin.pl
-66-
Rys. 46. Mapowanie komponentu MDB
Podczas mapowania komponentu MDB można zauważyć brak interfejsów zdalnych, czy
też lokalnych. Związane jest to z tym, że kod klasy komponentu nie jest bezpośrednio
wywoływany przez klienta. Metoda onMessage jest aktywowana przez kolejkę JMS
konfigurowana przez serwer J2EE.
Rys. 47. Mapowanie kolejki i fabryki komponentu MDB
Razem z serwerem j2EE RI 1.3.1 jest uruchamiany serwer JMS. Jest in silnie związany z
serwerem baz danych ponieważ natura komunikatów JMS określa ich asynchroniczność.
http://j2ee.ie.tu.koszalin.pl
-67-
Komunikat może zostać wysłany do kolejki z której będzie odebrany w późniejszym
czasie. Z tego względu treść komunikatu musi zostać czasowo utrwalona.
10.3. Prosty klient wysyłający komunikaty
JMS
Przykładowy kod realizuje wysłanie tekstowego komunikatu do kolejki jms/Topic
skonfigurowanej przez działający serwer J2EE. Kolejka została udostępniona lokalnie i
kod działa na tym samym komputerze (bez rozproszenia). W przypadku wysyłania
komunikatów JMS przy pomocy IIOP zdalnie należy najpierw odnaleźć kolejkę na
serwerze JNDI.
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
package project.client;
import java.util.Date;
import
import
import
import
import
import
import
import
import
import
javax.jms.ObjectMessage;
javax.jms.Session;
javax.jms.TextMessage;
javax.jms.Topic;
javax.jms.TopicConnection;
javax.jms.TopicConnectionFactory;
javax.jms.TopicPublisher;
javax.jms.TopicSession;
javax.naming.Context;
javax.naming.InitialContext;
public class JmsClient {
public static void main(String[] args) {
try {
//inicjalizacja kontekstu
Context ctx = new InitialContext();
TopicConnectionFactory factory = (TopicConnectionFactory) ctx.lookup
("jms/TopicConnectionFactory"); //nazwa JNDI fabryki JMS
1252
TopicConnection connection = factory.createTopicConnection();
1253
TopicSession topicSession = connection.createTopicSession
(false,Session.AUTO_ACKNOWLEDGE);
1254
Topic topic = (Topic) ctx.lookup("jms/Topic");
1255
1256
TopicPublisher publisher = topicSession.createPublisher(topic);
1257
1258
//przesyłanie komunikatu w postaci tekstu
1259
TextMessage textMsg = topicSession.createTextMessage();
1260
1261
textMsg.setStringProperty("info","Przesylka w postaci komunikatu TextMessage");
textMsg.setText("Tresc tekstowa komunikatu... ");
1262
1263
1264
1265
1266
1267
1268
publisher.publish(textMsg);
System.out.println("Wysłano komunikat TextMessage --> "+textMsg);
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278 }
1279 }
publisher.publish(objMsg);
System.out.println("Wysłano komunikat ObjectMessage --> "+objMsg);
//przesyłanie komunikatu w postaci obiektu
ObjectMessage objMsg = topicSession.createObjectMessage();
objMsg.setStringProperty("info","Przesylka w postaci komunikatu ObjectMessage");
objMsg.setObject(new Date());
connection.close();
} catch (Exception e) {
System.err.println(e);
return;
}
http://j2ee.ie.tu.koszalin.pl
-68-
Po wykonaniu kodu na konsoli klienta zostanie wyświetlony komunikat, którego
zawartość została przesłana do kolejki JMS.
Java(TM) Message Service 1.0.2 Reference Implementation (build b14)
Wysłano komunikat TextMessage --> ID:_krypton-by6ksqw_1104758069097_36.1.1.1: Tresc tekstowa komunikatu...
Wysłano komunikat ObjectMessage --> ID:_krypton-by6ksqw_1104758069097_36.1.1.2: contains a java.util.Date
Przy odpowiednio skonfigurowanym na serwerze komponencie MDB jego metoda
onMessage przejmuje przekazany komunikat i wyświetla jego zawartość na konsoli
serwera.
Deploying message driven bean LogBean, consuming from jms/Topic
Binding name:`java:comp/env/ejb/Facade`
Created Context:/project
Application project deployed.
------------------------------------------------parametr info: Przesylka w postaci komunikatu TextMessage
Komunikat TextMessage: Tresc tekstowa komunikatu...
------------------------------------------------parametr info: Przesylka w postaci komunikatu ObjectMessage
Komunikat ObjectMessage: class java.util.Date Mon Jan 03 14:14:29 CET 2005
Rys. 48. Konsola serwera J2EE z treścią odebranych komunikatów JMS
Na konsoli serwera J2EE podczas rozmieszczania aplikacji pojawiają się informacje o
wiązaniach nazw JNDI poszczególnych komponentów EJB. Jest także informacja o
konsumowaniu komunikatów z kolejki jms/Topic przez komponent MDB LogBean.
W kodzie klienta, jak i w kodzie odbiorczym komponentu MDB zastosowano dwa typy
komunikatów. Tekstowy TextMessage oraz do przesyłania zserializowanych obiektów
ObjectMessage. Dodatkowo dodano ustawianie właściwości komunikatów. W
przykładzie zastosowano właściwość typu String o nazwie info. Kod klienta ustawia
właściwość, a komponent MDB ją pobiera z komunikatu.
Kod zawarty w klasie JmsClient.java można równie dobrze umieścić w aplikacji
webowej jaki część servletu, czy też strony jsp.
10.4. ServiceLocator
–
rozszerzenie
wyszukiwania o kolejki JMS
Podobnie jak z wzorcem wyszukiwania usług dla komponentów EJB można ten wzorzec
stosować dla innych typów usług. Idea stosowania jest taka sama w każdym przypadku
i polega na odciążeniu kodu klienta od technicznych znajomości związanych z JNDI,
EJB, JMS, Web Services czy też innej technologii.
http://j2ee.ie.tu.koszalin.pl
-69-
XI.Web Services
W specyfikacji J2EE 1.3 nie uwzględniono jeszcze nowej, szybo rozwijającej się
technologii Web Services opartej o tzw. architekturę opartą o serwisy (SOA). W nowej
specyfikacji J2EE 1.4 usługi zostały już zintegrowane z warstwą kontenera EJB. Przy
projektach wykorzystujących starszą specyfikację należy wykorzystać kod pośredni w
postaci servletu. Oczekuje on na żądania klienta www, przetwarza otrzymaną
informację w postaci koperty SOAP i na jej podstawie wywołuje metody wraz z ich
parametrami klas java. Po otrzymaniu wyniku dokonuje ponownej translacji, ale w
przeciwną stronę. Wynik działania metod java jest pakowany w kopertę SOAP i
odesłany klientowi w formacie XML. Klient otrzymuje kopertę SOAP i przetwarza jej
zawartość przy pomocy własnych mechanizmów, klient nie musi być realizowany w
technologii java, a jedynie musi rozumieć gramatykę schematu dokumentów SOAP.
Dodatkowo w celu informacji klientów o działaniu danej usługi serwer z naszym
serwerem powinien udostępniać XML'owy dokument WSDL.
Całość procesu obsługi usług Web Service w technologii java wspiera projekt
Apaceh – AXIS.
11.1. AXIS
Projekt Axis jest serwletem, który umieszczony w kontenerze web'owym (aplikacji
WAR) umożliwia konwersję klas javy udostępnianych w postaci pliku źródłowego ze
zmienionym rozszerzeniem *.jws. Dla wszystkich plików JWS serwlet umożliwia
automatyczną generację dokumentów WSDL.
1280 public class Simple {
1281
1282
public String info() {
1283
return "info: wywołanie metody usługi sieciowej Simple.jws";
1284
}
1285 }
http://j2ee.ie.tu.koszalin.pl
-70-
XII.Autentykacja i
Autoryzacja
12.1. Role użytkowników
Rys. 49. Blokada metody test() komponentu SimbleBean (zakładka Security)
Po ustawieniu blokady (opcja No Users) metody testowej komponentu EJB klient
otrzymuje wyjątek braku zdalnego dostępu RMI - AccessException.
java.rmi.AccessException: CORBA NO_PERMISSION 9998 Maybe; nested exception is:
org.omg.CORBA.NO_PERMISSION:
vmcid: 0x2000 minor code: 1806 completed: Maybe
Rys. 50. Przypisanie roli project metodzie test() komponentu SimbleBean (zakładka Security)
http://j2ee.ie.tu.koszalin.pl
-71-
12.2. Komunikacja SSL
Opis w przygotowaniu...
http://j2ee.ie.tu.koszalin.pl
-72-
XIII.Testy jednostkowe
Testowanie można podzielić na kilka rodzajów:
• testowanie logiki – przy pomocy atrap – Mock Object;
• testowanie integracyjne – np. przy pomocy Cactusa działającego w rzeczywistym
kontenerze – kontener WEB lub EJB na serwerze J2EE;
• testy funkcjonalne – np. HttpUnit testujące funkcjonowanie aplikacji przy
wykorzystaniu żądań i odpowiedzi serwera.
13.1. JUnit
Kluczowym elementem tworzenia projektu jest przeprowadzanie testów. Wielokrotne
wykonywanie tych samych czynności wymusiło stworzenie narzędzi wspomagajacych
testowanie. W ten sposób powstały testy jednostkowe stosowane w różnych jezykach
(java, perl, python, c++, czy też c#). Jednostkowość polega na wydzieleniu elementarnych
operacji, które mogą wykonywać się niezależnie od innych. Wynik testu jest
diagnozowany na podstawie wywoływania metod asercji. Poprawne wykonanie
wszystkich metod danego testu powoduje, że dany kod testowy wykonał się
prawidłowo.
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
package systemy.client;
import java.util.Properties;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.rmi.PortableRemoteObject;
import systemy.session.Facade;
import systemy.session.FacadeHome;
import junit.framework.TestCase;
public class TestClient extends TestCase {
Context ctx;
protected void setUp() throws Exception {
Properties env = new Properties();
//J2EE RI 1.3.1
env.put("java.naming.factory.initial","com.sun.enterprise.naming.SerialInitContextFactory");
env.put("java.naming.provider.url", "iiop://localhost:1050");
try {
ctx = new InitialContext(env);
} catch (Exception e) {
System.err.println(e);
}
}
//================================================================
public void testFacade() throws Exception {
Object objref = ctx.lookup("ejb/FacadeBean"); //nazwa JNDI
FacadeHome home = (FacadeHome) PortableRemoteObject.narrow(objref,FacadeHome.class);
Facade facade = home.create();
String result = facade.test();
System.out.println(result);
http://j2ee.ie.tu.koszalin.pl
-73-
1327
assertEquals(result,"test");
1328 }
1329 //================================================================
1330
1331 protected void tearDown() throws Exception { }
1332
1333 public static void main(String[] args) {
1334
1335
junit.swingui.TestRunner.run(TestClient.class);
1336
//junit.awtui.TestRunner.run(TestClient.class);
1337 }
1338 }
Rys. 51. Klient biblioteki JUnit
Stosowanie testów jednostkowych ułatwia wprowadzanie zmian w projekcie.
Optymalizując kod można szybciej sprawdzać jego poprawność poprzez wykonanie
testów. Ma to kluczowe znaczenie przy coraz bardziej złożonych projektach.
Grupowanie testów – w przygotowaniu.
http://j2ee.ie.tu.koszalin.pl
-74-
13.2. Projekt Cactus – osadzanie testów
jednostkowych na serwerze J2EE
Opis w przygotowaniu...
http://j2ee.ie.tu.koszalin.pl
-75-
XIV.Komponent?!
14.1. Projekt CUBA
Projektowanie komponentowe stawia za cel tworzenie kodu wielokrotnego
użytku. Projekt CUBA umożliwia automatyzację procesu tworzenia dodatkowej
infrastruktury do zaprojektowanego komponentu w zależności od typu komponentu i
kontenera w jakim będzie egzystował. Dla zaprojektowanej klasy i interfejsu metod,
które maja zostać udostępnione na zewnątrz projekt CUBA umożliwia automatyczne
stworzenie klas i deskryptorów w zależności od typu komponentu wynikowego.
Projektant ma możliwość generacji komponentów zdalnych obsługiwanych przy
pomocy JNDI i RMI, komponentów EJB wymagających kontenera EJB, czy też usług
sieciowych Web Services opartych o pakiet AXIS.
java cuba.util.codegen.AdapterGenerator
No adapter type specified
Usage: AdapterGenerator <options> <component descriptor>
or: AdapterGenerator <options> -> reads descriptor vom CLASSPATH
Options are:
-h
this help message
-a
create a Web-Service-Adapter
-e
create EJB adapter
-w
create wired adapter
-c
create package structure
-d <dir>
output directory
-x <class> XML parser to use (default cuba.wired.ddread.XmlParserXerces)
http://j2ee.ie.tu.koszalin.pl
-76-
XV.Log4j
15.1. Poziomy rejestracji logów
DEBUG ← INFO ← WARN ← ERROR ← FATAL (ALL)
1339
1340
1341
1342
1343
log.debug("DEBUG...");
log.info("INFO...");
log.warn("WARN...");
log.error("ERROR...");
log.fatal("FATAL...");
15.2. Przekierowanie logów
•
•
•
•
•
•
•
console
files
GUI components
remote socket
JMS
NT Events Logger
SysLog (Unix)
15.3. Definiowanie wzorca
przykłady:
%d{ABSOLUTE} %-5p [%c{1}] %m%n
%r [%t] %-5p %c - %m%n
176 [main] INFO org.foo.Bar - Located nearest gas station.
%r czas w milisekundach od startu programu
%t
nazwa metody
the number of milliseconds elapsed since the start of the program
the thread making the log request
the level of the log statement
the name of the logger associated with the log request
the '-' is the message of the statement.
http://j2ee.ie.tu.koszalin.pl
-77-
Projekt log4j dostępny jest pod adresem http://jakarta.apache.org/log4j.
15.3.1. Kod klasy Log4jClient.java
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
package systemy.client;
import org.apache.log4j.Logger;
import org.apache.log4j.BasicConfigurator;
public class Log4jClient {
static Logger log = Logger.getLogger(Log4jClient.class);
public static void main(String[] args) {
BasicConfigurator.configure();
log.info("J2EE Project");
// kod klienta...
}
}
log.info("Koniec");
15.3.2. Plik właściwości biblioteki log4j – log4j.properties
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
log4j.rootCategory=DEBUG, CONSOLE, FILE
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Threshold=INFO
log4j.appender.CONSOLE.Target=System.out
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ABSOLUTE} %-5p [%c{1}] %m%n
log4j.appender.FILE=org.apache.log4j.RollingFileAppender
log4j.appender.FILE.threshold=DEBUG
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=%d{ABSOLUTE} %-5p [%c{1}] %m%n
log4j.appender.FILE.append=true
log4j.appender.FILE.file=client.log
log4j.appender.FILE.bufferedIO=false
log4j.appender.FILE.maxBackupIndex=3
log4j.appender.FILE.maxFileSize=10kB
http://j2ee.ie.tu.koszalin.pl
-78-
XVI.ANT i MAVEN
16.1. Ant
W celu automatyzacji przygotowania aplikacji EAR bardzo często wykorzystuje
się narzędzie ANT. Projekt ten we wczesnym stadium rozwoju był przeznaczony do
wspomagania budowy serwera Tomcat. Oba projekty należą do fundacji Apache i są w
pełni darmowe. Ideą narzędzia jest tworzenie skryptów w języku XML, dzięki temu
uzyskuje się niezależność od systemu opercyjnego. Nasza aplikacja nie potrzebuje teraz
osobnych skryptów instalacyjnych np. dla windows i(*.bat) linux'a (*.sh). Jedynym
warunkiem jest oczywiście instalacja javy.
Aktualnie projekt jest na tyle zaawansowany, że jest wykorzystywany przez
wszystkie znaczące narzędzia projektowe javy. Architektura ANT'a wspiera tworzenie
wtyczek (plug-in), które znacznie rozszerzają funkcjonowanie narzędzia.
16.1.1. Skrypt ANT'a z J2EE Project – build.xml
1380 <?xml version="1.0" encoding="UTF-8"?>
1381 <project name="J2EE Project ANT Script" default="deploy" basedir=".">
1382
1383 <!-- <splash/> -->
1384
1385 <!-1386
UWAGA! Plik build.xml spełnia następujące założenia projektowe
1387
1388
1. Źródła wszystkich klas javy znajdują się w podkatalogu src.
1389
2. Zmienna app.name określa nazwe aplikacji EAR.
1390
- archiwym EAR test.ear <- nazwa aplikacji dla app.name="test"
1391
1392
Zmiana zmiennej app.name wymusza aktualizację jej nazwy w deskryptorze application.xml
1393
1394
3. Skrypt uwzględnia tworzenie pojedynczego archiwum ejb-jar, war
1395
o następujących nazwach:
1396
1397
- archiwum WAR war-ic.war
1398
- archiwum EJB ejb-jar.jar
1399
1400
code by ([email protected]) ver. 20.12.2004
1401
-->
1402
1403 <!-- =================================================================== -->
1404 <!-- Init
-->
1405 <!-- =================================================================== -->
1406 <target name="init">
1407
1408
<!-- rejestracja log'ów
1409
<record name="verbose.log" action="start" loglevel="verbose"/>
1410
<record name="verbose.log" loglevel="debug"/>
1411
-->
1412
1413
<!-- =============================================================== -->
1414
<!-- parametry do modyfikacji znajdują się w pliku build.properties -->
1415
<!-- =============================================================== -->
1416
<property environment="env" />
1417
<property name="j2ee.home" value="${env.J2EE_HOME}" />
1418
<property file="build.properties" />
1419
<property name="src.dir" value="${basedir}/src" />
1420
1421
<property name="build.dir" value="${basedir}/build" />
1422
<available property="build.dir.exists" file="${build.dir}"/>
1423
1424
<!-- lokalizacja tymczasowa plików dla aplikacji EJB JAR -->
http://j2ee.ie.tu.koszalin.pl
-79-
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
<property name="build.ejb.dir" value="${build.dir}/ejb" />
<!-- lokalizacja tymczasowa plików dla aplikacji WAR -->
<property name="build.war.dir" value="${build.dir}/war" />
<!-- lokalizacja tymczasowa plików dla aplikacji EAR -->
<property name="build.ear.dir" value="${build.dir}/ear" />
<property name="j2ee.server.name" value="localhost" />
<property name="j2ee.classpath" value="${j2ee.home}/lib/j2ee.jar:${j2ee.home}/
lib/system/cloudscape.jar:${j2ee.home}/lib/system/tools.jar:${j2ee.home}/
lib/cloudscape/RmiJdbc.jar:${j2ee.home}/lib/cloudscape/cloudclient.jar:${j2ee.home}/
lib/classes:${j2ee.home}/classes:${j2ee.home}/lib/locale:${j2ee.home}/lib/jhall.jar:$
{junit.lib}:${cactus.lib}:" />
</target>
<!-- =================================================================== -->
<!-- Prepare
unless="build.dir.exists"
-->
<!-- =================================================================== -->
<target name="prepare" depends="init" >
<mkdir dir="${build.dir}"/>
<mkdir dir="${build.ejb.dir}"/>
<mkdir dir="${build.war.dir}"/>
<mkdir dir="${build.ear.dir}"/>
</target>
<!-- =================================================================== -->
<!-- Compile
-->
<!-- =================================================================== -->
<target name="compile" depends="prepare">
<!-- kompilacja klas dla archiwum EJB -->
<javac srcdir="${src.dir}" destdir="${build.ejb.dir}"
classpath="${j2ee.classpath}" debug="on">
<!-- w tym miejscu mozna określić dokładnie jakie klasy projektu mają należeć do EJB JAR -->
<include name="**"/>
<!-- wszystkie -->
<exclude name="**/client/**"/>
<!-- z wyjątkiem należących do pakietu client -->
<exclude name="**/war/**"/>
<!-- z wyjątkiem należących do pakietu war -->
</javac>
<!-- kompilacja klas dla archiwum WAR -->
<javac srcdir="${src.dir}" destdir="${build.war.dir}" classpath="${j2ee.classpath}">
<include name="**/war/**"/>
<!-- wszystkie należące do pakietu war -->
</javac>
</target>
<!-- =================================================================== -->
<!-- Jar
-->
<!-- =================================================================== -->
<target name="jar" depends="compile">
<!-<!-<!-<jar
==================================================== -->
pakowanie archiwum EJB JAR -->
==================================================== -->
jarfile="${build.ear.dir}/ejb-jar-ic.jar">
<metainf file="${basedir}/ejb-jar/META-INF/ejb-jar.xml"/>
<fileset dir="${build.ejb.dir}" />
</jar>
<!-<!-<!-<war
==================================================== -->
pakowanie archiwum WAR -->
==================================================== -->
warfile="${build.ear.dir}/war-ic.war" webxml="${basedir}/war/WEB-INF/web.xml">
<fileset dir="${basedir}/war"/>
<classes dir="${build.war.dir}"/>
<!-- <lib dir="${jars}"><include name="test.jar"/> </lib> -->
</war>
<!-<!-<!-<ear
==================================================== -->
pakowanie archiwum EAR = EJB JAR + WAR + deskryptory -->
==================================================== -->
earfile="${build.dir}/${app.name}.ear"
appxml="${basedir}/ear/META-INF/application.xml">
<metainf file="${basedir}/ear/META-INF/sun-j2ee-ri.xml/"/>
<fileset dir="${build.ear.dir}" includes="*.jar,*.war"/>
</ear>
</target>
<!-- =================================================================== -->
<!-- Deploy
-->
<!-- =================================================================== -->
<target name="deploy" depends="jar">
http://j2ee.ie.tu.koszalin.pl
-80-
1507
<java classname="com.sun.enterprise.tools.deployment.main.Main" fork="yes">
1508
<classpath path="${j2ee.classpath}" />
1509
<sysproperty key="com.sun.enterprise.home" value="${j2ee.home}" />
1510
<sysproperty key="org.omg.CORBA.ORBInitialPort" value="1050" />
1511
<sysproperty key="java.security.policy"
1512
value="${j2ee.home}/lib/security/java.policy" />
1513
<arg line="-deploy ${build.dir}/${app.name}.ear ${j2ee.server.name}" />
1514
</java>
1515
1516
<waitfor maxwait="10000">
1517
<http url="http://localhost:8000/project/TestServlet"/>
1518
</waitfor>
1519
1520 </target>
1521
1522 <!-- =================================================================== -->
1523 <!-- Undeploy
-->
1524 <!-- =================================================================== -->
1525 <target name="undeploy" depends="init">
1526
1527
<java classname="com.sun.enterprise.tools.deployment.main.Main" fork="yes">
1528
<classpath path="${j2ee.classpath}" />
1529
<sysproperty key="com.sun.enterprise.home" value="${j2ee.home}" />
1530
<sysproperty key="org.omg.CORBA.ORBInitialPort" value="1050" />
1531
<sysproperty key="java.security.policy"
1532
value="${j2ee.home}/lib/security/java.policy" />
1533
<arg line="-uninstall ${app.name} ${j2ee.server.name}" />
1534
</java>
1535
1536 </target>
1537
1538 <!-- =================================================================== -->
1539 <!-- Clean
-->
1540 <!-- =================================================================== -->
1541 <target name="clean" depends="init">
1542
<delete dir="${build.dir}" />
1543 </target>
1544
1545 <!-- =================================================================== -->
1546 <!-- JacaDoc
-->
1547 <!-- =================================================================== -->
1548 <target name="javadoc">
1549
<javadoc packagenames = "*" sourcepath="${src.dir}" destdir="doc"
1550
classpath="${j2ee.classpath}" />
1551 </target>
1552
1553 <!-- =================================================================== -->
1554 <!-- SignJar
-->
1555 <!-- =================================================================== -->
1556 <target name="signJar" depends="jar">
1557
<!-- podpisz archiwum EAR certyfikatem -->
1558
<signjar keystore="${basedir}/security/certs"
1559
jar="${build.dir}/${app.name}.ear" alias="portal"
1560
storepass="portal" keypass="portal"/>
1561 </target>
1562 <!-- =================================================================== -->
1563
1564 </project>
16.2. Maven
Znacznym postępem w narzędziach do budowy i integrowania aplikacji jest projekt
MAVEN. Można go przyrównać do Anta tak jak postęp języka C++ względem C).
Maven potrafi odnaleźć w sieci brakującą bibliotekę, integrować zasoby z różnych
serwerów CVS.
http://j2ee.ie.tu.koszalin.pl
-81-
XVII.JBoss i XDoclet
17.1. JBoss
Ten rozdział będzie posiadał opis wszystkich wcześniejszych etapów projektu z
wykorzystaniem serwera JBOSS dostepnego pod adresem www.jboss.org. Jest to
darmowy projekt OPEN SOURCE wykorzystujący kontener webowy w postaci serwera
Tomcat lub Jetty.
Info! W sieci istnieje polskie forum dotyczące serwera JBOSS – www.jboss.pl prowadzone przez
ludzi związanych z firmą JAVART.
17.2. XDoclet
Aby zminimalizować ilość pisanego kodu szerokie zastosowanie ma biblioteka xdoclet,
która analizując źródła javy wyszukuje teksty zawarte w komentarzach poprzedzone
znaczkiem @ (np. @jboss, @ejb). Na podstawie atrybutów, bo o nich mowa, można
wygenerować dodtkowe pliki (np. deskryptory xml, czy też źródła klas lub interfejsów java).
http://j2ee.ie.tu.koszalin.pl
-82-
XVIII.Geronimo
Darmowy serwer JBoss jes rozwijany przez komercyjną firmę. Czerpie ona zyski
głównie ze wsparcia i sprzedaży dokumentacji do serwera. Fundacja Apache znana z
serwera Tomcat rozpoczęła rozwó własnego darmowego projektu Geronimo. Aktualnie
jest to wersja rozwojowa Geronimo-1.0M3 i nie implementuje jeszcze wszystkich
mechanizmów zgodnych ze specyfikacją J2EE. W przyszłości zakłada się większe
wsparcie niniejszej dokumentacji o opis serwera Geronimo.
http://j2ee.ie.tu.koszalin.pl
-83-
XIX. Atrapa EJB ? MockEJB
Projektowanie komponentów z ciągłym ich testowaniem na rzeczywistym serwerze jest
zadaniem czasochłonnym. Aby zminimalizować ten proces można zastosować atrapę
kontenera EJB i cały projektowany kod wykonywać znacznie szybciej bez całego procesu
tworzenia infrastuktury aplikacji enterprise (wszelkich deskryptorów rozmieszczenia, czy też
generacji szkieletów klas wykorzystywanych przy połączeniach zdalnych) wraz z jej instalacją.
Pod adresem http://www.mockejb.org znajduje się zestaw bibliotek
zawierających wszelkie niezbedne klasy z pakietu javax.ejb jak równierz inne związane
z platformą J2EE.
19.1. Aplikcja klienta
19.1.1. Zmodyfikawana klasa klienta - SimpleMockClient.java
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
package systemy.client;
import java.util.Properties;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.rmi.PortableRemoteObject;
import org.mockejb.MockContainer;
import org.mockejb.SessionBeanDescriptor;
import org.mockejb.jndi.MockContextFactory;
import systemy.session.Facade;
import systemy.session.FacadeBean;
import systemy.session.FacadeHome;
public class SimpleMockClient {
public static void main(String[] args) {
//Properties env = new Properties();
//J2EE RI 1.3.1
//env.put("java.naming.factory.initial","com.sun.enterprise.naming.SerialInitContextFactory");
//env.put("java.naming.provider.url", "iiop://localhost:1050");
//Context ctx = new InitialContext(env);
try {
//=============================================================================
MockContextFactory.setAsInitial();
Context ctx = new InitialContext();
//=============================================================================
MockContainer mockContainer = new MockContainer(ctx);
SessionBeanDescriptor descriptor =
new SessionBeanDescriptor("ejb/FacadeBean",FacadeHome.class, Facade.class, new FacadeBean
() );
mockContainer.deploy(descriptor);
//=============================================================================
//reszta kodu bez zmian
Object objref = ctx.lookup("ejb/FacadeBean"); //nazwa JNDI
FacadeHome home = (FacadeHome) PortableRemoteObject.narrow(objref,FacadeHome.class);
Facade w = home.create();
System.out.println(w.test()); //test
http://j2ee.ie.tu.koszalin.pl
-84-
1609
1610
} catch (Exception e) {
1611
System.err.println(e);
1612
}
1613
}
1614 }
Testowanie projektu polega na rezygnacji ze standardowej biblioteki j2ee.jar i w zamian
zastosowanie bibliotek *.jar zawartych w katalogu lib projektu MockEJB.
Wykonanie kodu klienta powoduje wygenerowanie na konsoli nastepujących
komunikatów:
[INFO] FacadeBean: setEntityContext(SessionContext org.mockejb.MockEjbContext@91cee)
[INFO] FacadeUserBean: ejbCreate()
[INFO] FacadeBean: test()
test
Podczas testów nie tworzono żadnych deskryptorów. Cołość została zahermetyzowana
obiektem MockContainer,
który kontroluje wywoływanie metod komponentu
FacadeBean – w tym przypadku metody test() wyświetlającej komunikat test.
Aktualnie jest dostępna wersja mockejb-0.6-beta2.zip zawierajaca kilka przykładów
odnoszących się do różnych komponetów ejb oraz transakcji. Dodatkowo w
przykładach wykorzystano mechanizm testów jednostkowych projektów JUnit oraz
Cactus.
Info! Ciekawy artykuł na temat wykorzystywania bibliotek atrap (mock) znajduje się pod
adresem http://jdn.pl/do/news/view?id=67
http://j2ee.ie.tu.koszalin.pl
-85-
XX.Systemy kontroli wersji Cvs i Svn
20.1. CVS
Opis w przygotowaniu...
20.2. SVN
Opis w przygotowaniu...
svn --version
svn, version 1.1.0 (r11180)
compiled Oct 4 2004, 21:11:18
Copyright (C) 2000-2004 CollabNet.
Subversion is open source software, see http://subversion.tigris.org/
This product includes software developed by CollabNet (http://www.Collab.Net/).
The following repository access (RA) modules are available:
* ra_dav : Module for accessing a repository via WebDAV (DeltaV) protocol.
- handles 'http' schema
- handles 'https' schema
* ra_local : Module for accessing a repository on local disk.
- handles 'file' schema
* ra_svn : Module for accessing a repository using the svn network protocol.
handles 'svn' schema
svn --help
usage: svn <subcommand> [options] [args]
Type "svn help <subcommand>" for help on a specific subcommand.
Most subcommands take file and/or directory arguments, recursing
on the directories. If no arguments are supplied to such a
command, it will recurse on the current directory (inclusive) by
default.
Available subcommands:
add
blame (praise, annotate, ann)
cat
checkout (co)
cleanup
commit (ci)
copy (cp)
delete (del, remove, rm)
diff (di)
export
help (?, h)
import
info
list (ls)
http://j2ee.ie.tu.koszalin.pl
-86-
log
merge
mkdir
move (mv, rename, ren)
propdel (pdel, pd)
propedit (pedit, pe)
propget (pget, pg)
proplist (plist, pl)
propset (pset, ps)
resolved
revert
status (stat, st)
switch (sw)
update (up)
Subversion is a tool for version control.
For additional information, see http://subversion.tigris.org/
svnadmin --help
general usage: svnadmin SUBCOMMAND REPOS_PATH [ARGS & OPTIONS ...]
Type "svnadmin help <subcommand>" for help on a specific subcommand.
Available subcommands:
create
deltify
dump
help (?, h)
hotcopy
list-dblogs
list-unused-dblogs
load
lstxns
recover
rmtxns
setlog
verify
svnadmin create d:\svn\reporitory
20.2.1. Tworzenie repozytorium SVN
svnadmin create /lokalizacja_repozytorium
svn import /katalog_projektu file:///lokalizacja_repozytorium -m "nazwa_projektu"
http://j2ee.ie.tu.koszalin.pl
-87-
XXI.UML
21.1. Diagramy przypadków użycia
Opis w przygotowaniu...
http://j2ee.ie.tu.koszalin.pl
-88-
XXII.Projekt
Tworząc projekty opieramy się na źródłach mojego projektu będącego swego rodzaju
szkieletem do dalszej rozbudowy – http://j2ee.ie.tu.koszalin.
Projekt składa się z trzech modułów:
•
•
•
komponenty entity beans (utrwalanie danych i relacje CMR);
komponenty session bean (wzorce FacadeBean, DTO i ServiceLocator);
aplikacja klas klienta (wzorce ServiceLocator i BussnesDelegate, testy JUnit)
ID
Zagadnienia cząstkowe projektów
2x J2EE
Rozproszenie komponentów aplikacji na dwa serwery J2EE
SSL
Autentykacja w aplikacji EAR (protokół SSL)
ROLE
Autoryzacja w aplikacji EAR (role użytkowników)
CMR
Relacje pomiędzy komponentami Entity (1:1, 1:N, M:N)
WS
Wywoływanie usług sieciowych Web Services (pakiet AXIS)
Properties
Parametryzacja danych komponentów aplikacji EAR
JMS
Komunikaty JMS w komponentach EJB MDB
LDAP
Serwer katalogowy LDAP
jUnit
Testy jednostkowe jUnit
log4j
Mechanizm rejestracji log'ów
22.1. Założenia nazewnicze
Każda grupa projektowa otrzyma numer projektu, który należy używać przy tworzeniu
własnych klas i interfejsów. Głównym celem jest eliminacja sytuacji, gdy kilka projektów
nie będzie mogło ze sobą egzystować na jednym serwerze testowym.
Np. dla grupy numer 10 wystąpią następujące warunki wstępne:
– Nazwa głównego pakietu ma zostać przemianowana z project na project10, a tym
samym np. klasa project.entity.Firma będzie teraz klasą project10.entity.Firma.
– Wszystkie nazwy JNDI
mają zostać przemianowane z dodaniem przedrostka
project10 np. dla ejb/Facade będzie teraz ejb/project10/Facade;
– Wszystkie projekty mają wykorzystywać do utrwalania danych źródło bazy danych –
Cloudscape o nazwie jdbc/Cloudscape;
– Nazwy (Abstract Schema Name) stosowane przy komponentach Entity i używane do
budowania zapytań w EJB-QL oraz generacji kodu SQL należy zmienić dodając do
każdej z nich numer projektu np. dla FirmaBean będzie nazwa FirmaBean10. W
wyniku takiej modyfikacji będzie generowana tabel FirmaBean10Table w bazie
Cloudscape – w pewien sposób unikatowa dla każdej grupy.
http://j2ee.ie.tu.koszalin.pl
-89-
22.2. Diagram klas projektu
Aplikacja
klienta
<<Singleton>>
<<Singleton>>
ServiceLocator
ServiceLocator
Aplikacja EAR
zainstalowana na
serwerze J2EE
<<EntityEJB>>
FirmaBean
<<POJO>>
Client
<<POJO>>
<<SessinoEJB>>
BusinessDelegate
FacadeBean
<<EntityEJB>>
PracownikBean
<<POJO>>
DataTransferObject
Rys. 52. Diagram podstawowych klas projektu J2EE Project.
Nazwy zawarte w znakach << .... >> oznaczają stereotypy. Wskazuje to na rodzaj
implementacji danej klasy w rzeczywistym systemie.
• <<POJO>> - (ang. Plain Old Java Object) oznacza zwykłe obiekty JAVA;
• <<Singleton>> - istnienit tylko jednej instancji obiektu z danej klasy;
• <<SessionEJB>> - obiekt Session Bean wymagający istnienia kontenera EJB;
• <<EntityBEan>> - obiekt EntityBean wymagający istnienia kontenera EJB.
http://j2ee.ie.tu.koszalin.pl
-90-
22.3. Lista tematów
Lp
Opis
Technologia
Rozszerzyć projekt o obsługę Konta, na które będą przekazywane środki
pieniężne – aktywacja dokonująca transferu gotówki ma myć dokonywana przy
użyciu klientów JMS i 2 komponentów MDB. Każdy z komponentów ma
1 obsługiwać inny typ kolejki JMS.
JMS, MDB
Rozszerzyć projekt o obsługę Konta, na które będą przekazywane środki
pieniężne – aktywacja dokonująca transfer gotówki ma być dokonywana przy
2 użyciu technologii WebServices (AXIS)
WebService,
AXIS
Zasymulować komunikację dwóch serwerów J2EE na jednym komputerze i
dokonać rozproszenia części komponentów Entity Bean używając interfejsów
zdalnych. Dodać dodatkowe metody biznesowe rozszerzające funkcjonalność
3 systemu o możliwość zatrudniania jednego pracownika w dwóch firmach
2xJ2EE, CMR
Rozszerzyć system o komponent biznesowy ResourceBean przechowujący
informacje o zasobach udostępnianych pracownikom firmy. Przez zasoby
rozumiem środki trwałe jak np. komputer, samochód, telefon komórkowy. Kod
aplikacji klienta ResourceClient.java ma umożliwiać wyświetlanie informacji o
danym użytkowniku i zasobach jakie aktualnie posiada. W projekcie
wykorzystać pakiet jUnit do realizacji testów jednostkowych klasy
4 ResourceClientTest.java
CMR, jUnit
Zrealizować rejestrację użytkowników firmy przez zewnętrzny system
JNDI,
wysyłania komunikatów JMS. Podczas rejestracji nowego użytkownika jego dane JMS
5 mają zostać także umieszczone na serwerze LDAP.
Zrealizować aplikację klienta (np. działu wysyłania reklam do firm) aby pełniła
rolę odbiorcy informacji o komunikatach JMS przesyłanych przez system w
przypadku rejestracji nowej firmy. Rejestrację nowej firmy zrealizować jako
prostą aplikację war z formularzem dodawania danych firmy. Wykorzystać
6 wzorzec delegata biznesowego hermetyzującego kod obsługi JMS klienta.
LDAP,
JMS,
BussDelegate
Rozszerzyć system rejestrujący pracowników o nowe pola. Dodać zestaw funkcji EJB-QL
wyszukujących według różnych kryteriów, których deklaracje należy umieścić w
interfejscie PracownikLocalHome. Kod definicji funkcji będzie generowany na
podstawie języka zapytań EJB-QL. Opracować różne warianty, aby
7 zaprezentować możliwości składniowe EJB-QL.
Rozszerzyć system o komponent MagazynBean przechowujący towary danej
firmy. Zamodelować mechanizm przechowywania informacji o sprzedaży
danego towaru przez konkretnego pracownika. Zaprojektować metodę
biznesową obliczającą prowizję (np. 1,5%) od wartości towarów sprzedanych w
8 danym miesiącu.
Facade, CMR
Rozszerzyć klasę ServiceLocator o możliwość wyszukiwania usług JMS.
Zaprezentować jej działanie od strony klienta oraz od strony komponentów EJB.
Jako problem do rozwiązania przy użyciu tej technologii przyjąć system, który
przesyła informację o nakazie wykonania badań okresowych zatrudnionych w
danej firmie. Do odbioru danych wykorzystać prosty komponent MDB
9 przekazujący informacje na konsolę serwera.
ServiceLocator,
JMS, MDB
http://j2ee.ie.tu.koszalin.pl
-91-
Lp
Opis
Technologia
Rozszerzyć komponent PracownikBean o możliwość definiowania okresu
urlopowego. Do tego celu wykorzystać wzorzec transferu danych do stworzenia
klasy PracownikUrlopData.java. Zrealizować aplikację klienta, który będzie
pobierał listę urlopów pracowniczych posortowaną według rozpoczęcia lub
10 długości trwania.
DTO,
Facade,BussDe
legate
Rozbudować aktualną aplikację o testy jednostkowe realizowany przy pomocy
projektu Cactus (http://jakarta.apache.org/cactus). Biblioteka ta to sposób na
osadzanie biblioteki jUnit na serwerze i jej zdalne wywoływanie przez aplikację
webową. Zorganizować serię testów na wszystkich klasach, a w szczególności
11 komponentach EntityBean.
Junit, Cactus
Klient SOAP wykonuje zlecenie przelewu gotówki pomiędzy kontem Firmy i
Pracownika. Zaadaptuj system do obsługi takiej operacji na komponentach
FirmaBean i PracownikBean (każdy z komponentów rozszerzyć o pole double
12 konto)
SOAP, CMP
Rozszerzyć aplikację o obsługę szyfrowania komunikacji klienta RMI z
SSL,
ANT,
wykorzystaniem szyfrowania SSL. Opracować i opisać mechanizm szyfrowania i Certyfikaty
generacji certyfikatów dla aplikacji J2EE. Wykorzystać ANT'a do
13 automatycznego podpisywania archiwów EAR.
Rozbudować system o mechanizm wersjonowania Firm i Pracowników. Dane z
systemu nie mają znikać, a jedynie się dopisywać. Wymaga to dodania
dodatkowego identyfikatora do klas EntityBean zawierającego idFirmy i
idPracownika, daty zmiany, oraz identyfikatora ważności danego wpisu – czy
jest bieżący, czy też już historyczny. Rozszerzyć metody wyszukiwania po
14 określonym idFirmy i idPracownika.
CMR
Zamodelować usługę Web Services udostępniającą możliwość realizacji
Web Services
raportów na temat historii zmian wprowadzanych w systemie. W tym celu każda
metoda biznesowa opisana w komponencie fasady musi być wzbogacona o
tworzenie obiektu Entity Bean o nazwie HistoriaBean w którym należy
dokonywać zapisu czasu, wykonanej operacji i identyfikatorach id (kluczach
15 głównych) Pracownika i/lub Firmy
Rozszerz system o implementację forum na komponentach entity ForumBean i
Kategoria Bean. Zrealizuj mechanizm dodawania nowych wiadomości przez
autoryzowanych użytkowników. Komponent Kategoria ma umożliwiać
16 realizacje relacji cyklicznych (kategoria może zawierać podkategorie)
Role,
Autoryzacja
CMR
Opracować rozbudowaną aplikację kliencką umożliwiającą tylko odczyt danych
o pracownikach i firmach. W tym celu zastosować określone ROLE dostępu do
metod. Ograniczyć dostęp do metod setXXX). W projekcie należy uwzględnić
wszelkie możliwości parametryzowania projektu (zmiana serwera JNDI,
17 Properties itd...)
Autoryzacja,
FacadeBean,
Propertes
Zaprojektować komponent sesyjny JndiBean za pomocą którego klient przez
SessionBean,
pośrednictwo fasady będzie miał dostęp do wszystkich nazw JNDI
JNDI
zdefiniowanych na serwerze J2EE. Zaimplementować operacje przeglądania
(list), wyszukiwanie (lookup) oraz dodawania własnych nazw. Dodawanie nazw
18 wykonać z użyciem autentykacji – tylko dla określonej roli np. admin
Rozszerzyć projekt o testowanie Delegata Biznesowego klienta przy pomocy
19 biblioteki jUnit. Zaprezentować zestaw testów wraz z ich pogrupowaniem.
http://j2ee.ie.tu.koszalin.pl
JUnit,
BussDelegate
-92-
Lp
Opis
Technologia
Rozszerzyć projekt o testowanie Fasady Sesji umieszczonej na serwerze. W tym
celu rozbudować fasadę o nowe metody i do testów użyć biblioteki JUnitEE.
Zaprezentować testy wykorzystujące komunikację komponentów EJB z
20 wykorzystaniem interfejsów zdalnych i lokalnych.
JUnitEE,
FasadeBean
Firmy wykorzystujące nasz system zostały w nim zarejestrowane. Dodatkowo
każda z firm mogła się zarejestrować we własnej kolejce komunikatów (Queue)
naszego serwera. Zrealizuj wysyłanie do kolejki danej firmy komunikatu
podczas wstawiania i usuwania jej pracownika. Jako treść komunikatu należy
przesyłać nazwisko, imię i PESEL, ale bez innych szczegółowych informacji.
Wysyłki należy dokonać tylko, gdy dana firma używa kolejki. (rozszerzyć
komponent FirmaBean o pole String zawierające null -brak kolejki lub jej nazwę
21 np. jms/QueueFirmaA itd... )
JMS,
EntityBean,
JNDI
Opracować komponent sesyjny stanowy LicznikiBean realizujący rejestrację
liczników “biznesowych” danego klienta. Licznik może być wykorzystany do
zliczania np. liczby wywołać metody przelew, liczby nieudanych wywołać
metody wypłata itd... Komponent powinien posiadań obiekt Map, którego
zadaniem będzie przechowywanie par wartości (klucz=wartość).
Zaimplementować wyszukiwaniem według klucza i zwiększanie jego wartości
(inkrementacja). Uwaga! Zadeklarować możliwość wywoływanie metod
22 komponentu w transakcji jak i bez nich.
FacadeBean,
transakcje
Zamodelować komponenty TowarBean(Entity) oraz ZakupyBean (Session).
Komponent zakupów powinien posiadać możliwość podliczania ceny z
uwzględnieniem stóp podatkowych za dany towar (A=22%, B=7%, C=..., ...).
Wartości stóp procentowych należy deklarować z poziomu konfiguracji
23 Deploytool (nie w kodzie java).
EntityBean,
SessionBean,
Parameters
System raportowania pod wpływem otrzymania komunikatu JMS z kolejki z
JMS, MDB,
informacją o danej firmie (np. jej REGON) oraz treści komunikatu (np. tekst
JavaMail
pozdrowień świątecznych) ma wysłać otrzymaną treść wszystkim pracownikom
danej firmy zarejestrowanym w systemie. Do wysyłki użyć JavaMAIL i
24 komponentu MDB.
Zaprojektowany system ma być pośrednikiem pomiędzy systemami
magazynowymi naszych klientów – Firm. Zrealizuj mechanizm odpytywania
wybranych firm (np. z danego regiony, lub o danym profilu – rozszerzyć
komponent FirmaBean o dodatkowe właściwości). Klient Java komunikuje się z
komponentem FacadeBean, który pobiera odpowiednią listę firm. Następnie
wykonuje do każdej z nich odwołanie protokołem SOAP o cenę danego towaru
(np. książka o danym numerze ISBN). Podczas kolejnych odwołań następuje
zapamiętanie najkorzystniejszej oferty. Po wykonaniu operacji informacja
zwrotna trafia do klienta (klienta można obsługiwać także przez SOAP, RMI lub
25 JMS).
SOAP,
Web Services,
Session Bean
Rozbudować system o komponent ZusBean przechowujący kwotę opłaty
przekazanej przez firmę za zatrudnionych pracowników. W komponencie
FacadeBean zrealizować metody dodawania nowego wpisu (np. za dany
miesiąc), określania kwoty na podstawie sumy kwot każdego pracownika danej
firmy. Komponent PracownikBean musi posiadać pole kwotaZus oraz
26 odpowiednie metody do jego modyfikacji.
EntityBean,
FacadeBean
Na serwerze LDAP przechowano informacje o firmach. Zaprojektować metodę
LDAP, JMS
aktywowaną przy pomocy komunikatu JMS, której zadaniem jest przeglądniecie
drzewa LDAP i odnalezienie firm (DirContext), które nie zostały jeszcze
27 zarejestrowane w FirmaBean. Dokonać automatycznej rejestracji firm.
http://j2ee.ie.tu.koszalin.pl
-93-
Lp
Opis
Technologia
System przechowuje informacje o pracownikach. Rozszerz jego funkcjonalność o EntityBean,
możliwość przechowywania informacji na temat okresów pracy. W tym celu
FacadeBean
zadeklaruj komponent GrafikBean, który będzie przechowywał informację jaki
pracownik, dla jakiej firmy (nie musi do niej należeć), przez jaki okres (ile godzin
i od której godziny) i w jakim dniu wykonywał swoją pracę. Zadeklaruj metody
wyświetlania informacji dla danego pracownika i np. grafik za dany
28 tydzień/miesiąc dla wszystkich pracowników.
Należy przemodelować system w ten sposób,że nazwa komponent
EntityBean,
PracownikBean będzie teraz określała komponent PrzesyłkaBean. W ten sposób EJB-QL
system może pełnić rolę rejestracji firm oraz rejestracji przesyłek kurierskich,
które mają trafić pod podany adres.
Każda przesyłka ma posiadać pole “status”. Zaimplementować możliwość
wycofania przesyłki (status=WYCOFANIE), doręczenia (status=DORECZONO) i
oczywiście tryb przesyłania (status=NADAWCA, status=W_DRODZE,
status=ODBIORCA). Umożliwić wyświetlanie informacji o przesyłkach danej
29 firmy według ich statusu.
Zaprojektować testowanie logiczne aplikacji J2EE Project z wykorzystaniem
atrapy testów MockEJB. Całość opracować z wykorzystaniem biblioteki testów
jednostkowych JUnit. Dodatkowo w klasach adaptacyjnych wykorzystać
30 bibliotekę Log4J do rejestracji logów.
MockEJB,
JUnit, Log4J
Rozszerzyć aplikację o walidację danych. Zastosować dodatkowe metody w
klasach DTO – FirmaData i PracownikData. Określić pola komponentów
EntityBean, które muszą być wypełnione oraz pola dodatkowe. Rozszerzyć
walidację o mechanizm analizy takich pól jak NIP, REGON i PESEL (liczba cyfr i
31 sumy kontrolne). Walidacji dokonywać na serwerze w warstwie Fasady Session.
DTO,
Facade
Session,
Validate
Zrealizować komponent RssBean jako komponent BMP. Zamodelować
mechanizm pobierania i wstawiania danych z tabeli RssTable bazy danych
Cloudscape. Informacje uzyskane z połączenia cache'ować w lokalnej liście w
FacadeBean w postaci obiektów klasy RssData (według wzorca DTO). Ma to na
celu eliminacje zbyt częstych odwołać do bazy np. tylko raz na jeden dzień.
Klient ma mieć możliwość pobierania listy obiektów RssData oraz dokumentu
32 RSS (XML).
BMP, DTO,
RSS
Rozszerz aplikację EAR o nową aplikację enterprise JAR zawierającą kopię
EntityBean,
komponentów FirmaBean i PracownikBean. Zadaniem jest podział naszej
EJB-JAR,
aplikacji na część produkcyjną i nową testową, która jest jeszcze w rozwoju – np. FacadeBean
będzie miała dodatkową funkcjonalność. Komponent FacadeBean ma obsługiwać
wywoływania obu kopii komponentów przy czym błędy wynikłe w warstwie
testowej nie mają wpływać na pracę warstwy produkcyjnej – informowanie o
błędach mają być przesyłane np. na konsolę serwera.
Uwaga! Kopie komponentów Entity mają mieć inne nazwy JNDI np.
33 ejb/test/Pracownik.
Wyeksportuj wnętrze metod biznesowych znajdujących się w komponencie
FacadeBean do podległych klas wzorca Application Service. Celem jest
ograniczenie logiki biznesowej w fasadzie przez dodanie dodatkowej warstwy
biznesowej. W tym celu zamodeluj klasy FirmaApplicationService oraz
PracownikApplicationService. W każdej z nich umieść logikę do danego
34 przypadku użycia: pracownika i firmy.
http://j2ee.ie.tu.koszalin.pl
FacadeBean,
Application
Service
-94-
Lp
Opis
W zaprojektowanym systemie zamodelować utrwalanie danych komponentów
EntityBean dla innych typów danych (w przykładach wykorzystano tylko
String). W tym celu rozszerzyć komponenty PracownikBean i FirmaBean o
dodatkowe pola np. daty rejestracji, daty zatrudnienia, liczby dni urlopu. Dla
nowo przygotowanych komponentów stworzyć rozszerzone wersje obiektów
35 transferu danych DTO – FirmaExtData i PracownikExtData.
Technologia
Entity Bean,
DTO
Zamodelować komponenty FirmaBean i PracownikBean jako komponenty BMP. BMP, relacje
Do utrwalania danych wykorzystać własny mechanizm oparty o JDBC. Można
również wykorzystać projekt Hibernate lub JDO automatyzujący proces
36 generacji klas do komunikacj z JDBC.
Zamodelować generację wartości kluczy głównych (String) jako klasę
wywoływaną z lokalizatora usług o nazwie Key.java z polem
inkrementowanym. Wówczas w klasach FirmaBean i PracownikBean
wykorzystać pobieranie klucza zamiast jego generacji przy użyciu klasy
Guid.java. Uwaga! Zastosować standardowy mechanizm synchronizacji przy
pobieraniu wartości klucza, aby wyeliminować możliwość pobrania tej samej
37 wartości przy jednoczesnym odwołaniu do klasy generującej.
ServiceLocator,
EntityBean
Zaprojektuj komponent sesyjny InfoJndiBean , który aplikacji klienta
JNDI,
(delegatowi) będzie zwracał informację o liście nazw JNDI komponentów EJB. W Facadebean,
tym celu zaprojektuj dodatkową klasę JNDIName.java zawierającą publiczne
BussDelegate
pola statyczne np. public String FIRMA_NAME = “ejb/Firma”. Wówczas w
aplikacji wszelkie odwołania “ejb/Firma” mają zostać zamienione na odwołania
do JNDIName.FIRMA_NAME. Podobnych operacji dokonać dla wszystkich
nazw JNDI wykorzystywanych w referencjach fasady. Wszelkie nazwy muszą
być zarejestrowane w liście komponentu InfoJndiBean z możliwością ich
38 udostępniania klientowi.
Opracuj klasy PracownikPK i FirmaPK i użyj ich do tworzenia obiektów kluczy PK,
głównych komponentów Entity CMP. Wówczas podczas mapowania pół id dla CMP
Firmabean i PracownikBean należy jako klucz wybrać nasze klasy:
project.pk.PracownikPK i project.pk.FirmaPK. W klasach komponentów metody
ejbCreate(...) będą teraz zwracały zamiast String obiekty naszej klasy. Również
należy wnieść poprawki przy deklaracji metod create() lokalnych interfejsów
39 domowych.
Rozbudować projekt o realizację Web Services. W tym celu rozbudować projekt o 2xJ2EE,
możliwość komunikacji dwóch aplikacji J2EE. W przypadku wstawiania nowej
Web Services
firmy w jednym systemie (ServerA → EntityEJB) automatycznie ma zostać
wykonana usługa wstawiania takiej samej firmy w drugim systemie
40 (ServerA→ Web Services → SererB → EnityEjb)
http://j2ee.ie.tu.koszalin.pl
-95-
Przykładowe zagadnienia rozszerzające standardowy projekt:
•
•
•
•
•
•
•
•
•
•
•
serwer LDAP
dwa serwery J2EE ze wspólnym serwerem JNDI
rejestracja komponentów w zewnętrznym systemie LDAP
plik XML opisujący przelew klienta banku (Web Services)
przesyłanie komunikatów JMS pomiędzy dwoma serwerami J2EE
wywoływanie procedur RPC w WebService z poziomu EJB
komunikacja asynchroniczna JMS dwóch systemów
przelew bankowy – obsługa transakcyjności deklaratywnej
przelew bankowy – obsługa transakcyjności programowej
testy Jednostkowe jUnit oraz Cactus
bezpieczeństwo – autentykacja i autoryzacja użytkowników komponentów EJB
http://j2ee.ie.tu.koszalin.pl
-96-
22.4. Zagadnienia podstawowe
•
•
•
•
•
•
•
•
•
•
•
Komunikacja klienta z komponentem EJB za pośrednictwem JNDI;
Budowa komponentów EJB (interfejsy i klasa);
Cel i sposób realizacji wzorca Fasady;
Różnice pomiędzy komponentami sesyjnymi EJB stateless i stateful oraz przykłady
zastosowań;
Mechanizm utrwalania danych stosowany w komponentach EJB;
Mechanizm deklarowania referencji komponentów EJB w innych komponentach EJB;
Cel i sposób realizacji wzorca obiektu transferu danych DTO;
Różnice w definiowaniu interfejsów zdalnych i lokalnych;
Omów cel stosowania abstrakcyjnych klas EntityBean dla CMP 2.X;
Omów mechanizm definiowania relacji CMR komponentów entity bean;
Co rozumiesz przez pojęcie transakcji? Opisz zasady ACID;
Do projektu zostanie udostępniony szablon dokumentacji - (w www.OpenOffice.org)
http://j2ee.ie.tu.koszalin.pl
-97-
XXIII.Zasoby WWW
Serwery J2EE
• J2EE R I 1.3.1
• J2EE RI 1.4 – SunOne
• JBoss
• Geronimo
• Resin
• Tomcat
Testowanie aplikacji
• MockEJB
• JUnit
• Cactus
• JUnitEE
Usługi Web Services
• AXIS
XML
• Xerces
• Xalan
Biblioteki do zarządzania log'ami
• Log4j
Systemy kontroli wersji
• CVS
• SVN
Platforma ECLIPSE
• platforma eclipse – www.eclipse.org
Eclipse – plugins
Uml
• Omondo
http://j2ee.ie.tu.koszalin.pl
-98-
XXIV.Schematy
deskryptorów
Schemat deskryptora
application.xml
http://j2ee.ie.tu.koszalin.pl
-99-
Schemat deskryptora
ejb-jar.xml
http://j2ee.ie.tu.koszalin.pl
-100-
http://j2ee.ie.tu.koszalin.pl
-101-
Schemat deskryptora
sun-j2ee-ri.xml
http://j2ee.ie.tu.koszalin.pl
-102-
Schemat deskryptora
web-app.xml
http://j2ee.ie.tu.koszalin.pl
-103-
XXV.J2EE RI 1.3.1–
poprawki i aktualizacje
Standardowa instalacja wzorcowej implementacji J2EE (j2sdkee-1_3_1-win.exe)
posiada usterki utrudniające pracę.
25.1. Ścieżka do bazy Cloudscape
Uruchomienie serwera j2ee -verbose powoduje wyszukiwanie baz danych znajdujących
się w katalogu bieżącym. Aby ustawić stały katalog dla źródeł baz danych
zmodyfikowano plik setenv.bat z katalogu bin. Tekst wytłuszczony określa
wprowadzone zmiany.
25.1.1. Plik setenv.bat
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
REM
REM Copyright 2002 Sun Microsystems, Inc. All rights reserved.
REM SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
REM
rem
rem Set JAVA_HOME and J2EE_HOME before running this script.
rem
rem first include user-specified definitions.
call %J2EE_HOME%\bin\userconfig.bat
if "%JMS_HOME%" == "" set JMS_HOME=%J2EE_HOME%
set LIBDIR=%J2EE_HOME%\lib
set LOCALEDIR=%J2EE_HOME%\lib\locale
set CLOUDSCAPE_INSTALL=%LIBDIR%\cloudscape
set CLASSESDIR=%LIBDIR%\classes
set JMS_CLASSESDIR=%JMS_HOME%\classes
set J2EEJARS=%LIBDIR%\j2ee.jar
set JAVATOOLS=%JAVA_HOME%\lib\tools.jar
set JAVAHELPJARS=%LIBDIR%\jhall.jar
rem JMS DB PATH must end in slash to specify a directory
set JMS_DB_PATH=%J2EE_HOME%\repository\%COMPUTERNAME%\db\
set SYSTEM_LIB_DIR=%LIBDIR%\system
set JMS_RI_JDBC=%SYSTEM_LIB_DIR%\cloudscape.jar;%SYSTEM_LIB_DIR%\tools.jar
set CLOUDJARS=%JMS_RI_JDBC%;%CLOUDSCAPE_INSTALL%\RmiJdbc.jar;%CLOUDSCAPE_INSTALL\cloudclient.jar
set J2EETOOL_CLASSES=%LIBDIR%\toolclasses
set J2EETOOL_JAR=%LIBDIR%\j2eetools.jar
set CPATH=%CLOUDJARS%;%CLASSESDIR%;%JMS_CLASSESDIR%;%J2EEJARS%;%J2EETOOL_CLASSES%;%
J2EETOOL_JAR%;%LOCALEDIR%;%J2EE_CLASSPATH%;%JAVATOOLS%;%JAVAHELPJARS%
1652
1653 set JAAS_OPTIONS=-Djava.security.auth.policy=%J2EE_HOME%\lib\security\jaas.policy
1654 set SSL_OPTIONS=-Djavax.net.ssl.trustStore=%J2EE_HOME%\lib\security\cacerts.jks
1655 set LISTEN_OPTIONS=Dcom.sun.CORBA.connection.ORBListenSocket=SSL:0,SSL_MUTUALAUTH:0,PERSISTENT_SSL:1060
1656
1657 set CLOUD_OPTIONS=-Dcloudscape.system.home=%J2EE_HOME%\cloudscape
1658 set JAVA_COMMAND=%JAVA_HOME%\bin\java -Xmx128m %CLOUD_OPTIONS% %SSL_OPTIONS% %JAAS_OPTIONS%
1659
http://j2ee.ie.tu.koszalin.pl
-104-
25.2. Bibiblioteka klienta CloudView
CloudView jest programem (GUI) do obsługi baz Cloudscape. W pakiecie J2EE zawarta
jest biblioteca Cloudview.jar, ale nie współpracuje ona z nowszą wersją bazy Cloudscape
(biblioteka dla Cloudscape 4.0 a baza Cloudscape 4.06). Należy ze strony
www.cloudscape.com ściągnąć odpowiednie poprawki (wraz z tym plikiem dostępne
jest archiwum z wszystkimi poprawkami i bibliotekami). Są to pliki cloudscape406.jar
oraz plik pomocy jh.jar. Pliki należy skopiować do katalogu lib/cloudscape z
nadpisaniem na istniejący plik cloudscape.jar.
Dodatkowo w katalogu bin umieszczono plik cloudview.bat wywołujący program
CloudView z biblioteki cloudscape.jar.
25.2.1. Plik cloudview.bat
1660 set CLASSPATH=%J2EE_HOME%\lib\system\cloudscape.jar;%J2EE_HOME%\lib\system\cloudutil.jar;%
J2EE_HOME%\lib\cloudscape\cloudview.jar;%J2EE_HOME%\lib\cloudscape\jh.jar;%CLASSPATH%
1661
1662 java -ms32M -mx32M COM.cloudscape.tools.cview
1663
1664 pause
25.3. Obsługa serwera w Win98
W przypadku uruchamiania serwera pod systemem Windows 98 mamy do czynienia z
większym problemem. W skryptach bat zastosowano rozszerzoną wersję DOS'a i jako
parametry poleceń dozwolony jest zapis %*. W tych miejscach w których występuje %*
należy wstawić listę parametrów zgodną ze składnią Win98 %0 %1 %2 %3 %4 %5 %6 %7
%8 %9.
Dotyczy to wszystkich plików bat.
Następny problem jest próba uruchomienia serwera pod Win98 kończąca się
wyświetleniem komunikatu - za mało miejsca na środowisko. W takim przypadku
najlepiej umieścić na pulpicie skrót do programu command.com /P /E:3000. Po
uruchomieniu konsola jest niezależna od wcześniejszych ustawień i ma przydzielony
większy obszar roboczy pamięci. Przy uruchamianiu serwera J2EE należy też pamiętać o
ustawieniu zmiennych środowiskowych JAVA_HOME i J2EE_HOME na odpowiednie
katalogi.
25.4. Gramatyka sun-j2ee-ri_1_3.dtd
Podczas tworzenia serwera J2EE RI 1.3.1 firma SUN niedopracowała kilku elementów.
Jednym z nich jest źle zdefiniowana gramatyka dla dokumentu sun-j2ee-ri_1_3.dtd.
Dodałem brakujące wpisy:
1665
1666
1667
1668
1669
<!ELEMENT
<!ELEMENT
<!ELEMENT
<!ELEMENT
<!ELEMENT
method (ejb-name, method-intf, method-name, method-params)>
method-intf (#PCDATA)>
method-name (#PCDATA)>
method-params (method-param?)>
method-param (#PCDATA)>
http://j2ee.ie.tu.koszalin.pl
-105-
Do znacznika web dodano także możliwość definiowania w jego wnętrzu znacznika
module-name.
1670 <!ELEMENT web (display-name, module-name, servlet*, context-root, resource-ref*, ejb-ref*,
resource-env-ref*)>
Gramatyka jest przydatna podczas edycji dokumentów sun-j2ee-ri.xml, które można
automatycznie weryfikować na podstawie podanego schematu.
http://j2ee.ie.tu.koszalin.pl
-106-

Podobne dokumenty