Sunteți pe pagina 1din 106

Bazele programarii pe platforma Java EE:

Componente Enterprise JavaBeans


Cristina Fierbinteanu

Cuprins
1 Fundamente ale limbajului Java
1.1 Clase si obiecte.
Interfete si clase abstracte . . . . . . . . .
1.2 Incapsularea, mostenirea si polimorfismul .
1.3 Compilarea si executia unui program Java
1.4 Pachete . . . . . . . . . . . . . . . . . . .
1.5 Arhive jar . . . . . . . . . . . . . . . . . .
1.6 Colectii si clase generice . . . . . . . . . .
1.7 Tratarea exceptiilor . . . . . . . . . . . . .
1.8 Executie concurenta si sincronizare . . . .
1.9 Aplicatii cu baze de date . . . . . . . . . .

1
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

2 Arhitectura aplicatiilor Java EE


2.1 Arhitecturi pe mai multe niveluri . . . . . . . . .
2.2 Clasificarea componentelor EJB . . . . . . . . . .
2.3 Un exemplu de programare pe platforma Java EE
2.4 Gestiunea tranzactiilor . . . . . . . . . . . . . . .
2.5 Includerea componentelor n documente Web . . .
3 Componente de tip sesiune
3.1 Componente de tip sesiune, fara stare . . . . .
3.2 Componente de tip sesiune, cu stare . . . . . .
3.3 Componente de tip singleton . . . . . . . . . .
3.4 Ciclul de viata al componentelor de tip sesiune

.
.
.
.

.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

. 1
. 3
. 6
. 6
. 8
. 8
. 11
. 12
. 15

.
.
.
.
.

.
.
.
.
.

21
21
22
23
27
29

.
.
.
.

33
34
38
41
43

.
.
.
.

4 Entit
ati JPA
45
4.1 Clasa corespunzatoare unei tabele . . . . . . . . . . . . . . . . 45
4.2 Fatada componentei de tip entitate . . . . . . . . . . . . . . . 47
i

ii

CUPRINS
4.3
4.4
4.5
4.6
4.7
4.8
4.9
4.10

Definirea unitatii de persistenta . . . . . . . . . . . .


Impachetarea si darea n folosinta a aplicatiei . . . .
Un exemplu de client . . . . . . . . . . . . . . . . . .
Ciclul de viata al entitatilor JPA . . . . . . . . . . .
Chei primare compuse . . . . . . . . . . . . . . . . .
Specificarea relatiilor dintre entitatile JPA . . . . . .
Implementarea relatiilor de mostenire dintre entitatile
Limbajul JPQL . . . . . . . . . . . . . . . . . . . . .

. . .
. . .
. . .
. . .
. . .
. . .
JPA
. . .

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

49
50
50
52
54
58
61
61

5 Componente bazate pe mesaje


63
5.1 Crearea resurselor . . . . . . . . . . . . . . . . . . . . . . . . . 63
5.2 Prima componenta bazata pe mesaje . . . . . . . . . . . . . . 64
5.3 Trimiterea mesajelor . . . . . . . . . . . . . . . . . . . . . . . 66

Anexe

73

A Definirea unei surse de date n GlassFish

73

B Studiu de caz

77

Bibliografie

99

List
a de figuri
1.1

Optiunile comenzii jar . . . . . . . . . . . . . . . . . . . . . . 20

2.1 Programarea unui server de aplicatii


2.2 Incarcarea unei arhive-1 . . . . . . .
2.3 Incarcarea unei arhive-2 . . . . . . .
2.4 Structura unei arhive WAR . . . . .
2.5 Incarcarea unei arhive WAR . . . . .

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

23
27
28
32
32

3.1

Ciclul de viata al componentelor de tip sesiune cu stare . . . . 44

4.1
4.2

Structura arhivei EJB-JAR . . . . . . . . . . . . . . . . . . . 51


Starile unei entitati JPA pe durata ciclului sau de viata . . . . 53

5.1
5.2
5.3
5.4
5.5

Functionarea unei componente bazata pe mesaje . .


Crearea atelierului de conexiuni JMS . . . . . . . .
Crearea destinatiei JMS . . . . . . . . . . . . . . .
Fisierele de jurnalizare ale serverului GlassFish V3 .
Mesajul primit nregistrat n fisierul de jurnalizare .

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

64
65
66
70
70

A.1 Definirea unui rezervor de conexiuni . . . . . . . . . . . . . . . 74


A.2 Definirea unei surse de date . . . . . . . . . . . . . . . . . . . 75
B.1 Definirea rezervorului de conexiuni:Pasul 1 . . . . . . . . . . . 96
B.2 Definirea rezervorului de conexiuni:Pasul 2 . . . . . . . . . . . 97
B.3 Definirea sursei de date . . . . . . . . . . . . . . . . . . . . . . 98

iii

iv

DE FIGURI
LISTA

Capitolul 1
Fundamente ale limbajului Java
1.1

Clase si obiecte.
Interfete si clase abstracte

In toate limbajele de programare modelarea domeniului aplicatiei se face folosind variabile de diferite tipuri (numere ntregi sau reale, caractere, siruri
de caractere). O variabila reprezinta un nume atribuit unei zone de memorie,
astfel ncat continutul acesteia (siruri de zero sau unu) sa fie interpretat ntrun anumit mod de catre program. Java nu face exceptie n ceea ce priveste
definirea variabilelor, nsa, n afara de clasicele variabile de tip numeric sau
caractere, foloseste variabile cu tipuri de date definite de catre utilizatori. De
fapt, majoritatea variabilelor definite ntr-un program Java sunt instante
ale unor tipuri de date definite de catre programator, numite clase. Clasele
sunt tipuri de date definite de c
atre programator. Instantele claselor se numesc obiecte.
Clasele permit modelarea aplicatiei foarte aproape de lumea reala, n
comparatie cu modelarea prin numere si caractere. O clasa este un model
general pentru un grup de obiecte din lumea reala. Exemple de clase ntrun sistem de administrare a activitatii unei universitati: Student, Profesor,
Curs, Orar. Exemple de obiecte n acelasi sistem: popescu, ionescu, bazeDeDate, orarAnDoiGrupaC. O clasa este caracterizata prin campuri(atribute)
si metode(operatii). Campurile definesc proprietatile unei multimi de obiecte
iar metodele definesc comportamentul acestora. De exemplu clasa Curs ar
putea contine campurile numeCurs, titular, nrCredite si metodele inscrieS1

CAPITOLUL 1. FUNDAMENTE ALE LIMBAJULUI JAVA

tudent, alocaSala.
Un obiect este o entitate tangibila din lumea reala, creat pe baza sablonului
reprezentat de clasa. Un obiect contine structura(campurile) si comportamentul(metodele) unei clase. Un obiect este o instant
a a unei clase.
O clasa abstracta este o clasa care contine cel putin o metoda abstracta,
adica o metoda fara implementare. O clasa abstracta nu poate fi instantiata,
iar subclasele ei trebuie sa implementeze metodele abstracte.
In Java, o interfata este o clasa care declara metode, fara a le defini.
Toate metodele unei interfete sunt metode abstracte. Deasemenea,
toate campurile unei interfete reprezinta constante. O clasa derivata dintr-o
interfata trebuie sa defineasca toate metodele declarate n interfata.

Supranc
arcarea metodelor
Se poate folosi acelasi nume pentru metode diferite ale unei clase, cu conditia
ca listele de argumente ale acestor metode sa fie diferite. Numele unei metode mpreuna cu lista de argumente ale acesteia definesc semn
atura unei
metode, care identifica n mod unic metodele unei clase.

Constructori
Atunci cand sunt create instante ale unei clase (obiecte) este apelata n mod
automat o metoda a clasei respective, numita constructor. Un constructor
este o metod
a f
ar
a rezultat care are acelasi nume cu numele clasei.
Constructorii pot fi suprancarcati, deci se pot defini mai multi constructori
pentru o clasa, fiecare avand o alta lista de argumente.

Accesul la c
ampurile de date si apelul metodelor
Pentru a folosi un camp al unui obiect se utilizeaza operatorul punct asezat
ntre numele obiectului si numele campului. De exemplu, o1.nume se refera
la campul(atributul) nume al obiectului o1.
Apelul unei metode membre a unei clase se realizeaza printr-o referinta la
o instanta a clasei respective, urmata de operatorul punct si numele metodei.

1.2. INCAPSULAREA, MOSTENIREA SI POLIMORFISMUL

1.2

Incapsularea, mostenirea si polimorfismul

Conceptele de baz
a ale program
arii orientate pe obiecte sunt
ncapsularea, mostenirea si polimorfismul.
Incapsularea este mecanismul care permite ascunderea datelor si a
metodelor n obiecte, definind reguli de acces la acestea. In general atributele obiectelor sunt private, adica ele pot fi citite si scrise doar prin
intermediul unor metode, si nu direct. Deasemenea obiectele definesc metode private, care nu pot fi apelate decat de catre alte metode ale aceluiasi
obiect. Principiul de programare folosit este acela ca nu trebuie facute publice decat acele metode ale obiectelor care definesc modul de comunicare al
acestora cu instante ale altor clase.
Mostenirea este o relatie ntre clase, prin care o clasa declara o alta ca
fiindu-i parinte. Clasa copil(subclasa, clasa derivata) mosteneste toate
proprietatile clasei parinte(superclasei, clasei de baza), adica toate campurile
si metodele acesteia. Subclasa poate defini atribute si metode aditionale si
redefini operatii specificate de catre clasa parinte n cazul n care este necesara o implementare diferita. O clasa poate fi derivata dintr-o singura alta
clasa (cu alte cuvinte o clasa poate avea o singura superclasa), nsa poate
implementa oricate interfete.
Polimorfismul reprezinta posibilitatea de a transmite un mesaj cu acelasi
nteles unor obiecte care implementeza operatia ceruta n moduri diferite.
Din punct de vedere conceptual, apelul unei metode a unui obiect este privit ca reprezentand transmiterea unui mesaj catre acel obiect. Pentru a
explica polimorfismul, sa consideram clasa Baza si subclasele Derivata1 si
Derivata2 ale acesteia. Sa presupunem ca fiecare subclasa defineste cate o
metoda afiseaza. In momentul compilarii unui program Java n care se transmite mesajul afiseaza unui obiect de tip Baza nu se stie care dintre metode
va fi apelata: cea definita n clasa Derivata1 sau cea definita n clasa Derivata2. Doar n momentul executiei, atunci cand se cunoaste subclasa careia i
apartine instanta catre care se trimite mesajul, se decide care dintre metode
sa fie apelata.
Programul urmator ilustreaza atat polimorfismul, cat si unele dintre con-

CAPITOLUL 1. FUNDAMENTE ALE LIMBAJULUI JAVA

ceptele discutate anterior (clase, clase derivate, obiecte, constructori, metode


suprancarcate, apelul metodelor).
class Baza{
String nume;
Baza(){//constructor fara parametri
nume = "Baza";
}
Baza(String n){//constructor
nume = n;
}
void afiseaza(){
System.out.println("Baza");
}
void afiseaza(String sir){
System.out.println(nume+sir);
}
}
class Derivata1 extends Baza{
Derivata1(){
nume = "Derivata1";
}
void afiseaza(){
System.out.println("Derivata1");
}
}
class Derivata2 extends Baza{
Derivata2(){
nume = "Derivata2";
}
void afiseaza(){
System.out.println("Derivata2");
}
}

1.2. INCAPSULAREA, MOSTENIREA SI POLIMORFISMUL

class Program{
public static void main(String[] args){
//creaza obiectul b1, instanta a clasei Baza
Baza b = new Baza();
//creaza obiectul d1, instanta a clasei Derivata1
Derivata1 d1 = new Derivata1();
//creaza obiectul d2, instanta a clasei Derivata2
Derivata2 d2 = new Derivata2();
b.afiseaza(); //din Baza
d1.afiseaza(); //din Derivata1
d2.afiseaza(); //din Derivata2
b = d1;
b.afiseaza(); //din Derivata1
b = d2;
b.afiseaza(); //din Derivata2
}
}
Programul anterior, memorat n fisierul Program.java, este compilat si
executat folosind urmatoarele comenzi:
C:\ProgrameJava>javac Program.java
C:\ProgrameJava>java Program
Baza
Derivata1

CAPITOLUL 1. FUNDAMENTE ALE LIMBAJULUI JAVA

Derivata2
Derivata1
Derivata2

1.3

Compilarea si executia unui program Java

Pentru aceasta carte am lucrat cu Java EE 6 si serverul de aplicatii GlassFish V3, care se descarca de la adresa http://java.sun.com. Dupa
instalare se poate verifica existenta mediului Java prin executia comenzii:
java -version
Primul pas n dezvoltarea unui program Java consta n editarea unui fisier
text continand codul programului. Fisierul trebuie sa aiba extensia .java,
de exemplu, numele fisierului ar putea fi PrimulProgram.java. Compilarea
programului se face utilizand comanda javac:
javac PrimulProgram.java
In urma compilarii rezulta un fisier executabil de catre masina virtuala
Java (JVM). Acest fisier are extensia .class. Programul este executat utilizand interpretorul de Java (comanda java):
java PrimulProgram

1.4

Pachete

Un grup de clase care servesc unui anumit tip de aplicatie sunt pastrate n
Java n acelasi director si alcatuiesc un pachet. Numele pachetului este un
sir de nume de directoare separate prin puncte, care reprezinta ierarhia de
directoare (calea) pana la subdirectorul n care sunt memorate clasele din
pachet. De exemplu, fisierele din pachetul cu numele programeJava.unu pot
fi memorate n directorul C:\cristina\programeJava\unu, cu conditia ca directorul C:\cristina sa fie specificat n variabila de mediu CLASSPATH.
Fie ca exemplu fisierul Salut.java din directorul C:\cristina\programeJava\unu.

1.4. PACHETE

package programeJava.unu;
public class Salut {
public static void main(String args[]){
System.out.println("Salut!");}}
Salut.java

Compilarea programului se face utilizand comanda urmatoare:


C:\cristina>javac programeJava\unu\Salut.java
In urma compilarii este creat Salut.class, fisierul cu cod de octeti Java,
n directorul C:\cristina\programeJava\unu. Acest fisier este executabil pe
masina virtuala Java, cu una dintre urmatoarele comenzi:
C:\cristina>java programeJava.unu.Salut
Salut!
sau
C:\>java -classpath C:\cristina programeJava.unu.Salut
Salut!
Pentru a utiliza ntr-un program o clasa dintr-un alt pachet este necesara
folosirea n program a unei instructiuni import. Prima instructiune import
din exemplul urmator permite utilizarea n program a clasei Salut din pachetul programeJava.unu. Al doilea exemplu ilustreaza o instructiune import
care permite utilizarea n program a tuturor claselor definite n pachetul
programeJava.unu.
import programeJava.unu.Salut;
import programeJava.unu.*;

CAPITOLUL 1. FUNDAMENTE ALE LIMBAJULUI JAVA

1.5

Arhive jar

Arhivele Java (fisiere cu extensia jar) sunt folosite pentru a mpacheta ntrun singur fisier mai multe clase Java (fisiere cu extensia class). Algoritmul
de compresie folosit este algoritmul ZIP standard. In afara de clasele Java,
o arhiva de tip jar mai poate contine un director cu numele META-INF, n
care se pastreaza anumite fisiere de configurare si fisierul MANIFEST.MF cu
atribute referitoare la acel pachet (numele autorului, clasa principala, structura de directoare, etc.). Atat pentru crearea si actualizarea arhivelor jar,
cat si pentru extragerea fisierelor din arhiva, se foloseste comanda jar, care
face parte din Java Development Kit. O arhiva JAR poate fi folosita direct
n CLASSPATH, fara a fi necesara dezarhivarea si listarea n CLASSPATH
a tuturor componentelor din arhiva. Un fisier JAR poate fi executabil.
Figura 1.1 ilustreaza optiunile comenzii jar.

1.6

Colectii si clase generice

Pachetul java.util contine biblioteca API Collection(Collection Framework),


n care sunt definite clase corespunzatoare unor structuri de date precum
Set, List, ArrayList, LinkedList, Vector, Map, Hashtable, Stack, etc.
Aceste clase definesc metode de nivel nalt pentru cautarea si sortarea elementelor lor. Obiectele claselor din cadrul de lucru pentru colectii utilizeaza
o referinta Object pentru a indica spre elementele lor, astfel ncat n cadrul
aceleiasi liste, de exemplu, se pot stoca tipuri diferite de obiecte, ca n programul Colectii redat mai jos.
import java.util.ArrayList;
class Colectii{
public static void main(String[] args){
ArrayList studenti = new ArrayList();
studenti.add(1);
Studenti me = new Studenti("Popescu","Cristina",31);
studenti.add(me);

1.6. COLECT
II SI CLASE GENERICE

String nume = "Gogu";


studenti.add(nume);
for(int i=0; i<studenti.size(); i++){
System.out.println(studenti.get(i));
}
}
}
class Studenti{
String nume;
String prenume;
int varsta;
Studenti(String n, String p, int v){
nume=n; prenume=p; varsta=v;
}
public String toString(){
return nume + " " + prenume + " ";
}
}
Colectii.java

La compilare nu rezulta erori, ci doar warning-uri, cate unul pentru


fiecare adaugare n lista a unei referinte neverificate. Totusi, programul
functioneaza, n lista fiind adaugate obiecte de diferite tipuri.
C:\ProgrameJava\unu>javac Colectii.java
Note: Colectii.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.

10

CAPITOLUL 1. FUNDAMENTE ALE LIMBAJULUI JAVA

C:\ProgrameJava\unu>java Colectii
1
Popescu Cristina
Gogu
Pentru a mbunatati securitatea din punctul de vedere al verificarii tipurilor au fost introduse n Java 5.0 clasele generice. Principalul rol al
acestora este de a permite scrierea de colectii sigure din punctul de vedere al
tipurilor. Iata n continuare programul Colectii, rescris pentru a folosi tipul
generic ArrayList<Studenti>, o lista ale carei elemente nu pot fi decat
referinte catre instante ale clasei Student. Incercarea de a adauga n lista
elemente de alt tip va fi semnalata de catre compilator prin eroare, asa cum
se vede mai jos.

import java.util.ArrayList;
class Colectii2{
public static void main(String[] args){
ArrayList<Studenti> studenti = new ArrayList<Studenti>();
studenti.add(1);
Studenti me = new Studenti("Popescu","Cristina",31);
studenti.add(me);
String nume = "Gogu";
studenti.add(nume);
for(int i=0; i<studenti.size(); i++){
System.out.println(studenti.get(i));
}
}
}
Colectii2.java

1.7. TRATAREA EXCEPT


IILOR

11

C:\ProgrameJava\unu>javac Colectii2.java
Colectii2.java:9: cannot find symbol
symbol : method add(int)
location: class java.util.ArrayList<Studenti>
studenti.add(1);
Colectii2.java:13: cannot find symbol
symbol : method add(java.lang.String)
location: class java.util.ArrayList<Studenti>
studenti.add(nume);
2 errors

1.7

Tratarea exceptiilor

Instructiunile susceptibile de a genera erori de executie se plaseaza ntr-un


bloc try. Instructiunile care vor fi executate n cazul aparitiei unei exceptii
se plaseaza ntr-un bloc catch.
try {
//apeluri de metode
}
catch(ex1) {
//trateaza exceptia ex1
}
catch(ex2) {
//trateaza exceptia ex2
}
.
.
.
finally {
//se executa ntotdeauna
}

12

CAPITOLUL 1. FUNDAMENTE ALE LIMBAJULUI JAVA

Fiecarui bloc try trebuie sa i corespunda cel putin un bloc catch sau un
bloc finally. Un bloc finally contine instructiuni care se executa indiferent
daca apare sau nu o exceptie. Deoarece secventa de program plasata n interiorul unui bloc try poate genera mai multe tipuri de exceptii se pot folosi
blocuri catch multiple, fiecare corespunzand unui anumit tip de eroare. Blocurile catch trebuie sa apara imediat dupa blocul try caruia i corespund si
este necesar sa fie plasate unul dupa celalalt.
O exceptie poate fi lansata explicit folosind cuvantul cheie throw urmat
de operatorul new, numele exceptiei si mesajul de eroare afisat la interceptarea acesteia.
throw new ExceptiaMea(Mesaj din ExceptiaMea);
Pentru anumite categorii de exceptii, numite exceptii verificate, dupa lansare compilatorul Java verifica existenta unui bloc catch corespunzator. Daca
o metoda lanseaza o exceptie verificata, dar nu o trateaza, este obligatoriu sa
o includa n lista sa de exceptii. Lista de exceptii a unei metode este introdusa de cuvantul cheie throws n antetul metodei, dupa lista de parametri.
IOException, SQLException, ClassNotFoundException sunt printre clasele de
exceptii verificate din Java.
public String cauta(int index) throws SQLException {...}
O clasa proprie pentru manipularea exceptiilor poate fi creata prin derivarea clasei Exception.
public class ExceptiaMea extends Exception {...}

1.8

Executie concurent
a si sincronizare

Firele de executie Java sunt secvente de cod executate concurent de catre


masina virtuala Java. Firele de executie separate au stive de apeluri separate
gestionate de JVM, dar nu sunt procese separate rulate de catre sistemul de
operare. Orice aplicatie Java porneste cu firul de executie principal care ruleaza metoda main() lansat de catre JVM. Ca programatori, putem defini si
alte fire de executie si scrie cod care le lanseaza n executie.

SI SINCRONIZARE
1.8. EXECUT
IE CONCURENTA

13

Un fir de executie Java este reprezentat printr-un obiect al clasei Thread.


Obiectul de activitate al firului de executie este reprezentat printr-un obiect
al unei clase care implementeaza interfata Runnable. Atat clasa Thread
cat si interfata Runnable sunt icluse n pachetul java.lang, care este importat automat.
Interfata Runnable contine o singura metoda, public void run(), prin intermediul careia clasa care implementeaza interfata Runnable defineste codul
care va fi rulat de catre firul de executie. Legatura dintre obiectul Runnable
care defineste codul si obiectul Thread care reprezinta firul de executie se
face prin intermediul constructorului clasei Thread, caruia i se transmite ca
parametru obiectul de tip Runnable. Pornirea firului de executie se face prin
apelul metodei start() a clasei Thread.
Dupa apelul metodei start(), firul de executie devine executabil. Aceasta
nseamna ca firul are propria stiva de apeluri si poate fi selectat pentru
executie de catre planificatorul JVM. Trecerea din starea executabil n
starea n executie nu se poate face prin program.
Functionarea corecta a unui program nu trebuie sa se bazeze pe modul
de lucru al planificatorului, care poate fi diferit de la o rulare la alta, chiar
sub aceeasi masina JVM, acelasi sistem de operare si acelasi procesor. De
aceea, datele critice trebuie protejate prin sincronizarea metodelor care le
manipuleaza. Pentru a determina o metoda sa fie accesibila unui singur fir
de executie la un moment dat se foloseste modificatorul synchronized n
declaratia metodei. Blocarea nu se face la nivel de metoda, ci la nivel de
obiect: daca un obiect are mai multe metode sincronizate nseamna ca nu
pot exista doua fire de executie care folosesc simultan oricare dintre metodele
sincronizate.
Pentru a ordona accesul firelor de executie la resursele partajate (e.g. procesorul sau o zona de memorie), fiecarui fir de executie i se asociaza (implicit
sau explicit, de catre programator) prioritati cu valori cuprinse ntre 1 si 10,
numarul 10 reprezentand prioritatea maxima. Programul urmator ilustreaza
doua fire de executie cu prioritati diferite.

14

CAPITOLUL 1. FUNDAMENTE ALE LIMBAJULUI JAVA

class FirTipUnu implements Runnable


{
public void run()
{
for (int i=0; i<201; i++)
{
System.out.println("Unu " + i);
}
}
}
class FirTipDoi implements Runnable
{
public void run()
{
for (int i=0; i<201; i++)
{
System.out.println("Doi " + i*i);
}
}
}
class FireExecutie {
public static void main(String[] args)
{
FirTipUnu firLent = new FirTipUnu();
FirTipDoi firRapid = new FirTipDoi();
Thread fir1 = new Thread(firLent);
Thread fir2 = new Thread(firRapid);
fir1.setPriority(Thread.MIN_PRIORITY);
fir2.setPriority(Thread.MAX_PRIORITY);
fir1.start();
fir2.start(); }}
Fire de executie cu priorit
ati diferite

1.9. APLICAT
II CU BAZE DE DATE

15

In intervalul dintre pornirea unui fir de executie prin apelarea metodei


start() si terminarea acestuia (normala, prin aruncarea unei exceptii sau
prin apelarea uneia dintre metodele stop() sau exit()), n afara de starea
de executie propriu-zisa, firul se mai poate afla ntr-una dintre urmatoarele
doua stari: de asteptare (asteptand n coada pentru a i se aloca procesorul)
sau de blocare.
Metoda sleep(), definita n clasa Thread, determina firul de executie curent sa si ntrerupa executia (trecand n starea blocat) pentru numarul de
milisecunde specificat de catre primul sau argument. In cazul existentei
unui al doilea parametru, acesta reprezinta numarul de nanosecunde care se
adauga la primul parametru pentru a obtine timpul total n care procesul
curent va dormi. Intreruperea unui fir de executie blocat de catre un alt
fir de executie genereaza exceptia verificata InterruptedException.
Metoda yield() a clasei Thread determina firul curent sa faca o pauza
(trecand din starea de executie n starea de asteptare) n care li se permite
executia celorlalte fire aflate n asteptare.
Apelul metodei join() determina trecerea firului de executie corespunzator
n starea blocat, asteptand terminarea sa (apelul metodei stop()).

1.9

Aplicatii cu baze de date

Pentru a lucra cu baze de date n Java avem nevoie de:


un driver JDBC pentru sistemul DBMS folosit
interfata de programare a aplicatiilor JDBC API
Clasele fundamentale ale interfetei JDBC API se gasesc n pachetul java.sql.
Alte clase apartinand interfetei JDBC API au fost grupate n pachetul javax.sql.
Un driver este un program care asigura comunicarea ntre mediul Java
si un sistem DBMS. Driverul este specific fiecarui DBMS n parte, fiind n
general implementat de catre producatorul sistemului DBMS. Calea catre

16

CAPITOLUL 1. FUNDAMENTE ALE LIMBAJULUI JAVA

driverul bazei de date trebuie specificata n variabila de mediu CLASSPATH.


Exista patru tipuri de drivere ce pot fi folosite pentru realizarea conexiunilor prin intermediul JDBC, si anume:
Punte JDBC-ODBC (Tip 1)
Driver JDBC - Driver nativ (Tip 2)
Driver JDBC - Server (Tip 3)
Driver JDBC nativ (Tip 4)
Cea mai simpla solutie se obtine prin folosirea driverului JDBC nativ,
care este o implementare n Java a protocolului de retea al bazei de date,
traducand cererile JDBC direct n cereri catre baza de date.
Un driver de tipul al 2-lea ar putea oferi performante mai bune, dezavantajul constand n faptul ca este necesara instalarea unor biblioteci pe masina
locala. Un driver de tipul al 2-lea traduce cererile JDBC n apeluri catre
driverul nativ al bazei de date.
Inainte de a se conecta la un sistem DBMS, un program n Java trebuie sa ncarce driverul JDBC corespunzator. Aceasta operatie este realizata prin intermediul metodei Class.forName() al carei argument reprezinta
numele driverului (de exemplu org.apache.derby.jdbc.EmbeddedDriver). A
doua operatie necesara naintea interactiunii propriu-zise cu baza de date
este conectarea la sistemul DBMS, folosind un nume de utilizator si o parola care au fost create n prealabil de catre administratorul bazei de date.
Conectarea la sistemul DBMS este realizata de catre metoda DriverManager.getConnection, careia i se transmit ca argumente adresa URL a bazei de
date, numele si parola utilizatorului.
Interogarile sunt transmise din program catre sistemul DBMS prin intermediul unui obiect de tip Statement, apeland metoda executeQuery. Rezultatul interogarii este obtinut ntr-o instanta a clasei ResultSet. Operatiile
de tipul INSERT, UPDATE, CREATE TABLE, DROP TABLE sau ALTER TABLE, care nu au ca rezultat o multime de nregistrari, se efectueaza

1.9. APLICAT
II CU BAZE DE DATE

17

apeland metoda executeUpdate(), tot prin intermediul unui obiect de tip Statement.
Imediat dupa executia unei interogari, n tabela rezultat cursorul (pozitia
curenta n tabela) este pozitionat pe prima nregistrare a acestei tabele. Metoda next() are ca rezultat o valoare booleana care indica existenta a cel
putin nca unei nregistrari dupa nregistrarea curenta din tabela (instanta a
clasei ResultSet) corespunzatoare. Metoda getString() a clasei ResultSet are
ca rezultat valoarea din coloana cu numele care i se transmite ca parametru.
Interactiunea programului Java cu sistemul DBMS se ncheie cu nchiderea
conexiunii, folosind metoda close() a clasei Connection. Instantele clasei ResultSet definite pentru o anumita conexiune sunt nchise automat la nchiderea
conexiunii respective, nsa nchiderea explicita a tuturor obiectelor de tip ResultSet folosite este o buna practica de programare.

Java DB
Java DB este o versiune a sistemului Derby(Apache) pentru baze de date.
Aceasta versiune este dezvoltata n ntregime n tehnologie Java si este n
prezent mpachetata n serverul de aplicatii GlassFish.
Executia comenzilor SQL
Instrumentul pe care l avem la dispozitie pentru executia comenzilor SQL n
Java DB, atat a comenzilor de interogare cat si a celor de creare a tabelelor
si manipulare a datelor, se numeste ij . Interfata utilizatorului cu ij este
linia de comanda.
Pe calculatorul meu, ij se gaseste n directorul C:\Sun\SDK\javadb\bin.
Pentru a deschide o conexiune la baza de date, a crea o tabela si a insera
valori n aceasta am executat urmatoarele comenzi:

C:\Sun\SDK\javadb\bin>ij
ij>connect jdbc:derby:student;
create=true; user=profesor;

18

CAPITOLUL 1. FUNDAMENTE ALE LIMBAJULUI JAVA


password = parolaprofesor
as my_connection;

ij>CREATE TABLE t1(


nume VARCHAR(30),
varsta INTEGER);
ij>INSERT INTO t1 VALUES
(Cristina,30);
ij>SELECT * FROM t1;
ij>exit;
C:\Sun\SDK\javadb\bin>

Un program simplu cu JDBC


import java.sql.*;
public class Student {
public static void main(String[] args) {
Connection dbConnection = null;
String dbUrl =
"jdbc:derby:C:\\Sun\\SDK\\javadb\\bin\\student;"+
"user=profesor;password=parolaprofesor";
try{
Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
//incarca driver JDBC pt JavaDB
}
catch(ClassNotFoundException e) {
e.printStackTrace();
System.out.println("Eroare incarcare driver!\n" + e);

1.9. APLICAT
II CU BAZE DE DATE

19

}
try{
dbConnection=DriverManager.getConnection(dbUrl);
Statement stmt= dbConnection.createStatement();
ResultSet rs =
stmt.executeQuery(
" SELECT * FROM student");
while (rs.next()) {
System.out.println (
rs.getString ("nume") + "," +
rs.getString ("prenume") + "," +
rs.getString ("email"));
}
stmt.close();
}
catch(SQLException e) {
e.printStackTrace();
}
finally{rs.close();dbConnection.close();}
}
}
O aplicatie client-server

Programul se executa precizand n linia de comanda pentru masina virtuala Java calea catre driverul Java DB pentru SQL(derby.jar), ca n exemplul de mai jos:
java -classpath .;C:\Sun\SDK\javadb\lib\derby.jar Student

20

CAPITOLUL 1. FUNDAMENTE ALE LIMBAJULUI JAVA

Figura 1.1: Optiunile comenzii jar

Capitolul 2
Arhitectura aplicatiilor Java EE
2.1

Arhitecturi pe mai multe niveluri

Java EE(Enterprise Edition) reprezinta o tehnologie de programare a sistemelor bazate pe servere de aplicatii. Aceasta tehnologie foloseste diferite
tipuri de componente software administrate de catre serverul de aplicatii,
care actioneaza ca intermediari ntre programele clientilor si alte servere specializate (de exemplu servere de baze de date). Daca Java este un limbaj de
programare, Java EE este un standard care specifica, pe de o parte, modul de
realizare a sistemelor bazate pe servere de aplicatii, pe de alta parte modul de
functionare al serverului de aplicatii si serviciile pe care acesta trebuie sa
le puna la dispozitie, asfel ncat aplicatia sa fie independenta de serverul de
aplicatii. Am inclus cuvantul servicii ntre ghilimele, astfel ncat el sa nu
duca cititorul cu gandul la notiunea de servicii Web, ci sa fie luat n sensul
sau mai general, de functii sau metode pe care aplicatiile le au la dispozitie
n mediul creat de serverul de aplicatii. Cu alte cuvinte, principiul write
once, run anywhere este valabil si n privinta aplicatiilor Java EE, n sensul
ca orice aplicatie care este scrisa n conformitate cu standardul trebuie sa
functioneze la fel de bine pe Oracle WebLogic, IBM WebSphere, Sun GlassFish, etc. (Am enumerat cele mai cunoscute servere de aplicatii de astazi.)
Arhitectura sistemelor dezvoltate n tehnologia discutata aici este dezvoltata pe trei niveluri: client, server de aplicatii, baza de date, si reprezinta
o evolutie a arhitecturilor mai vechi, de tip client-server. Avand n vedere
ca n interiorul serverului de aplicatii exista doua containere, unul care ad21

22

CAPITOLUL 2. ARHITECTURA APLICAT


IILOR JAVA EE

ministreaza componente Web(pagini JSP si JSF), altul care administreaza


componente de tip EJB (Enterprise JavaBeans), aplicatia are n general chiar
patru niveluri: client(browser de Web), container Web (pagini JSF sau JSP),
container de componente EJB, baza de date. In aceasta carte sunt prezentate doar componentele de tip EJB. Avantajul major al folosirii componentelor de tip Enterprise JavaBeans este acela c
a administrarea
tranzactiilor, implementarea regulilor de securitate, lucrul cu mai
multe fire de executie (multithreading), preg
atirea n avans si alocarea resurselor (resource pooling), managementul ciclului de viat
a
al componentelor si c
aut
arile simple n baza de date sunt asigurate de c
atre containerul EJB, programatorul put
andu-se concentra
asupra implement
arii regulilor (logicii) specifice fiec
arei aplicatii n
parte.

2.2

Clasificarea componentelor EJB

Componentele Enterprise JavaBeans se clasifica n trei categorii: componente


de tip sesiune, entitati JPA(Java Persistence API) si componente bazate pe
mesaje. La randul lor, componentele de tip sesiune sunt de trei feluri: componente de tip sesiune cu stare (stateful session beans), componente de
tip sesiune fara stare (stateless session beans) si componente singulare
(singleton session beans).
Componentele de tip sesiune sunt cele care definesc si implementeaza o
serie de metode (asa numitele reguli de business) pe care programul client le poate apela. O componenta de tip sesiune este definita de o interfata
(locala sau la distanta) si de clasa care o implementeaza. In cadrul aceleiasi
masini virtuale Java, apelul metodelor puse la dispozitie de componenta se
face prin intermediul interfetei locale (de exemplu cazul unei componente de
tip sesiune care apeleaza metode ale altei componente de acelasi tip). In
cazul n care clientul componentei de tip sesiune se afla(executa) pe o alta
masina (virtuala Java), pentru apelul metodelor este folosita interfata remote. Componentele de tip sesiune pot sa si pastreze starea ntre doua
apeluri de metode, n acest caz ele fiind numite componente de tip sesiune
cu stare.
Entitatile JPA (Java Persistence API entities) corespund tabelelor din

2.3. UN EXEMPLU DE PROGRAMARE PE PLATFORMA JAVA EE 23


bazele de date. Totalitatea instantelor entitatilor JPA reprezinta contextul
de persistent
a al unei aplicatii. Entitatile dintr-un context de persistenta
sunt administrate de catre un administrator de context (entity manager).
Aceste notiuni sunt explicate n Capitolul 4.

Figura 2.1: Programarea unui server de aplicatii

2.3

Un exemplu de programare pe platforma


Java EE

Pentru a apela metode ale unei componente aflate pe aceeasi masina virtuala Java, un program client va folosi o interfata locala (o interfata Java
standard care contine metodele componentei). O interfata locala poarta ad-

24

CAPITOLUL 2. ARHITECTURA APLICAT


IILOR JAVA EE

notarea @Local1 . Metodele unei componente aflate la distanta (pe alta


masina virtuala Java) pot fi apelate prin intermediul unei interfete marcata
cu adnotarea @Remote.
Definitia unei interfete nu este obligatorie pentru accesul la serviciile componentelor de tip sesiune, acesta putandu-se realiza direct prin metodele
publice ale unei componente fara interfata.
In continuare este prezentata definitia unei interfete Salut, care contine o
singura metoda, saluta.
package firstBean;
import javax.ejb.Remote;
@Remote
public interface Salut{
public String saluta(String nume);
}
Salut.java

Clasa care implementeaza interfata este definita n fisierul SalutEJB.java,


al carui continut este redat mai jos. Definitia clasei este prefixata cu adnotarea @Stateless, care i semnaleaza containerului Java EE ca este vorba
de o componenta de tip sesiune, fara stare. Pentru componentele cu stare se
foloseste adnotarea @Stateful.
package firstBean;
import javax.ejb.*;
@Stateless
public class SalutEJB implements Salut{
1

Adnotarile(annotations) reprezint
a o modalitate de a marca anumite elemente ale
programelor Java cu scopul de a controla executia unei aplicatii. Le puteti privi ca fiind
comentarii disponibile n momentul executiei, destinate masinii virtuale Java. Din punct de
vedere sintactic, o adnotare este un nume, care reprezint
a n general tipul unei componente
(de exemplu Stateful, Stateless, Resource, Table, Column, etc.), prefixat cu simbolul @ si
care se scrie naintea modificatorilor de acces care preced declaratiile claselor.

2.3. UN EXEMPLU DE PROGRAMARE PE PLATFORMA JAVA EE 25


public String saluta(String nume){
return "Salut,"+nume+"!";}
}
SalutEJB.java

In continuare este prezentat un program client, care foloseste un obiect


al clasei InitialContext pentru a gasi o instanta a clasei Salut si apeleaza
metoda salut. Componenta de tip sesiune este identificata prin itermediul
serviciilor JNDI, pe baza numelui sau (firstBean.Salut). Pentru a ntelege
afirmatiile precedente, luati n considerare si urmatoarele precizari:
- Localizarea componentelor n retea pe baza unui simplu nume presupune existenta unui context n cadrul caruia fiecare nume este asociat
unei entitati concrete.
- Un serviciu de nume este o aplicatie care asociaza fiecarui nume o
entitate concreta.
- Java Naming and Directory Interface (JNDI) reprezinta un set de pachete care contin clasele Java necesare pentru obtinerea accesului la
diverse servicii de nume.
- Parametrii care permit clientilor sa localizeze resursele pot fi specificati
ca argumente ale constructorului unei instante a clasei InitialContext,
n fisierul jndi.properties sau n linia de comanda care invoca masina
virtuala Java. In exemplul de mai jos, arhiva appserv-rt.jar contine
fisierul jndi.properties. Localizarea serverului de aplicatii se face prin
intermediul parametrului org.omg.CORBA.ORBInitialHost.
package firstBeanClient;
import firstBean.Salut;
import javax.naming.InitialContext;
public class FirstBeanClient{
public static void main(String[] args) throws Exception
{
InitialContext context = new InitialContext();

26

CAPITOLUL 2. ARHITECTURA APLICAT


IILOR JAVA EE

Salut beanInstance = (Salut) context.lookup("firstBean.Salut");


System.out.println(beanInstance.saluta(args[0]));
}
}
FirstBeanClient.java

Pentru a testa functionarea componentei se vor parcurge urmatorii pasi:


1. C:\EJB>set CLASSPATH=.;C:\glassfishv3\glassfish\lib\javaee.jar
2. Se compileaza interfata componentei, clasa care o implementeaza si
programul client.
C:\EJB>javac -d . firstBean/*.java
C:\EJB>javac -d . firstBeanClient/*.java
3. Se mpacheteaza clasa si interfata corespunzatoare componentei de tip
sesiune n arhiva FirstBeanJar.jar.
C:\EJB>jar cvf FirstBeanJar.jar firstBean\
4. Se ncarca arhiva FirstBeanJar.jar pe serverul de aplicatii, folosind, de
exemplu, consola grafica de administrare (Figura 2.2).
5. Se executa programul client.
C:\EJB>java -classpath ->
->C:\glassfishv3\glassfish\lib\appserv-rt.jar; ->
->C:\glassfishv3\glassfish\lib\javaee.jar; ->
C:\EJB firstBeanClient.FirstBeanClient Cristina
Implicit serverul de aplicatii se gaseste pe masina locala, comanda precedenta fiind echivalenta cu urmatoarea:
C:\EJB>java -classpath ->
C:\glassfishv3\glassfish\lib\appserv-rt.jar; ->
->C:\glassfishv3\glassfish\lib\javaee.jar; ->
->C:\EJB -D org.omg.CORBA.ORBInitialHost = localhost ->
firstBeanClient.FirstBeanClient Cristina

2.4. GESTIUNEA TRANZACT


IILOR

27

Figura 2.2: Incarcarea unei arhive folosind consola grafica de administrare-1

2.4

Gestiunea tranzactiilor

In limbajul ingineriei software tranzactiile reprezinta tehnologia care asigura


integritatea datelor, controland accesul concurent la date si mpiedicand actualizarea partiala n cazul aparitiei unei erori n mijlocul executiei unui
program. Putem defini o tranzactie ca pe un grup de operatii dintre care fie
se executa toate, fie nu se executa niciuna. O tranzactie este o unitate
indivizibil
a de lucru (unit of work). De exemplu, ntr-o aplicatie de
eLearning, modificarea unei note poate necesita mai multi pasi:
begin
modifica nota
recalculeaza media
refa clasamentul
commit
O tranzactie trebuie sa fie atomica (se executa n totalitate sau nu se
executa deloc), consecventa (pastreaza integritatea bazei de date), izolata
(starile intermediare ale sistemului nu sunt vizibile n exterior pana la ncheierea

28

CAPITOLUL 2. ARHITECTURA APLICAT


IILOR JAVA EE

Figura 2.3: Incarcarea unei arhive folosind consola grafica de administrare-2

tranzactiei) si durabila (nainte de ncheierea tranzactiei, modificarile efectuate de aceasta vor fi scrise ntr-o memorie fizica, astfel ncat sa poata fi
recuperate chiar n cazul unei caderi a sistemului) (ACID).
Intr-o componenta de tip sesiune sau bazata pe mesaje care nu specifica tipul de gestiune a tranzactiilor, codul pe care l scrieti nu va contine
instructiuni care sa marcheze nceputul sau sfarsitul tranzactiilor, acestea
fiind setate de catre container. Containerul va ncepe, suspenda si ncheia
tranzactiile n functie de valoarea unui atribut specificat pentru fiecare metoda
cu adnotarea @TransactionAttribute. Valoarea acestui atribut poate fi
una dintre urmatoarele: REQUIRED, REQUIRES NEW, MANDATORY,
NOT SUPPORTED, SUPPORTS, NEVER.
Interfata de programare JTA (Java Transaction API) defineste metode
pentru initierea si terminarea explicita a tranzactiilor (begin, commit, rollback).

2.5. INCLUDEREA COMPONENTELOR IN DOCUMENTE WEB

2.5

29

Includerea componentelor n documente


Web (JSP,JSF)

Putin
a istorie
Documentele JSP sunt pagini HTML n care sunt incluse secvente de cod
Java si XML. JSP-urile sunt transformate de catre serverul Web n servleturi, avantajul lor fiind acela al scrierii ntr-o maniera mai simpla a aplicatiei.
Servlet-urile sunt clase Java care se executa pe serverul Web n momentul primirii unei cereri de la un client (browser Web), reprezentand astfel o
modalitate de a genera n mod dinamic continutul paginilor Web. Servleturile sunt implementarea Java a standardului Common Gateway Interface
(CGI), care specifica modul de comunicare ntre clientii si serverele de Web,
atunci cand raspunsul transmis clientului de catre server se obtine n urma
executiei pe server a unui program cu parametri primiti de la client. Servleturile sunt gestionate de servere Web special concepute pentru a folosi aceasta
tehnologie (e.g. Tomcat).
Tehnologia JavaServer Pages (JSP) foloseste un limbaj de expresii
(Expression Language, prescurtat EL) pentru a folosi date ale unor obiecte
externe. La nceput acest limbaj s-a numit JavaServer Pages Standard Tag
Library (JSTL). De exemplu, expresia ${student.nume} este folosita pentru a cauta componenta student si a apela metoda citesteNume a acesteia,
afisand n pagina valoarea atributului(campului) nume(numele studentului).
Tehnologia JavaServer Faces (JSF) adauga tehnologiei JSP un model
de componente de interfata cu utilizatorul (componente UI) care include:
un set de clase care definesc componente grafice de interfata (componente UI).
un mecanism pentru tratarea evenimentelor generate de catre componentele UI.
un mecanism de validare a datelor corespunzatoare componentelor UI.
Pentru tehnologia JavaServer Faces a fost creat un nou limbaj de expresii
care permite:

30

CAPITOLUL 2. ARHITECTURA APLICAT


IILOR JAVA EE
conectarea evenimentelor generate de componentele grafice la programele de pe server care trateaza aceste evenimente.
realizarea legaturii dintre componentele grafice de interfata si obiectele
corespunzatoare de pe server.
asocierea cu componentele grafice de interfata a unor metode de conversie si validare a datelor.

Insa limbajul de expresii folosit de catre tagurile JSTL intra n conflict


cu cel folosit de catre JSF. De aceea a fost creat un nou limbaj de expresii,
UEL(Unified Expression Language), care reprezinta n esenta unificarea celor
doua limbaje de expresii din JSP si JSF.

O pagin
a JSP simpl
a
<%@page import="student.AfiseazaStudent"%>
<html>
<head>
<title>Prima pagina JSP</title>
</head>
<body>
<%
javax.naming.InitialContext ctx =
new javax.naming.InitialContext();
AfiseazaStudent beanInstance = (AfiseazaStudent)
ctx.lookup(AfiseazaStudent.class.getName());
String result = beanInstance.afiseaza(777);
%>
<%= result %>
</body>
</html>
student.jsp

In afara de cod HTML si XML, o pagina JSP mai poate contine:


directive
declaratii, expresii, cod Java (tag-uri)

2.5. INCLUDEREA COMPONENTELOR IN DOCUMENTE WEB

31

Directivele reprezinta intructiuni care sunt prelucrate de catre server (containerul JSP) atunci cand pagina este compilata. De exemplu cu directiva
page se definesc atribute valabile pentru ntreaga pagina JSP. Atributul import, similar cu instructiunea import din Java, reprezinta o lista de clase
care pot fi folosite n declaratiile, expresiile si fragmentele de cod Java din
interiorul paginii JSP.
Fragmentele de cod Java ncep cu secventa de caractere < % si se ncheie
cu secventa % >.
Expresiile ncep cu secventa de caractere < % = si se ncheie cu secventa
% >. Expresiile sunt evaluate la run time si rezultatul lor inserat n iesirea
servlet-ului (afisat).

Module Web
Un modul web al unei aplicatii de tip Enterprise este mpachetat ntr-o arhiv
a Java cu extensia war. Structura generala a unei arhive WAR este
ilustrata n Figura 2.4. Daca modulul web contine numai pagini JSP si pagini statice fisierul de configurare (deployment descriptor) web.xml nu este
necesar. Acesta este folosit doar n cazul tehnologiei JavaServer Faces, pentru specificarea unor informatii de securitate sau daca se doreste modificarea
unor configurari realizate prin adnotari la nivelul componentelor web.
Comanda folosita pentru crearea arhivei este urmatoarea:
C:\WebApps>jar cvf StudentApp.war student.jsp WEB-INF/lib/
In WEB-INF/lib exista arhiva StudentApp.jar, continand componenta
AfiseazaStudent, pe care am construit-o folosind comanda:
C:\EJB>jar cf StudentApp.jar student\

32

CAPITOLUL 2. ARHITECTURA APLICAT


IILOR JAVA EE

Figura 2.4: Structura unei arhive WAR

Figura 2.5: Incarcarea unei arhive WAR

Capitolul 3
Componente de tip sesiune
Componentele de tip sesiune sunt folosite n Java EE pentru a implementa
asa-numitele reguli de business, adica acele operatii, functii, actiuni specifice domeniului aplicatiei. Componentele de tip sesiune sunt folosite n cadrul
conversatiilor (sesiunilor) clientilor cu serverul.
Exista trei categorii de componente de tip sesiune:
componente de tip sesiune cu stare(stateful session beans)
componente de tip sesiune f
ar
a stare(stateless session beans)
componente singulare(singleton session beans)
In cazul componentelor de tip sesiune fara stare, sesiunea (conversatia)
clientului cu serverul este alcatuita dintr-un singur apel de metoda.
Daca, n logica procesului de business implementat, invocarea unei metode este dependenta de apelul sau precedent, sunt folosite componentele de
tip sesiune cu stare, n cazul carora sesiunea poate contine mai multe apeluri
(ale aceleiasi metode sau ale unor metode diferite ale aceleiasi componente)
iar starea asociata clientului este mentinuta n componenta pe tot parcursul
sesiunii (de la un apel de metoda la altul). Exemplul clasic l constituie implementarea unui cos de cumparaturi ntr-o aplicatie de comert electronic. Clasa
CosDeCumparaturi va cotine o metoda adaugaInCos; aceasta metoda
trebuie sa cunoasca starea clientului anterioara fiecarui apel (continutul
33

34

CAPITOLUL 3. COMPONENTE DE TIP SESIUNE

cosului de cumparaturi). Altfel spus, serverul trebuie sa-i aloce unui client aceeasi instanta a clasei care implementeaza cosul de cumparaturi, de
fiecare data cand clientul apeleaza metoda adaugaInCos. Astfel, implementarea se face printr-o componenta de tip sesiune cu stare. (Imaginati-va
un cumparator ntr-un supermarket, care ar pune articolele pe care le ia de
pe rafturi, de fiecare data n alt cos! Acest scenariu ar corespunde n Java
EE folosirii componentelor fara stare.) Prin contrast, verificarea validitatii
unui card de credit, de exemplu, nu presupune alocarea aceleiasi instante a
unei componente de tip sesiune unui client care solicita aceasta operatie n
mod repetat. Verificarea validitatii unui card de credit se poate implementa
prinr-o componenta de tip sesiune fara stare.

3.1

Componente de tip sesiune, f


ar
a stare

In Capitolul 2 am prezentat deja o componenta de tip sesiune, fara stare.


Ceea ce aduce nou exemplul din aceasta sectiune este folosirea unei baze
de date. Observati, n clasa AfiseazaStudentBean, adnotarea @Resource,
care precede declaratia campului ds de tip DataSource: se specifica astfel ca
valoarea acestui camp va fi atribuita (injectata) de catre containerul EJB
la momentul executiei. Mecanismul se numeste dependency injection(DI).
Resursa injectata este o sursa de date cu numele jdbc/student. In Anexa A
este prezentat modul n care se face definirea unei surse de date folosind consola grafica de administrare a serverului GlassFish.
Pentru exemplul din aceasta sectiune am construit tabela student, folosind
urmatoarea comanda SQL:
CREATE TABLE student(
studentID INTEGER PRIMARY KEY,
nume VARCHAR(30),
prenume VARCHAR(30),
email VARCHAR(40) );
Am introdus n tabela, folosind instructiunea INSERT (a se vedea si
Anexa A), nregistrarile din Tabela 3.1.
Vom defini o componenta de tip sesiune, fara stare, care contine o metoda
cu numele afiseaza. Metoda are un singur parametru, de tip numar ntreg,

A
STARE
3.1. COMPONENTE DE TIP SESIUNE, FAR
STUDENTID
111
222
333
444
555
777

NUME
Popescu
Ionescu
Petrescu
Vasilescu
Georgescu
Bond

PRENUME
Ion
Vasile
Petre
Mihai
Gogu
James

35

EMAIL
ipop@mycomp.com
vion@mycomp.com
ppet@mycomp.com
mvas@mycomp.com
ggeo@mycomp.com
jbond@mycomp.com

Tabela 3.1: Tabela student


care reprezinta numarul matricol al unui student (n tabela noastra STUDENTID). Rezultatul metodei este de tip sir de caractere (String), continand
numele, prenumele si emailul studentului cu id-ul specificat de argumentul
metodei.
Sa ne reamintim ca orice componenta de tip sesiune presupune existenta
unei interfete si a unei clase, definitia clasei fiind prefixata cu adnotarea
@Stateless. Mai jos sunt reproduse cele doua definitii din exemplul considerat aici.

Definitia interfetei
package student;
import javax.ejb.Remote;
@Remote
public interface AfiseazaStudent{
public String afiseaza(int sid);
}
AfiseazaStudent.java

Definitia clasei
package student;
import java.sql.*;

36

CAPITOLUL 3. COMPONENTE DE TIP SESIUNE

import javax.ejb.*;
import javax.annotation.Resource;
@Stateless(name="AfiseazaStudent")
public class AfiseazaStudentBean implements AfiseazaStudent{
@Resource(name="jdbc/student")
private javax.sql.DataSource ds;
private Connection con;
private Statement st;
private ResultSet rs;
public String afiseaza(int sid)
{
try{
con = ds.getConnection();
st = con.createStatement();
rs = st.executeQuery
("SELECT * FROM student WHERE studentid = " + sid);
rs.next();
return rs.getString("nume")+ "," +
rs.getString ("prenume") + "," +
rs.getString ("email");
}
catch(Exception e){
return e.toString();
}
}
}
AfiseazaStudentBean.java

Pentru a putea executa interogari SQL, programul trebuie sa se conecteze la serverul de baze de date, apeland metoda getConnection() a clasei
DataSource din pachetul javax.sql. Transmiterea unei interogari SQL catre
serverul de baze de date se face prin intermediul unei instante a clasei Statement, care defineste metoda executeQuery(). Pentru a crea o instanta a

A
STARE
3.1. COMPONENTE DE TIP SESIUNE, FAR

37

clasei Statement se foloseste metoda createStatement() a clasei Connection.


Metoda executeQuery() primeste ca parametru un sir de caractere care reprezinta interogarea SQL pe care o transmitem catre sistemul de gestiune a
bazei de date(DBMS). Rezultatul obtinut de la sistemul DBMS este disponibil ntr-un obiect al clasei ResultSet, care defineste si metodele necesare
pentru prelucrarea acestui rezultat n programul Java.
In continuare este prezentat un exemplu de client al componentei de tip
sesiune AfiseazaStudent. Acest client foloseste, pentru localizarea componentei, Java Naming and Directory Interface(JNDI). JNDI este un serviciu
pus la dispozitie de platforma Java EE pentru localizarea resurselor folosite
de programe. Comparati acest mecanism cu cel de dependency injection,
explicat mai sus. Observati ca, n cazul JNDI, numele resursei este codificat
n program (hard-coded), programul avand n acelasi timp responsabilitatea
de a obtine o referinta la resursa cautata prin apelul efectiv al unei metode
(metoda lookup a clasei InitialContext).
package clienti;
import student.AfiseazaStudent;
import javax.naming.InitialContext;
public class StudentClient{
public static void main(String[] args) throws Exception
{
InitialContext ctx = new InitialContext();
AfiseazaStudent beanInstance = (AfiseazaStudent)
ctx.lookup(student.AfiseazaStudent);
System.out.println(beanInstance.afiseaza(Integer.parseInt(args[0])));
}
}
StudentClient.java

Pentru a testa exemplul de mai sus se vor executa urmatoarele comenzi:


1. C:\EJB>set CLASSPATH = .;C:\glassfishv3\glassfish\lib\javaee.jar
2. C:\EJB>javac -d . student/*.java
C:\EJB>javac clienti/StudentClient.java

38

CAPITOLUL 3. COMPONENTE DE TIP SESIUNE


3. C:\EJB>jar cf StudentApp.jar student\
4. Se ncarca arhiva FirstBeanJar.jar pe serverul de aplicatii.
5. Se executa programul client:
C:\EJB>java
-classpath
C:\glassfishv3\glassfish\lib\appservrt.jar;C:\glassfishv3\glassfish\lib\javaee.jar;.
clienti.StudentClient 777
Apr 19, 2010 2:17:29 PM
com.sun.enterprise.transaction.JavaEETransactionManagerSimplified
initDelegates
INFO:
Using
com.sun.enterprise.transaction.jts.JavaEETransactionManagerJTSDelegate
as the delegate
Bond,James,jbon@mycomp.com

3.2

Componente de tip sesiune, cu stare

In aceasta sectiune ne imaginam un sistem de e-learning bazat pe un server


de aplicatii. O operatie elementara ntr-un astfel de sistem este afisarea unei
ntrebari, n cadrul unui examen on-line. Am ales sa implementez aceasta
operatie prin intermediul unei componente de tip sesiune, care defineste o
metoda afiseazaIntrebare(). Componenta de tip sesiune trebuie sa pastreze
starea clientului pe parcursul unei sesiuni cu serverul, de exemplu pentru a
nu afisa de doua ori aceeasi ntrebare. Mai jos este prezentata o implementare
schematica a acestei idei.

3.2. COMPONENTE DE TIP SESIUNE, CU STARE

Definitia interfetei
package examen;
import javax.ejb.Remote;
@Remote
public interface ExamenOnline{
public String afiseazaIntrebare();
}
ExamenOnline.java

Definitia clasei
package examen;
import javax.ejb.*;
@Stateful
public class ExamenOnlineBean implements ExamenOnline{
private int nrIntrebare=0;
public String afiseazaIntrebare(){
++nrIntrebare;
switch(nrIntrebare){
case 1: return "Cine a inventat ciocolata?";
case 2: return "In ce an s-a nascut Einstein?";
case 3: return "Cate planete sunt in sistemul nostru solar?";
default: return "Nu mai sunt intrebari"; }//switch}}
ExamenOnlineBean.java

Un exemplu de client al componentei ExamenOnline


package clienti;
import examen.ExamenOnline;

39

40

CAPITOLUL 3. COMPONENTE DE TIP SESIUNE

import javax.naming.InitialContext;
public class ExamenOnlineClient{
public static void main(String[] args) throws Exception
{
InitialContext ctx = new InitialContext();
ExamenOnline beanInstance = (ExamenOnline)
ctx.lookup("examen.ExamenOnline");
for(int i=0; i<5; i++)
System.out.println(beanInstance.afiseazaIntrebare());}}

ExamenOnlineClient.java

Exemplul de mai sus poate fi testat folosind urmatoarele comenzi:

C:\EJB>javac -classpath .;C:\glassfishv3\glassfish\lib\javaee.jar ->


-> -d . examen/*.java
C:\EJB>javac -classpath .;C:\glassfishv3\glassfish\lib\javaee.jar ->
-> -d . clienti/ExamenOnlineClient.java
C:\EJB>jar cf ExamenApp.jar examen\
C:\EJB>java -classpath C:\glassfishv3\glassfish\lib\appserv-rt.jar; ->
->C:\glassfishv3\glassfish\lib\javaee.jar;C:\EJB ->
-> clienti.ExamenOnlineClient
Cine a inventat ciocolata?
In ce an s-a nascut Einstein?
Cate planete sunt in sistemul nostru solar?
Nu mai sunt intrebari
Nu mai sunt intrebari

Inainte de a executa programul client, nu uitati sa ncarcati pe server


arhiva ExamenApp.jar!

3.3. COMPONENTE DE TIP SINGLETON

3.3

41

Componente de tip sesiune singulare


(singleton)

Adnotarea folosita pentru a desemna o componenta de tip sesiune singulara


este @Singleton, folosita naintea definitiei clasei care implementeaza componenta.
O componenta de tip sesiune singulara este instantiata o singura data
ntr-o aplicatie, fiind astfel utila n cazurile n care un obiect al aplicatiei
va fi folosit n mod partajat si concurent de catre toti clientii aplicatiei.
Un exemplu tipic este acela al unei componente de tip contor, prezentat n
continuare.
package single;
import javax.ejb.Remote;
@Remote
public interface Contor{
public int citesteContor();
}
Contor.java

package single;
import javax.ejb.Singleton;
@Singleton(name="Contor")
public class ContorBean implements Contor{
private int numara = 0;
public int citesteContor(){
return numara++;
}
}
ContorBean.java

42

CAPITOLUL 3. COMPONENTE DE TIP SESIUNE

package clienti;
import single.Contor;
import javax.naming.InitialContext;
public class SingleClient{
public static void main(String[] args) throws Exception{
InitialContext context = new InitialContext();
Contor contor = (Contor)context.lookup("single.Contor");
System.out.println(contor.citesteContor());
}}
SingleClient.java

Comenzile folosite pentru compilarea componentei, construirea arhivei,


compilarea si executia clientului sunt reproduse mai jos.
C:\EJB>set CLASSPATH=.;C:\glassfishv3\glassfish\lib\javaee.jar
C:\EJB>javac -d single/*.java
C:\EJB>jar cvf Single.jar single\
C:\EJB>javac -d . clienti/SingleClient.java
C:\EJB>java -classpath ->
->C:\glassfishv3\glassfish\lib\appserv-rt.jar;->
->C:\glassfishv3\glassfish\lib\javaee.jar;. ->
-> clienti.SingleClient
O componenta de tip singleton este initializata de catre containerul EJB
nainte ca acesta sa raspunda vreunei cereri adresate oricarei alte componente
a aplicatiei. De aceea componentele singulare pot fi folosite foarte bine pentru
a executa operatii la pornirea aplicatiei (startup tasks). In cazul n care mai
multe componente singleton sunt folosite pentru astfel de task-uri, ordinea
n care acestea sunt initializate de catre containerul EJB poate fi specificata
cu ajutorul adnotarii @DependsOn. Astfel, daca se specifica

AL COMPONENTELOR DE TIP SESIUNE 43


3.4. CICLUL DE VIAT
A
@Singleton
@DependsOn("A")
public class B {...}
containerul EJB va initializa A naintea lui B.
Folosirea adnotarii @Startup naintea definitiei unei componente de tip
singleton va determina initializarea acesteia la pornirea aplicatiei.

3.4

Ciclul de viat
a al componentelor de tip
sesiune

O component
a de tip sesiune f
ar
a stare este creat
a la initiativa
containerului EJB. Containerul mentine un rezervor (pool) de instante
ale componentelor de acest tip, astfel ncat atunci cand un client apeleaza
o metoda a unei componente de tip sesiune fara stare este aleasa o instanta
a componentei din rezervor si invocata metoda acesteia. Acest lucru este
posibil deoarece starea componentei nu trebuie mentinuta dupa ncheierea
executiei metodei. Distrugerea componentelor de tip sesiune fara stare este
deasemenea efectuata prin decizia containerului EJB, de exemplu pentru eliberarea unor resurse de memorie sau atunci cand o anumita componenta nu
este utilizata un timp mai ndelungat. Astfel, o componenta de tip sesiune
fara stare se poate gasi n timpul ciclului sau de viata doar ntr-una din doua
stari: inexistenta si n astepare(ready).
O metoda a unei componente de tip sesiune fara stare poate fi marcata
cu una dintre adnotarile @PostConstruct sau @PreDestroy, ceea ce va
face ca ele sa fie apelate imediat dupa instantierea componentei, respectiv
nainte de distrugerea ei.
Spre deosebire de cazul componentelor fara stare, ciclul de viat
a al
componentelor de tip sesiune cu stare este initiat de c
atre clienti
prin solicitarea unei referinte la o instant
a a unei componente. Pe
durata ciclului sau de viata, o componenta de tip sesiune cu stare poate fi
trecuta de catre container din starea ready, n care componenta se afla n
memoria principala, ntr-o stare pasiva(inactiva), n memoria secundara a
serverului. Re-activarea are loc atunci cand un client apeleaza o metoda a

44

CAPITOLUL 3. COMPONENTE DE TIP SESIUNE

unei instante pasive. Reamintiti-va ca o componenta de tip sesiune cu stare


este asociata unui client pentru toata durata conversatiei acestuia cu serverul,
care poate contine mai multe apeluri de metode, ntre care trebuie pastrata
starea componentei. Prin urmare o componenta de tip sesiune cu stare nu va
fi n general distrusa la initiativa containerului! (Se poate ca o componenta
de tip sesiune cu stare, pasiva, sa fie distrusa de container dupa o perioada
ndelungata de inactivitate a clientului, timeout.)
Adnotarile care pot marca una dintre metodele unei componente de tip
sesiune cu stare sunt: @PostConstruct, @PreDestroy, @PrePassivate
si @PostActivate, cu semnificatiile evidente date de numele lor.

Figura 3.1: Ciclul de viata al componentelor de tip sesiune cu stare

Capitolul 4
Entit
ati JPA
4.1

Clasa corespunz
atoare unei tabele

Java EE foloseste standardul JPA(Java Persistence API) pentru realizarea


corespondentei dintre obiecte Java si tabele ale unei baze de date relationale.
Intre aplicatie, care foloseste modelul bazat pe obiecte, si schema bazei de
date exista n Java EE un nivel numit de persistenta, care izoleaza programatorul de problemele specifice bazei de date (e.g. gestiunea tranzactiilor).
O tabela dintr-o baza de date relationala este reprezentata n program printro entitate JPA, o clasa Java marcata cu adnotarea @Entity. In plus, clasa
care reprezinta o entitate JPA trebuie sa respecte si urmatoarele cerinte[2]:
1. Sa defineasca un constructor fara argumente.
2. Sa implementeze interfata Serializable, pentru ca o instanta a sa sa
poata fi transmisa ca parametru prin valoare, de exemplu prin intermediul interfetei la distanta a unei componente de tip sesiune.
3. Sa nu fie declarata final si sa nu contina metode sau atribute persistente
declarate final.
O instanta a unei entitati JPA corespunde unei linii din tabela asociata.
Corespondenta dintre o entitate JPA si o tabela din baza de date se
realizeaza folosind adnotari n clasa Java care reprezinta entitatea JPA. Astfel, de exemplu, @Table specifica numele tabelei cu care entitatea este asociata, @Column desemneaza numele coloanei din tabela cu care este asociat
45

I JPA
CAPITOLUL 4. ENTITAT

46

campul marcat al entitatii JPA, @Id marcheaza un camp al entitatii care


corespunde unei chei primare in tabela asociata.
Mai jos se gaseste definitia clasei Student, entitatea JPA corespunzatoare
tabelei STUDENT, definita n capitolul precedent.
package doi;
import
import
import
import
import

javax.persistence.Entity;
javax.persistence.Table;
javax.persistence.Id;
javax.persistence.Column;
java.io.Serializable;

@Entity
@Table(name="STUDENT")
public class Student implements Serializable{
@Id
@Column(name="STUDENTID", nullable=false)
private int studentId;
@Column(name="NUME")
private String nume;
@Column(name="PRENUME")
private String prenume;
@Column(name="EMAIL")
private String email;
public Student(){
}
public long citesteStudentId(){
return studentId;
}

4.2. FAT
ADA COMPONENTEI DE TIP ENTITATE

47

public void scrieStudentId(int i){


studentId=i;
}
public String citesteNume(){
return nume;
}
public void scrieNume(String n){
nume=n;
}
public String citestePrenume(){
return prenume;
}
public void scriePrenume(String p){
prenume=p;
}
public String citesteEmail(){
return email;
}
public void scrieEmail(String e){
email=e;
}
}
Student.java

4.2

Fatada componentei de tip entitate

Gasirea, actualizarea, crearea si stergerea obiectelor asociate cu linii dintr-o


tabela relationala (gasirea, actualizarea, crearea si stergerea entitatilor JPA)
se face prin intermediul unor metode specificate de interfata EntityManager, care face parte din standardul JPA.
Pentru a obtine o instanta de tip EntityManager se foloseste adnotarea
@PersistenceContext pentru a injecta gestionarul de entitati JPA n componenta care opereaza cu entitati JPA. (Exista si gestionari de entitati creati
si distrusi de catre aplicatiile care i folosesc. Acestia sunt creati folosind metoda createEntityManager() a unei instante de tipul EntityManagerFactory,

I JPA
CAPITOLUL 4. ENTITAT

48

injectata la randul ei n aplicatie cu adnotarea @PersistenceUnit. Nu ne vom


ocupa nsa n aceasta carte de gestionari de entitati administrati la nivelul
aplicatiilor.)
Accesul la o componenta de tip entitate este implementat prin intermediul unei componente de tip sesiune. Definim n continuare interfata si
clasa corespunzatoare componentei CautaStudent, o componenta de tip sesiune, fara stare, care defineste metoda cauta(int id). Rezultatul metodei
cauta reprezinta numele studentului cu id-ul dat ca argument, obtinut prin
folosirea metodei find() a gestionarului de entitati em. La apelul metodei
find(), gestionarul de entitati extrage nregistrarea cautata din baza de date
si instantiaza cu valorile obtinute un obiect de tipul corespunzator (n exemplul nostru de tipul Student).

Definitia interfetei
package doi;
import javax.ejb.Remote;
import doi.Student;
@Remote
public interface CautaStudent{
public String cauta(int id);
}
CautaStudent.java

Definitia clasei
package doi;
import
import
import
import
import

javax.ejb.Stateless;
javax.annotation.Resource;
javax.persistence.PersistenceContext;
javax.persistence.PersistenceUnit;
javax.persistence.EntityManager;

II DE PERSISTENT

4.3. DEFINIREA UNITAT


A

49

import javax.persistence.EntityManagerFactory;
import doi.Student;
@Stateless(name="CautaStudent")
public class CautaStudentBean implements CautaStudent{
@PersistenceContext(unitName="StudentPersistUnit")
EntityManager em;
public String cauta(int id){
Student s = em.find(Student.class,id);
return s.citesteNume();
}
}
CautaStudentBean.java

Compilati entitatea JPA, interfata si clasa corespunzatoare componentei


de tip sesiune, folosind urmatoarele comenzi:
C:\EJB>set CLASSPATH=.;C:\glassfishv3\glassfish\lib\javaee.jar
C:\EJB>javac -d . doi/Student.java
C:\EJB>javac -d . doi/CautaStudent.java
C:\EJB>javac -d . doi/CautaStudentBean.java

4.3

Definirea unit
atii de persistent
a

O unitate de persistenta defineste multimea tuturor entitatilor JPA dintr-o


aplicatie administrate de instante de tipul EntityManager si specific
a numele global JNDI al sursei de date corespunz
atoare. Unitatile de
persistenta sunt definite n fisierul de configurare persistence.xml, care
trebuie sa se gaseasca n directorul META-INF al unei arhive EJB-JAR.
(Daca unitatea de persistenta este mpachetata ntr-o arhiva de tip WAR,
persistence.xml va fi localizat n directorul WEB-INF/classes/META-INF al

I JPA
CAPITOLUL 4. ENTITAT

50
arhivei WAR[1].)

Pentru exemplul considerat am creat n directorul C:\EJB\META-INF


fisierul persistence.xml redat mai jos, care specifica numele sursei de date folosite de catre containerul EJB (jdbc/student) si numele clasei de persistenta
gestionata de EntityManager (doi.Student).
<persistence>
<persistence-unit name="StudentPersistUnit">
<description>
Prima unitate de persistenta.
Administreaza date referitoare la studenti.
</description>
<jta-data-source>jdbc/student</jta-data-source>
<class>doi.Student</class>
</persistence-unit>
</persistence>
persistence.xml

4.4

Impachetarea si darea n folosint


a a aplicatiei

Construiti arhiva MyStudentApp.jar folosind urmatoarea comanda:


C:\EJB> jar cvf MyStudentApp.jar doi/CautaStudent.* ->
->doi/CautaStudentBean.* doi/Student.* META-INF/persistence.xml
Incarcati arhiva MyStudentApp.jar pe serverul de aplicatii, folosind consola grafica de administrare si specificand tipul arhivei ca fiind EJB Jar.

4.5

Un exemplu de client

package clienti;
import doi.CautaStudent;
import javax.naming.InitialContext;
import doi.Student;

4.5. UN EXEMPLU DE CLIENT

51

Figura 4.1: Structura arhivei EJB-JAR

public class EntityBeanStudentClient{


public static void main(String[] args) throws Exception
{
InitialContext ctx = new InitialContext();
CautaStudent beanInstance = (CautaStudent)
ctx.lookup(CautaStudent.class.getName());
String myName=beanInstance.cauta(777);
System.out.println("Hi, "
+ myName + "!");
}
}
EntityBeanStudentClient.java

Compilati si executati programul client folosind urmatoarele comenzi:


C:\EJB>javac -d . clienti/EntityBeanStudentClient.java
C:\EJB>java -classpath C:\glassfishv3\glassfish\lib\appserv-rt.jar;->

52

I JPA
CAPITOLUL 4. ENTITAT

->C:\glassfishv3\glassfish\lib\javaee.jar;. ->
->clienti.EntityBeanStudentClient
Apr 21, 2010 5:12:26 PM
com.sun.enterprise.transaction.JavaEETransactionManagerSimplified
initDelegates
INFO: Using
com.sun.enterprise.transaction.jts.JavaEETransactionManagerJTSDelegate
as the delegate
Hi, Bond!

4.6

Ciclul de viat
a al entit
atilor JPA

In timpul ciclului sau de viata o instanta a unei entitati JPA poate fi ntr-una
dintre urmatoarele patru stari: noua (new), asociata (managed), detasata
(detached) sau stearsa (removed).
Crearea instantelor entitatilor JPA si trecerea acestora dintr-o stare n
alta are loc ca urmare a unor apeluri de metode ale unei instante de tip
EntityManager. Gestiunea instantelor entit
atilor JPA se face prin
intermediul unui obiect de tip EntityManager.
Metoda EntityManager.find() executa o instructiune SELECT asupra bazei de date, folosind cheia primara a entitatii careia i este aplicata.
Rezultatul metodei este o entitate cu o identitate persistenta, asociata cu
un context de persistenta, aflata n starea managed. In aceeasi stare (managed) va trece o entitate noua, atunci cand asupra ei este invocata una
dintre metodele EntityManager.persist()sau EntityManager.merge().
La executia operatiilor EntityManager.persist() sau EntityManager.merge()
asupra bazei de date va fi executata o instructiune INSERT.
Executia metodei EntityManager.remove() marcheaza o entitate JPA
pentru stergere, trecand-o n starea removed, n care entitatea are nca
o identitate persistenta si este asociata cu un context de persistenta. La
executia unei metode EntityManager.flush(), entitatile marcate pentru
stergere (aflate n starea removed) vor fi sterse din baza de date prin executia
unei comenzi DELETE. Daca EntityManager.persist() este apelata asupra instantei unei entitati JPA aflata n starea removed, aceasta va trece n

AL ENTITAT
ILOR JPA
4.6. CICLUL DE VIAT
A

53

Figura 4.2: Starile unei entitati JPA pe durata ciclului sau de viata
starea managed.
O entitate detasat
a are o identitate persistenta, nsa nu este asociata
cu un context de persistenta, rezultand de exemplu n urma unei tranzactii
ncheiate cu commit sau rollback. La executia EntityManager.merge()
asupra unei entitati detasate aceasta trece n starea managed iar baza de
date va fi actualizata prin executia comenzii UPDATE.
Starile entitatilor persistente sunt sincronizate cu baza de date atunci
cand tranzactiile cu care acestea sunt asociate executa commit. Pentru a
forta sincronizarea cu baza de date se poate folosi metoda EntityMana-

I JPA
CAPITOLUL 4. ENTITAT

54
ger.flush().

4.7

Chei primare compuse

Fiecare entitate JPA trebuie sa aiba o cheie primara, pentru a putea fi identificata n mod unic. Atunci cand cheia primara este compusa din mai multe
atribute este necesar sa fie definita o clasa corespunzatoare acesteia. Clasa
corespunzatoare cheii primare a unei entitati JPA este specificata folosind
adnotarea @IdClass n fata numelui clasei corespunzatoare entitatii JPA.
Clasa corespunzatoare unei chei primare trebuie sa ndeplineasca urmatoarele
conditii([2]):
Sa fie definita public.
Sa implementeze interfata Serializable.
Sa aiba un constructor public fara parametri.
Sa implementeze metodele hashCode si equals.
Numele si tipurile campurilor din cheia primara trebuie sa fie aceleasi n
clasa corespunzatoare cheii primare si n clasa corespunzatoare entitatii
JPA. In clasa corespunzatoare entitatii JPA, campurile care fac parte
din cheia primara vor fi marcate cu adnotarea @Id.
Campurile din clasa corespunzatoare cheii primare vor fi definite public sau protected, daca este folosit accesul bazat pe valorile din aceste
campuri (property-based access).

Exemplu
ij> CREATE TABLE Grades(
> studentID INTEGER NOT NULL,
> cursID INTEGER NOT NULL,
> semestrul1 INTEGER,
> semestrul2 INTEGER,
> laborator INTEGER,
> CONSTRAINT pk_SidCid PRIMARY KEY(studentID,cursID));
0 rows inserted/updated/deleted

4.7. CHEI PRIMARE COMPUSE


...
ij> INSERT INTO Grades VALUES
> (1,1,9,10,10);
1 row inserted/updated/deleted
...
ij> SELECT * FROM Grades;
STUDENTID |CURSID
|SEMESTRUL1 |SEMESTRUL2 |LABORATOR
----------------------------------------------------------1
|1
|9
|10
|10
2
|1
|8
|7
|8
3
|1
|10
|10
|10
...
28 rows selected
package celeste;
import
import
import
import
import
import
import

javax.persistence.Entity;
javax.persistence.Table;
javax.persistence.Id;
javax.persistence.IdClass;
javax.persistence.Column;
javax.persistence.NamedQuery;
java.io.Serializable;

@Entity
@Table(name="GRADES")
@IdClass(GradesPK.class)
@NamedQuery(name="Grades.forOneStudent",
query="select o from Grades o where o.studentId=:param")
public class Grades implements Serializable{
@Id
@Column(name="STUDENTID", nullable=false)
private int studentId;
@Id
@Column(name="CURSID", nullable=false)

55

56

I JPA
CAPITOLUL 4. ENTITAT

private int cursId;


@Column(name="SEMESTRUL1")
private int semestrul1;
@Column(name="SEMESTRUL2")
private int semestrul2;
@Column(name="LABORATOR")
private int laborator;
public Grades(){
}
public long citesteStudentId(){
return studentId;
}
public void scrieStudentId(int i){
studentId=i;
}
public long citesteCursId(){
return cursId;
}
public void scrieCursId(int i){
cursId=i;
}
public int citesteSemestrul1(){
return semestrul1;
}
public void scrieSemestrul1(int n){
semestrul1=n;
}
public int citesteSemestrul2(){
return semestrul2;
}
public void scrieSemestrul2(int n){
semestrul2=n;
}

4.7. CHEI PRIMARE COMPUSE


public int citesteLaborator(){
return laborator;
}
public void scrieLaborator(int l){
laborator=l;
}
}
Grades.java

package celeste;
import java.io.Serializable;
public class GradesPK implements Serializable{
public int studentId;
public int cursId;
public GradesPK(){
//constructor public fara parametri
}
public int hashCode(){
return super.hashCode();
}
public boolean equals(Object other){
if(!(other instanceof GradesPK)){
return false;}
GradesPK celalalt = (GradesPK)other;
return(celalalt.studentId==studentId
&&
celalalt.cursId==cursId);
}
}
GradesPK.java

57

I JPA
CAPITOLUL 4. ENTITAT

58

...
public List<Grades> getGradesforOneStudent(int idStud){
List<Grades> note =
(List<Grades>)em.createNamedQuery("Grades.forOneStudent").
setParameter("param",idStud).getResultList();
return note;
}
...
FatadaCursuriBean.java

//Notele studentului cu studentId=2


List<Grades> grades = beanInstance.getGradesforOneStudent(2);
ListIterator listIterator2 = grades.listIterator();
System.out.println("Notele studentului cu studentId=2");
while(listIterator2.hasNext()){
Grades linie = (Grades)listIterator2.next();
System.out.print("ID Curs:"+linie.citesteCursId());
System.out.print(" Nota 1:"+linie.citesteSemestrul1());
System.out.print(" Nota 2:"+linie.citesteSemestrul2());
System.out.println(" Nota lab.:"+linie.citesteLaborator());
}
CelesteClient1.java

4.8

Specificarea relatiilor dintre entit


atile JPA

Exista patru tipuri de relatii ntre entitatile JPA, si anume:


Relatia unul cu unul (One-to-One)
Relatia unul cu mai multi(One-to-Many)
Relatia mai multi cu unul(Many-to-One)

ILE JPA
4.8. SPECIFICAREA RELAT
IILOR DINTRE ENTITAT

59

Relatia mai multi cu mai multi (Many-to-Many)


O relatie poate fi unidirectional
a sau bidirectional
a. Intr-o relatie
unidirectionala, una si numai una dintre entitati contine un camp care se
refera la cealalta entitate. Intr-o relatie bidirectionala, fiecare dintre entitati contine un camp care se refera la cealalta. Directia relatiei dintre doua
entitati determina posibilitatea unei interogari (query) de a naviga de la o
entitate la cealalta. Implementarea relatiilor n contextul de persistenta, care
determina modul n care se fac actualizarile n baza de date, se realizeaza
prin adnotarea campurilor care se refera la entitatile relationate, n functie de
tipul relatiei, cu @OneToOne, @ManyToOne, @ManyToMany, @JoinColumn, @JoinTable, etc.
Pentru a exemplifica aceste relatii vom folosi baza de date descrisa n
Anexa B.

Relatia mai multi cu mai multi (Many-to-Many)


Relatia dintre tabela Studenti si tabela Cursuri este una de tipul mai multi
cu mai multi.
ij> connect jdbc:derby:celeste;user=dba;password=paroladba;
ij> CREATE TABLE STUD_CURS(
> studentID INTEGER,
> cursID INTEGER);
0 rows inserted/updated/deleted
ij> INSERT INTO STUD_CURS VALUES (1,1);
1 row inserted/updated/deleted
...
ij> select * from stud_curs;
STUDENTID |CURSID
----------------------1
|1
1
|2
1
|3
2
|3
2
|4
3
|1
3
|2

I JPA
CAPITOLUL 4. ENTITAT

60
3
4
4
5
5
5
5
6
7
7
7

|3
|3
|1
|1
|2
|3
|4
|4
|1
|3
|4

18 rows selected

...
@Entity
@Table(name="CURSURI")
...
public class Cursuri implements Serializable{
...
@ManyToMany
@JoinTable(name="STUD_CURS",
joinColumns=
@JoinColumn(name="CURSID",referencedColumnName="CURSID"),
inverseJoinColumns=
@JoinColumn(name="STUDENTID",referencedColumnName="STUDENTID"))
//name=numele coloanei din tabela STUD_CURS (tabela de join)
//referencedColumnName=numele coloanelor din tabelele
//CURSURI, respectiv STUDENTI
private Set<Studenti> studenti;
...
}

ILE JPA61
4.9. IMPLEMENTAREA RELAT
IILOR DE MOSTENIRE DINTRE ENTITAT

4.9

Implementarea relatiilor de mostenire dintre entit


atile JPA

Implementarea n baza de date a relatiilor de mostenire dintre entitatile JPA


se poate face n trei moduri[2]:
Cu o singura tabela pentru ierarhia de clase.
Cu cate o tabela pentru fiecare tip de entitate.
Printr-o strategie de join, campurile specifice subclasei fiind stocate
ntr-o tabela diferita de cea n care sunt stocate proprietatile comune
ntre subclasa si clasa de baza.

4.10

Limbajul JPQL

In contextul entitatilor JPA interogarea bazei de date se face n limbajul


JPQL (Java Persistence Query Language), un limbaj declarativ similar cu
SQL dar care opereaza cu obiecte Java n locul tabelelor relationale. Cu
JPQL se pot defini atat interogari statice (named queries), cat si interogari
dinamice. Interogarile statice sunt definite ntr-o entitate JPA cu adnotarea @NamedQuery. Interogarile dinamice sunt definite direct n logica
aplicatiei. Interfata EntityManager contine metodele createQuery si createNamedQuery care sunt folosite pentru a crea interogarile statice, si,
respectiv, dinamice.

62

I JPA
CAPITOLUL 4. ENTITAT

Capitolul 5
Componente bazate pe mesaje
O componenta bazata pe mesaje (message-driven bean, MDB) este o componenta fara stare care consuma mesaje dintr-o coada JMS (Java Message
Service). Standardul JMS este parte integranta din Java EE si implementeaza suportul pentru comunicatii asincrone pe aceasta platforma. Mai concret, este vorba despre dirijarea mesajelor catre destinatii denumite cozi si
distribuirea acestor mesaje catre consumatori.
O componenta MDB defineste o metoda, onMessage(), care este apelata
de catre containerul EJB ori de cate ori este primit un mesaj n coada la
care este asociata componenta(Fig.5.1). O component
a de tip MDB nu
poate fi apelat
a direct de c
atre clienti.

5.1

Crearea resurselor

Resursele necesare transmiterii mesajelor folosind JMS sunt:


un obiect de tip ConnectionFactory, care contine parametrii pentru
configurarea conexiunii. Acest obiect este folosit de clienti la crearea
conexiunilor cu providerul de JMS.
un obiect de tip Queue, coada propriu-zisa de mesaje.
o destinatie fizica.
Cele trei resurse pot fi create folosind consola grafica de administrare a serverului de aplicatii(Fig.5.2 si fig.5.3).
63

64

CAPITOLUL 5. COMPONENTE BAZATE PE MESAJE

Figura 5.1: Functionarea unei componente bazata pe mesaje

5.2

Prima component
a bazat
a pe mesaje

Ca exercitiu, am creat fisierul PrimaCBM.java, cu urmatorul continut:


import
import
import
import
import

javax.ejb.MessageDriven;
javax.jms.MessageListener;
javax.jms.Message;
javax.jms.TextMessage;
java.util.logging.Logger;

@MessageDriven(name="PrimaCBM",mappedName="jms/Queue")
public class PrimaCBM implements MessageListener {
static final Logger registru = Logger.getLogger("PrimaCBM");
public PrimaCBM(){}

BAZATA
PE MESAJE
5.2. PRIMA COMPONENTA

65

Figura 5.2: Crearea atelierului de conexiuni JMS


public void onMessage(Message mesaj) {
try {
String text = mesaj.getStringProperty("text");
registru.info("CBM a primit mesajul:"+text);
}
catch (Exception e) {
e.printStackTrace();
}
}
}
PrimaCBM.java

La primirea unui mesaj containerul apeleaza metoda onMessage(). Vom


nregistra primirea mesajului ntr-unul dintre fisierele de jurnalizare ale serverului de aplicatii. In acest scop folosim un obiect de tipul Logger, definit
n pachetul java.util.logging. Continutul fisierului de jurnalizare va putea fi

66

CAPITOLUL 5. COMPONENTE BAZATE PE MESAJE

Figura 5.3: Crearea destinatiei JMS


vizualizat prin intermediul consolei grafice de administrare a serverului.
Compilati componenta si construiti arhiva CBM.jar, folosind urmatoarele
comenzi:
C:\EJB>javac -classpath ->
->.;C:\glassfishv3\glassfish\lib\javaee.jar PrimaCBM.java
C:\EJB>jar cvf CBM.jar PrimaCBM.class
Incarcati arhiva CBM.jar pe serverul de aplicatii, folosind consola grafica
de administrare si specificand tipul arhivei ca fiind EJB Jar.

5.3

Trimiterea mesajelor

Pentru a trimite mesaje catre componenta definita am creat programul CBMClient.java,


a carui sursa este redata mai jos.

5.3. TRIMITEREA MESAJELOR


import
import
import
import
import
import
import

67

javax.jms.ConnectionFactory;
javax.jms.Queue;
javax.jms.Connection;
javax.jms.Session;
javax.jms.MessageProducer;
javax.jms.TextMessage;
javax.jms.Message;

import javax.naming.InitialContext;

public class CBMClient {


public static void main(String[] args) {
System.out.println("Hi!");
try {
InitialContext ctx = new InitialContext();
System.out.println("S-a creat InitialContext");
ConnectionFactory connectionFactory =
(ConnectionFactory) ctx.lookup("firstJMS_pool");
System.out.println("S-a creat ConnectionFactory");
Queue coadaMesaje = (Queue) ctx.lookup("jms/Queue");
System.out.println("S-a creat Queue");
Connection conexiune = null;
Session sesiune = null;
MessageProducer expeditor = null;
Message mesaj = null;
conexiune = connectionFactory.createConnection();
System.out.println("S-a creat conexiunea");
sesiune = conexiune.createSession(false, Session.AUTO_ACKNOWLEDGE);
expeditor = sesiune.createProducer(coadaMesaje);
mesaj = sesiune.createMessage();

68

CAPITOLUL 5. COMPONENTE BAZATE PE MESAJE

mesaj.setStringProperty("text","Testez CBM");
expeditor.send(mesaj);
System.out.println("Am trimis mesajul:"+mesaj.getStringProperty("text"));
expeditor.close();
sesiune.close();
conexiune.close();
}
catch(Exception e){System.out.println("Exceptie: " + e.toString());}
} // main
} // class

CBMClient.java

Compilati si executati programul client folosind urmatoarele comenzi:


C:\EJB\clienti>javac -classpath ->
-> .;C:\glassfishv3\glassfish\lib\javaee.jar CBMClient.java
C:\EJB\clienti>java -classpath ->
-> .;C:\glassfishv3\glassfish\lib\appserv-rt.jar; ->
-> C:\glassfishv3\glassfish\lib\->
->install\applications\jmsra\imqjmsra.jar; ->
-> C:\glassfishv3\glassfish\lib\appserv-admin.jar;
-> C:\glassfishv3\glassfish\lib\appserv-ws.jar; ->
-> C:\glassfishv3\glassfish\lib\javaee.jar CBMClient
Mai jos sunt redate mesajele serverului la executia programului client.
C:\EJB\clienti>java -classpath .;C:\glassfishv3\glassfish\lib\->
->appserv-rt.jar;C:\glassfishv3\glassfish\lib\javaee.jar;->
->C:\glassfishv3\glassfish\lib\install\applications\jmsra\imqjmsra.jar;->
->C:\glassfishv3\glassfish\lib\appserv-admin.jar;->
C:\glassfishv3\glassfish\lib\appserv-ws.jar CBMClient
Hi!

5.3. TRIMITEREA MESAJELOR

69

S-a creat InitialContext


May 4, 2010 1:02:57 PM com.sun.enterprise.transaction.->
->JavaEETransactionManagerSimplified initDelegates
INFO: Using com.sun.enterprise.transaction.jts.->
->JavaEETransactionManagerJTSDelegate as the delegate
May 4, 2010 1:03:02 PM com.sun.enterprise.connectors.jms.util.JmsRaUtil ->
->getInstalledMqVersion
WARNING: jmsra.upgrade_check_failed
May 4, 2010 1:03:02 PM org.hibernate.validator.util.Version <clinit>
INFO: Hibernate Validator bean-validator-3.0-JBoss-4.0.2
May 4, 2010 1:03:02 PM org.hibernate.validator.engine.resolver.->
->DefaultTraversableResolver detectJPA
INFO: Instantiated an instance of ->
org.hibernate.validator.engine.resolver.JPATraversableResolver.
May 4, 2010 1:03:02 PM com.sun.messaging.jms.ra.ResourceAdapter start
INFO: MQJMSRA_RA1101: SJSMQ JMS Resource Adapter starting: REMOTE
May 4, 2010 1:03:03 PM com.sun.messaging.jms.ra.ResourceAdapter start
INFO: MQJMSRA_RA1101: SJSMQ JMSRA Started:REMOTE
May 4, 2010 1:03:03 PM com.sun.messaging.jms.ra.ManagedConnectionFactory ->
->setAddressList
INFO: MQJMSRA_MF1101: setAddressList:NOT setting default value=localhost
May 4, 2010 1:03:03 PM com.sun.messaging.jms.ra.ManagedConnectionFactory ->
->setPassword
INFO: MQJMSRA_MF1101: setPassword:NOT setting default value
May 4, 2010 1:03:03 PM com.sun.messaging.jms.ra.ManagedConnectionFactory ->
->setUserName
INFO: MQJMSRA_MF1101: setUserName:NOT setting default value=guest
S-a creat ConnectionFactory
S-a creat Queue
S-a creat conexiunea
Am trimis mesajul:Testez CBM
Mesajul primit nregistrat n fisierul de jurnalizare poate fi vazut prin
intermediul consolei grafice de administrare a serverului, asa cum este ilustrat
n imaginile de mai jos.

70

CAPITOLUL 5. COMPONENTE BAZATE PE MESAJE

Figura 5.4: Fisierele de jurnalizare ale serverului GlassFish V3

Figura 5.5: Mesajul primit nregistrat n fisierul de jurnalizare

Anexe

71

Anexa A
Definirea unei surse de date n
GlassFish
Crearea si distrugerea conexiunilor la o baza de date poate fi costisitoare,
ceea ce justifica mentinerea unui rezervor de conexiuni (connection pool),
o multime de conexiuni reutilizabile, pentru o anumita baza de date, pregatite
n prealabil si administrate de catre serverul de aplicatii. Definitia unei surse
de date n GlassFish trebuie sa fie precedata de definitia rezervorului de conexiuni folosit de aceasta. Am definit rezervorul de conexiuni si sursa de date
folosind consola grafica pentru administrare a serverului, asa cum se vede n
figurile A.1 si A.2.
Pentru ca definitia unui rezervor de conexiuni pe o baza de date Java
DB sa fie completa trebuie definite si urmatoarele proprietati: DatabaseName, User, Password, PortNumber, ServerName. Mai jos este specificat ca
exemplu un set de valori pentru aceste proprietati.
DatabaseName = C:\Sun\SDK\javaDB\bin\student
User = profesor
Password = parolaprofesor
PortNumber = 1527
ServerName = localhost

73

74

ANEXA A. DEFINIREA UNEI SURSE DE DATE IN GLASSFISH

Figura A.1: Definirea unui rezervor de conexiuni

75

Figura A.2: Definirea unei surse de date

76

ANEXA A. DEFINIREA UNEI SURSE DE DATE IN GLASSFISH

Anexa B
Fragment dintr-un sistem de
e-learning
Crearea bazei de date
Folosim o baza de date cu patru tabele, Studenti, Profesori, Cursuri si
Note, ntre care exista relatiile prezentate n Tabela B.1.
C:\Sun\SDK\javadb\bin>ij
ij version 10.4
ij> connect jdbc:derby:celeste;
create=true;user=dba;password=paroladba
> as conex1;
ij> CREATE TABLE Studenti(
> studentID INTEGER PRIMARY KEY,
> nume VARCHAR(30),
> prenume VARCHAR(30),
> email VARCHAR(40));
0 rows inserted/updated/deleted
Studenti
Profesori
Studenti

Cursuri
Cursuri
Note

M:M
1:M
1:1

Relatia mai multi cu mai multi


Relatia unu cu mai multi
Relatia unu cu unu

Tabela B.1: Relatii ntre tabelele bazei de date


77

78

ANEXA B. STUDIU DE CAZ

ij> SELECT * FROM Studenti;


STUDENTID |NUME
|PRENUME
|EMAIL
-----------------------------------------------------------------------0 rows selected
ij> CREATE TABLE Cursuri(
> cursID INTEGER PRIMARY KEY,
> nume VARCHAR(100),
> profesorID INTEGER);
0 rows inserted/updated/deleted
ij> SELECT * FROM Cursuri;
CURSID
|NUME
|PROFESORID
-----------------------------------------------------------------------0 rows selected
ij> CREATE TABLE Profesori(
> profesorID INTEGER PRIMARY KEY,
> nume VARCHAR(30),
> prenume VARCHAR(30));
0 rows inserted/updated/deleted
ij> SELECT * FROM Profesori;
PROFESORID |NUME
|PRENUME
-----------------------------------------------------------------------0 rows selected
ij> CREATE TABLE Note(
> studentID INTEGER PRIMARY KEY,
> semestrul1 INTEGER,
> semestrul2 INTEGER,
> laborator INTEGER);
0 rows inserted/updated/deleted
ij> SELECT * FROM Note;
STUDENTID |SEMESTRUL1 |SEMESTRUL2 |LABORATOR
-----------------------------------------------

79
0 rows selected
ij>
ij> INSERT INTO Studenti VALUES
> (1,Ion,Ionescu,iion@celeste.ro);
1 row inserted/updated/deleted
ij> INSERT INTO Studenti VALUES
> (2,Petre,Petrescu,ppet@celeste.ro);
1 row inserted/updated/deleted
ij> INSERT INTO Studenti VALUES
> (3,Cristina,Cristescu,cris@celeste.ro);
1 row inserted/updated/deleted
ij> INSERT INTO Studenti VALUES
> (4,Ioana,Ionescu,ioio@celeste.ro);
1 row inserted/updated/deleted
ij> INSERT INTO Studenti VALUES
> (5,Vasile,Vasilescu,vasi@celeste.ro);
1 row inserted/updated/deleted
ij> INSERT INTO Studenti VALUES
> (6,Gelu,Popescu,gepo@celeste.ro);
1 row inserted/updated/deleted
ij> INSERT INTO Studenti VALUES
> (7,Andrei,Andreescu,andre@celeste.ro);
1 row inserted/updated/deleted
ij> SELECT * FROM Studenti;
STUDENTID |NUME
|PRENUME
|EMAIL
---------------------------------------------------------------------1
|Ion
|Ionescu
|iion@celeste.ro
2
|Petre
|Petrescu
|ppet@celeste.ro
3
|Cristina
|Cristescu
|cris@celeste.ro
4
|Ioana
|Ionescu
|ioio@celeste.ro
5
|Vasile
|Vasilescu
|vasi@celeste.ro
6
|Gelu
|Popescu
|gepo@celeste.ro
7
|Andrei
|Andreescu
|andre@celeste.ro
7 rows selected
ij> INSERT INTO Note VALUES

80

ANEXA B. STUDIU DE CAZ

> (1,9,10,10);
1 row inserted/updated/deleted
ij> INSERT INTO Note VALUES
> (2,8,7,8);
1 row inserted/updated/deleted
ij> INSERT INTO Note VALUES
> (3,10,10,10);
1 row inserted/updated/deleted
ij> INSERT INTO Note VALUES
> (4,7,6,7);
1 row inserted/updated/deleted
ij> INSERT INTO Note VALUES
> (5,5,5,5);
1 row inserted/updated/deleted
ij> INSERT INTO Note VALUES
> (6,10,9,10);
1 row inserted/updated/deleted
ij> INSERT INTO Note VALUES
> (7,7,5,9);
1 row inserted/updated/deleted
ij> SELECT * FROM Note;
STUDENTID |SEMESTRUL1 |SEMESTRUL2 |LABORATOR
----------------------------------------------1
|9
|10
|10
2
|8
|7
|8
3
|10
|10
|10
4
|7
|6
|7
5
|5
|5
|5
6
|10
|9
|10
7
|7
|5
|9
7 rows selected
ij> INSERT INTO Profesori VALUES
> (1,Ionescu,Cristina);
1 row inserted/updated/deleted
ij> INSERT INTO Profesori VALUES
> (2,Teodorescu,Mihai);

81
1 row inserted/updated/deleted
ij> INSERT INTO Profesori VALUES
> (3,Popescu,Paul);
1 row inserted/updated/deleted
ij> SELECT * FROM Profesori;
PROFESORID |NUME
|PRENUME
------------------------------------------------------------------------1
|Ionescu
|Cristina
2
|Teodorescu
|Mihai
3
|Popescu
|Paul
3 rows selected
ij> INSERT INTO Cursuri VALUES
> (1,Proiectarea bazelor de date,3);
1 row inserted/updated/deleted
ij> INSERT INTO Cursuri VALUES
> (2,Programare orientata pe obiecte,1);
1 row inserted/updated/deleted
ij> INSERT INTO Cursuri VALUES
> (3,Dezvoltarea aplicatiilor Web,1);
1 row inserted/updated/deleted
ij> INSERT INTO Cursuri VALUES
> (4,Retele de calculatoare,2);
1 row inserted/updated/deleted
ij> INSERT INTO Cursuri VALUES
> (5,Sisteme de gestiune a bazelor de date,3);
1 row inserted/updated/deleted
ij> SELECT * FROM Cursuri;
CURSID
|NUME
|PROFESORID
-------------------------------------------------------------------------1
|Proiectarea bazelor de date
|3
2
|Programare orientata pe obiecte
|1
3
|Dezvoltarea aplicatiilor Web
|1
4
|Retele de calculatoare
|2
5
|Sisteme de gestiune a bazelor de date
|3

82

ANEXA B. STUDIU DE CAZ

5 rows selected

Definirea entit
atilor JPA
Studenti
package celeste;
import
import
import
import
import
import
import
import

javax.persistence.Entity;
javax.persistence.Table;
javax.persistence.Id;
javax.persistence.Column;
javax.persistence.OneToOne;
javax.persistence.JoinColumn;
javax.persistence.NamedQuery;
java.io.Serializable;

@Entity
@Table(name="STUDENTI")
@NamedQuery(name="Studenti.note",
query="select o.note from Studenti o " +
"where o.studentId = :param")
public class Studenti implements Serializable{
@Id
@Column(name="STUDENTID", nullable=false)
private int studentId;
@Column(name="NUME")
private String nume;
@Column(name="PRENUME")
private String prenume;
@Column(name="EMAIL")

83
private String email;
@OneToOne
@JoinColumn(name="STUDENTID",referencedColumnName="STUDENTID")
private Note note;
public Studenti(){
}
public long citesteStudentId(){
return studentId;
}
public void scrieStudentId(int i){
studentId=i;
}
public String citesteNume(){
return nume;
}
public void scrieNume(String n){
nume=n;
}
public String citestePrenume(){
return prenume;
}
public void scriePrenume(String p){
prenume=p;
}
public String citesteEmail(){
return email;
}
public void scrieEmail(String e){
email=e;
}
}

Studenti.java

84

ANEXA B. STUDIU DE CAZ

Cursuri
package celeste;
import
import
import
import
import
import
import
import
import
import
import
import

javax.persistence.Entity;
javax.persistence.Table;
javax.persistence.Id;
javax.persistence.Column;
javax.persistence.NamedQuery;
javax.persistence.NamedQueries;
javax.persistence.ManyToOne;
javax.persistence.ManyToMany;
javax.persistence.JoinColumn;
javax.persistence.JoinTable;
java.io.Serializable;
java.util.List;

@Entity
@Table(name="CURSURI")
/*@NamedQuery(name="Cursuri.numeTitular",
query="select o.profesor from Cursuri o " +
"where o.cursId = :param")
*/
/*
@NamedQuery(name="Cursuri.studentiInscrisi",
query="select o.studenti from Cursuri o " +
"where o.cursId = :param")
*/
@NamedQueries({
@NamedQuery(name="Cursuri.numeTitular",
query="select o.profesor from Cursuri o " +
"where o.cursId = :param"),
@NamedQuery(name="Cursuri.studentiInscrisi",
query="select o.studenti from Cursuri o " +
"where o.cursId = :param")
})

85
public class Cursuri implements Serializable{
@Id
@Column(name="CURSID", nullable=false)
private int cursId;
@Column(name="NUME")
private String nume;
//@Column(name="PROFESORID")
//private String profesorId;
@ManyToOne
@JoinColumn(name="PROFESORID",referencedColumnName="PROFESORID")
private Profesori profesor;
@ManyToMany
@JoinTable(name="STUD_CURS",
joinColumns=
@JoinColumn(name="CURSID",referencedColumnName="CURSID"),
inverseJoinColumns=
@JoinColumn(name="STUDENTID",referencedColumnName="STUDENTID"))
//name=numele coloanei din tabela
//STUD_CURS (tabela de join)
//referencedColumnName=numele coloanelor din tabelele
//CURSURI, respectiv STUDENTI
private List<Studenti> studenti;

public Cursuri(){
}
public long citesteCursId(){
return cursId;
}
public void scrieCursId(int i){
cursId=i;
}

86

ANEXA B. STUDIU DE CAZ

public String citesteNume(){


return nume;
}
public void scrieNume(String n){
nume=n;
}
/*
public String citesteProfesorId(){
return profesorId;
}
public void scrieProfesorId(String p){
profesorId=p;
}
*/
}
Cursuri.java

Profesori
package celeste;
import
import
import
import
import

javax.persistence.Entity;
javax.persistence.Table;
javax.persistence.Id;
javax.persistence.Column;
java.io.Serializable;

@Entity
@Table(name="PROFESORI")
public class Profesori implements Serializable{
@Id
@Column(name="PROFESORID", nullable=false)
private int profesorId;
@Column(name="NUME")

87
private String nume;
@Column(name="PRENUME")
private String prenume;
public Profesori(){
}
public long citesteProfesorId(){
return profesorId;
}
public void scrieProfesorId(int i){
profesorId=i;
}
public String citesteNume(){
return nume;
}
public void scrieNume(String n){
nume=n;
}
public String citestePrenume(){
return prenume;
}
public void scriePrenume(String p){
prenume=p;
}
}
Profesori.java

Note
package celeste;
import javax.persistence.Entity;
import javax.persistence.Table;
import javax.persistence.Id;

88

ANEXA B. STUDIU DE CAZ

import javax.persistence.Column;
import java.io.Serializable;
@Entity
@Table(name="NOTE")
public class Note implements Serializable{
@Id
@Column(name="STUDENTID", nullable=false)
private int studentId;
@Column(name="SEMESTRUL1")
private int semestrul1;
@Column(name="SEMESTRUL2")
private int semestrul2;
@Column(name="LABORATOR")
private int laborator;
public Note(){
}
public long citesteStudentId(){
return studentId;
}
public void scrieStudentId(int i){
studentId=i;
}
public int citesteSemestrul1(){
return semestrul1;
}
public void scrieSemestrul1(int n){
semestrul1=n;
}
public int citesteSemestrul2(){
return semestrul2;

89
}
public void scrieSemestrul2(int n){
semestrul2=n;
}
public int citesteLaborator(){
return laborator;
}
public void scrieLaborator(int l){
laborator=l;
}
}
Note.java

Componenta de tip sesiune


a. Interfata
package celeste;
import javax.ejb.Remote;
import java.util.List;
@Remote
public interface FatadaCursuri{
public String cautaTitular(int id);
public List<Studenti> cautaStudenti(int idCurs);
public Note cautaNote(int idStud);
public List<Grades> getGradesforOneStudent(int idStud);
}
FatadaCursuri.java

b. Clasa care implementeaz


a interfata

90

ANEXA B. STUDIU DE CAZ

package celeste;
import
import
import
import

javax.ejb.Stateless;
javax.annotation.Resource;
javax.persistence.PersistenceContext;
javax.persistence.EntityManager;

import java.util.List;
@Stateless(name="FatadaCursuri")
public class FatadaCursuriBean implements FatadaCursuri{
@PersistenceContext(unitName="CelestePersistUnit")
EntityManager em;
public String cautaTitular(int id){
Profesori titular = (Profesori)em.createNamedQuery("Cursuri.numeTitular").
setParameter("param",id).getSingleResult();
return titular.citesteNume();
}
public List<Studenti> cautaStudenti(int idCurs){
List<Studenti> listaStudenti = (List<Studenti>)em.createNamedQuery
("Cursuri.studentiInscrisi").setParameter("param",idCurs).getResultList();
return listaStudenti;
}
public Note cautaNote(int idStud){
Note note = (Note)em.createNamedQuery("Studenti.note").
setParameter("param",idStud).getSingleResult();

91
return note;
}
public List<Grades> getGradesforOneStudent(int idStud){
List<Grades> note = (List<Grades>)em.createNamedQuery("Grades.forOneStudent").
setParameter("param",idStud).getResultList();
return note;
}
}
FatadaCursuriBean.java

Compilarea entit
atilor si componentelor fatadei
C:\EJB>set CLASSPATH=.;C:\glassfishv3\glassfish\lib\javaee.jar
C:\EJB>javac -d . celeste/*.java

Definirea unit
atii de persistent
a
<persistence>
<persistence-unit name="CelestePersistUnit">
<description>
Cristinas ELEarning SysTEm.
</description>
<jta-data-source>jdbc/celeste</jta-data-source>
<class>celeste.Studenti</class>
<class>celeste.Cursuri</class>
<class>celeste.Profesori</class>
<class>celeste.Note</class>
<class>celeste.Grades</class>
</persistence-unit>
</persistence>
persistence.xml

92

ANEXA B. STUDIU DE CAZ

Construirea arhivei
C:\EJB>jar cvf CelesteApp.jar celeste/FatadaCursuri.* ->
->celeste/FatadaCursuriBean.* celeste/Studenti.* celeste/Cursuri.* c
eleste/Profesori.* celeste/Note.* META-INF/persistence.xml
added manifest
adding: celeste/FatadaCursuri.class(in = 223) (out= 184)(deflated 17%)
adding: celeste/FatadaCursuri.java(in = 186) (out= 126)(deflated 32%)
adding: celeste/FatadaCursuriBean.class(in = 1062) (out= 584)(deflated 45%)
adding: celeste/FatadaCursuriBean.java(in = 600) (out= 302)(deflated 49%)
adding: celeste/Studenti.class(in = 1219) (out= 596)(deflated 51%)
adding: celeste/Studenti.java(in = 920) (out= 335)(deflated 63%)
adding: celeste/Cursuri.class(in = 1352) (out= 704)(deflated 47%)
adding: celeste/Cursuri.java(in = 1121) (out= 439)(deflated 60%)
adding: celeste/Profesori.class(in = 1056) (out= 549)(deflated 48%)
adding: celeste/Profesori.java(in = 784) (out= 303)(deflated 61%)
adding: celeste/Note.class(in = 1195) (out= 591)(deflated 50%)
adding: celeste/Note.java(in = 957) (out= 343)(deflated 64%)
adding: META-INF/persistence.xml(in = 353) (out= 173)(deflated 50%)

Definirea rezervorului de conexiuni si a sursei


de date
Figurile B.1 si B.2 ilustreaza cei doi pasi din definirea rezervorului de conexiuni prin intermediul interfetei grafice de administrare. Valorile proprietatilor
folosite de driverul JavaDB sunt stabilite n pasul al 2-lea (Fig. B.2) dupa
cum urmeaza.
DatabaseName = C:\Sun\SDK\javaDB\bin\celeste
User = dba
Password = paroladba
PortNumber = 1527
ServerName = localhost

93

Exemple de clienti
package clienti;
import
import
import
import
import
import
import

celeste.FatadaCursuri;
javax.naming.InitialContext;
celeste.Cursuri;
celeste.Profesori;
celeste.Studenti;
celeste.Note;
celeste.Grades;

import java.util.List;
import java.util.ListIterator;
public class CelesteClient1{
public static void main(String[] args) throws Exception
{
InitialContext ctx = new InitialContext();
FatadaCursuri beanInstance = (FatadaCursuri)
ctx.lookup(FatadaCursuri.class.getName());
String myName=beanInstance.cautaTitular(1);
System.out.println("Hi, "
+ myName + "!");
List<Studenti> studenti = beanInstance.cautaStudenti(1);

94

ANEXA B. STUDIU DE CAZ

ListIterator listIterator = studenti.listIterator();


while(listIterator.hasNext())
System.out.println(((Studenti)listIterator.next()).citesteNume());

Note note=beanInstance.cautaNote(1);
System.out.println("Notele: Sem.1: "+note.citesteSemestrul1()+
" Sem.2: "+note.citesteSemestrul2()+
" Lab.: "+note.citesteLaborator());
//Notele studentului cu studentId=2
List<Grades> grades = beanInstance.getGradesforOneStudent(2);
ListIterator listIterator2 = grades.listIterator();
System.out.println("Notele studentului cu studentId=2");
while(listIterator2.hasNext()){
Grades linie = (Grades)listIterator2.next();
System.out.print("ID Curs:"+linie.citesteCursId());
System.out.print(" Nota 1:"+linie.citesteSemestrul1());
System.out.print(" Nota 2:"+linie.citesteSemestrul2());
System.out.println(" Nota lab.:"+linie.citesteLaborator());
}
}
}
CelesteClient1.java

Comenzile pentru compilarea si executia programului client sunt urmatoarele:


C:\EJB>javac -d . clienti/CelesteClient1.java

95
C:\EJB>java -classpath ->
->C:\glassfishv3\glassfish\lib\appserv-rt.jar;->
C:\glassfishv3\glassfish\lib\javaee.jar;. clienti.CelesteClient1

96

ANEXA B. STUDIU DE CAZ

Figura B.1: Definirea rezervorului de conexiuni:Pasul 1

97

Figura B.2: Definirea rezervorului de conexiuni:Pasul 2

98

ANEXA B. STUDIU DE CAZ

Figura B.3: Definirea sursei de date

Bibliografie
[1] ***: The Java EE 5 Tutorial, http:// java.sun.com/ javaee/ 5/ docs/
tutorial/ doc/ index.html.
[2] ***: The Java EE 6 Tutorial, Volume I, http:// java.sun.com/ javaee/
6/ docs/ tutorial/ doc/ index.html.
[3] ***: glassfish: EJB FAQ, https:// glassfish.dev.java.net/ javaee5/ ejb/
EJB FAQ.html.
[4] Stefan Tanasa, Cristian Olaru, Stefan Andrei: JAVA de la 0 la expert,
Ed. Polirom, Iasi, 2003.
[5] Stefan Tanasa, Cristian Olaru: Dezvoltarea aplicatiilor Web folosind
JAVA, Ed. Polirom, Iasi, 2005.
[6] ***: jar - The JAR File Tool, Java Tool Tutorials - Herongs Tutorial Notes, http://www.herongyang.com/Java-Tools/jar-The-JAR-FileTool.html.
[7] Cristina Fierbinteanu: Programare orientata pe obiecte: Java, Editura
Universitatii Titu Maiorescu, Bucuresti, 2008.
[8] Jim Keogh: Java fara mistere, Ed.Rosetti Educational, Bucuresti, 2006.
[9] Michael J. Hernandez: Proiectarea bazelor de date, Ed. Teora, Bucuresti,
2003.
[10] Kathy Sierra, Bert Bates: Atac la Java (Head First Java Second Edition), Ed. Teora USA, 2006.
[11] Richard Monson-Haefel, Bill Burke: Enterprise JavaBeans 3.0, 5th Edition, OReilly Media, Inc., 2006.
99

100

BIBLIOGRAFIE

[12] Cristian
Frasinaru:
Curs
practic
de
Java,
http://profs.info.uaic.ro/
acf/java/Cristian FrasinaruCurs practic de Java.pdf, Ed. Matrix Rom, 2005.