You are on page 1of 39

Sistem Object Relational Mapping in Java

Student Hotnog Sorin Traian


Grupa:MPI

CUPRINS

Introducere ................................................................................................................... 3
Principalii indicatori de fiabilitate a sistemelor ........................................................ 3
Caracteristici generale ale object relational mapping ................................................... 6
Contextul .................................................................................................................. 6
ORM (Object Relational Mapping) .......................................................................... 7
Motivaia dezvoltrii unui sistem de ORM .............................................................. 8
Descrierea proiectului ............................................................................................... 9
Alegerea Platformei .................................................................................................... 10
Tehnologii folosite...................................................................................................... 11
IDE (Mediu integrat de dezvoltare) ........................................................................ 11
Sisteme de management ale bazelor de date relaionale ........................................ 14
PostgreSQL......................................................................................................... 14
Microsoft SQL Server ........................................................................................ 15
API-uri folosite ....................................................................................................... 15
API-ul de JDBC(Java Database Connectivity)................................................... 16
API-ul de Reflection ........................................................................................... 17
API-ul de SWT(Standard Widget Toolkit)......................................................... 18
API-ul pentru crearea de fiiere PDF ................................................................. 20
Dezvoltarea aplicaiei ................................................................................................. 21
Cerinele aplicaiei .................................................................................................. 21
Arhitectura .............................................................................................................. 22
Strucura proiectului ................................................................................................ 23
Funcionalitile sistemului i tratarea problemelor ............................................... 26
Concluzii................................................................................................................. 38
Bibliografie ................................................................................................................. 38

Introducere

Fiabilitatea este un domeniu interdisciplinar care studiaza legile degradarii in timp a elementelor si
sistemelor. Este necesar sa se cunoasca cat mai exact care este nivelul real al fiabilitatii, astfel incat, in functie
de acesta, sa se stabileasca durata misiunii, perioadele de revizie si elementele de siguranta.
Descrierea matematica a fiabilitatii unui sistem poate fi facuta la nivel global, ignorand structura
sistemului, sau la nivel structural, luand in consideratie elementele sistemului si relatiile dintre ele. In ambele
cazuri caracterizarea fiabilitatii sistemului va folosi teoria probabilitatilor.

Principalii indicatori de fiabilitate a sistemelor sunt:


1. Fiabilitate: R(t)=p(t)=Prob(T>t)
Adica probabilitatea ca sistemul S sa functioneze fara defectiuni pe o perioada de timp .
R(t)=p(t) => 0<p(t)<1,
p(t) = 1, t = 0
p(t) =0, t = infinit.
R(t) este o functie descrescatoare in timp.
t timp de misiune.
T este o variabila aleatoare si reprezinta durata de functionare pana la defectare.
2. Disponibilitate D(t): probabilitatea ca sistemul sa fie in stare de functionare la momentul t (in
orice moment).
3. Mentenabilitate M(t): probabilitatea ca sistemul sa poata fi supravegheat , intretinut si reparat
intr-o anumita perioada de timp.
M(t) este o functie crescatoare de la 0 la 1, pe intervalul [0,infinit).
4. Timp de buna functionare: intervalul de timp intre doua defectari succesive.
MTBF timpul mediu de buna functionare.
5. Mentenanta: totalitatea actiunilor care se executa periodic in scopul mentinerii caracteristicilor
functionale.
6. Restabilire: proprietatea dispozitivului de a-si recapata capacitatea de functionare dupa efectuarea
reparatiilor sau a altor operatii de inlaturare a defectului.

Proiectul i propune a fi o aplicaie de dezvoltare a unui sistem de ORM (Object Relational


Mapping) care s implementeze cele patru funcii principale de lucru cu baza de date, select, update,
insert, delete.
El presupune familiarizarea cu API-urile de JDBC i de Reflection, implementarea mini
ORM-ului i dezvoltarea unei aplicaii de test pentru acesta.
Alegerea acestui proiect se datoreaz lucrului cu astfel de sisteme , dar fr s fi avut o
nelegere de ansamblu asupra funcionrii interne.
Pentru dezvoltarea aplicaiei am folosit limbajul de programare Java, API-uri pentru JDBC,
Reflection, SWT i creare de PDF i ca sisteme de management al bazelor de date am ales cele mai
reprezentative dou sisteme PostgreSQL i Microsoft Sql Server.

Notaii i Abrevieri

API Application Programming Interface


AWT Abstract Window Toolkit
DB Database
GWT Google Web Toolkit
IDE Integrated Development Environment
JDBC Java Database Connectivity
JPA Java Persistance API
JVM - Java Virtual Machine
J2EE Java Enterprise Edition
J2ME Java Micro Edition
J2SE Java Standard Edition
MVC Model View Controller
ORM Object Relational Mapping
PDA Personal Digital Assistant PK
Primary Key
POO Programare Orientat pe Obiecte
SGBD Sistem de Gestiune a Bazelor de Date
SQL Structured Query Language
SWT Standard Widget Toolkit

Caracteristici generale ale object relational mapping


Contextul
nc de la apariia modelului de baze de date relaionale programatorii au simit nevoia
s sporeasc posibilitile acestui model i s-l fac mai flexibil. Un salt uria n acest sens a
fost fcut n anii 90, atunci cnd limbajele orientate-obiect au nceput s capete o influen tot
mai mare.
O prim ncercare de a lega obiectele din POO cu tabelele unei baze de date a fost
fcut n anul 1992 de compania NeXT (companie nfiinat de Steve Jobs la mijlocul anilor
80). Soft-ul dezvoltat nu era un ORM n adevratul sens al cuvntului, el fiind mai apropiat de
JDBC-ul din Java. Acest sistem purta denumirea de DbKit i reprezenta un layer de
abstractizare, care asemntor JDBC-ului de astzi permitea accesul la diferite baze de date fr
obligativitatea de a scrie cod specific bazelor de date. Pornind de la acest sistem, dezvoltatorii
de la NeXT au lansat mai apoi un framework de ORM complet.
Totui, primul sistem ce poate fi considerat un ORM a fost dezvoltat pentru limbajul
SmallTalk de o mic firm din Canada i s-a numit TopLink. n 1996 a aprut i prima versiune
pentru Java.
Prima versiune de TopLink permitea printre altele:
a) s mapeze cmpurile bazei de date pe atributele obiectelor
b) s realizeze conversie ntre tipurile atributelor i tipurile cmpurilor pe care se
mapeaz
c) posibilitatea de a mapa o nregistrare din baza de date pe mai multe obiecte
Dei aparent dezvoltarea unui astfel de sistem pare c a venit de la sine, o perioad
semnificativ de timp s-a lucrat la rezolvarea conflictelor dintre limbajele orientate-obiect i
sistemele de gestiune ale bazei de date.
Este cunoscut faptul c o baz de date prezint pentru fiecare tabel o cheie primar care
identific n mod unic o nregistrare. Spre deosebire de nregistrrile din baza de date, obiectele
din Java pot s fie identice, caz n care au aceai valoare i aceeai adres n memorie, sau egale,
avnd doar acceai valoare.
Alte diferene sunt legate de concepte precum motenire, granularitate, asociere. n
ceea ce privete motenirea, obiectele din Java accept motenire simpl i preiau atributele i
metodele obiectului motenit. n schimb, bazele de date nu cunosc noiunea de motenire.
Conceptul de asociere se refer la modul de legare a dou entiti fie n Java, fie n
baze de date. Dac n Java asocierile sunt unidirecionale, n baze de date acestea sunt
bidirecionale i se fac prin intermediul cheii externe. n cazul n care se doresc legturi
bidirecionale n Java, se poate declara n fiecare obiect un cmp de tipul celuilalt obiect.
Granularitatea se refer la problema legat de numrul de obiecte din model
comparativ cu numrul de tabele din baz. Pentru a se putea face maparea obiectelor pe baza de
date este necesar existena unei corespondene. Prin urmare cele dou numere trebuie s fie
egale.
6

ORM (Object Relational Mapping)

Dup cum am precizat, ORM-ul a aprut n perioada n care limbajele de programare


orientate obiect au cptat un avnt deosebit, fiind principalele limbaje de dezvoltare datorit
flexibilitii i uurinei de dezvoltare. Cu toate acestea necesitatea comunicrii cu un sistem de
gestiune a bazelor de date a determinat piaa IT s gseasc soluii de comunicare ntre obiectele
create i tabelele bazei de date, precum i gsirea de soluii pentru conflictele de
incompatibilitate dintre cele dou tehnologii.
Astfel, el reprezint un nivel de legtur ntre cele cele dou modele:

TABEL A

Obiect A

SGBD

ORM

TABEL B

Obiect B

Fig. 1.1 ORM legtura dintre obiecte i SGBD

Din figura de mai sus se observ corespondena Obiect A Tabel A , respectiv Obiect B Tabel
B.
Dei faptul c asigur comunicarea cu baza de date este un aspect foarte important,
ORM-ul mai are o serie de avantaje precum :
a)
Independena fa de baza de date acest fapt reprezint un avantaj major al
sistemului ORM deoarece nu conteaz sistemul de management al unei baze de date relaionale
folosit, n Java codul folosit va fi acelai, metodele nu vor avea ali parametri sau nu vor avea
alte rezultate. Schimbarea sistemului de management al bazei de date nu va determina
schimbarea vreunei linii de cod n Java.
b)
Simplitatea Este mult mai uor de lucrat cu obiecte n Java i de folosit
principiile POO dect lucrul cu cod SQL. n SQL, atunci cnd se depete un anumit grad de
dificultate lucrurile pot deveni foarte ncurcate, pe cnd n Java tot timpul vor fi mai uor de
prelucrat datele i de folosit aa cum ne dorim.

c)
Scalabilitate Sistemul va funciona la fel indiferent de dimensiunea bazei de
date, a tabelelor sau a tipurilor de date folosite
d)
Rapiditate Operaiile dorite se vor executa ntr-un timp foarte scurt, rezultatele
vazndu-se imediat
e)
Un mare avantaj pentru programator este reprezentat i de faptul c nu va mai fi
nevoit s realizeze o conexiune de fiecare dat i s apeleze la concepte de JDBC, conexiunea
se va face automat cnd va fi nevoie iar datele vor fi salvate n obiecte.
f)
ntreinerea codului i depanarea lui va fi foarte uoar avnd n vedere cantitatea
de cod mult redus i uurina cu care acesta poate fi neles.

Motivaia dezvoltrii unui sistem de ORM

De-a lungul timpului, att n calitate de student ct i n calitate de programator, am


avut ocazia s folosesc mai multe sisteme de mapare a obiectelor pe tabelele unei baze de
date. Dintre acestea cele mai cunoscute sunt Hibernate i JPA(Java Persistence Api).
Dei tiam s folosesc un ORM, nu nelegeam pe deplin tot ce se ntmpl n spate,
iar realizarea acestei lucrri a fost o bun oportunitate s studiez i s ncerc s rezolv
problemele ce pot aprea la un astfel de sistem.
Dou probleme pe care eu le-am ntlnit i pe care le-am considerat mai importante,
necesitnd o atenie mai deosebit erau reprezentate de maparea cheii primare i
compatibilitatea irurilor de caractere.
La maparea cheii primare apar de fapt dou probleme ce trebuie rezolvate:

Prima din ele este necesitatea specificrii printr-un parametru a numelui coloanei din
baz sau numele cmpului trebuie s se potriveasc cu numele coloanei din tabel. Prin
soluia propus am fcut s nu mai fie necesar potrivirea de nume, am considerat c
tratarea cheii primare ar trebui s fie una special, n sensul c ar trebui sa fie mai uor
de mapat, nu mai greu dup prerea mea, ca n Hibernate.

A doua problem la maparea cheii primare este i cea care face ca maparea s fie mai
dificil, i anume generarea id-urilor atunci cnd se face un insert. n Hibernate practic
trebuia mapat i o secven pentru generarea id-urilor. De asemenea, neplceri mai
apreau i dac se fceau insert-uri n sesiuni diferite de lucru,generarea secvenei
fcndu-se de la o valoare cu 50 mai mare fa de valoarea cu care s-a nceput sesiunea
precedent. Astfel, dac se fceau ntr-o sesiune de lucru mai mult de 50 de insert-uri
apreau probleme n sesiunea urmtoare deoarece se ncerca o inserare cu un id care
deja exista. Eu am ncercat ca prin simpla mapare cu o adnotare generarea s se fac
automat n raport cu valoarea maxim din tabel indiferent de sesiunea de lucru.

La compatibilitatea irurilor de caractere, Hibernate impune o limitare de 255 de caractere.


Dac se folosesc iruri de caractere mai mari, este necesar la mapare s se precizeze i
8

dimensiunea irului. Am fcut ca irurile de caractere s fie compatibile fr a fi nevoie de


o mapare special n cazul unor dimensiuni mai mari.
Dei am utilizat mai multe astfel de sisteme de ORM, am ales s m raportez la Hibernate
deoarece este cel mai popular dintre ele i totodat cel mai complet sistem de acest gen
existent pe pia, acesta fiind i sistemul cu care eu m-am iniiat n tainele folosirii
ORMurilor.

Descrierea proiectului
Proiectul presupune dezvoltarea unui mini sistem de mapare a obiectelor pe tabelele din
baza de date. Totui el trebuie s permit maparea obiectelor pe orice sistem de management al
bazelor de date relaionale, fr impunerea unui anumit sistem. Totodat, el trebuie s poat s
fac conversie ntre tipurile proprietilor din obiectele Java i tipul cmpurilor din tabele.
Acest mini ORM trebuie s implemeteze principalele operaii pe baza de date, cunoscute n
limbajul SQL ca: SELECT, DELETE, UPDATE, INSERT. Metodele asociate acestor operaii
sunt:

pentru SELECT
a) read(Object) aceast metod primete ca parametru un obiect al crui id este
cunoscut i returneaz din baza de date valorile cmpurilor pentru nregistrarea
cu id-ul id
b) readAll(Object) aceast metod primete ca parametru un obiect care
corespunde unui tabel din baz i returneaz toate nregistrarile din respectivul
tabel.

pentru DELETE
delete(Object) aceast metod primete ca parametru un obiect cu id cunoscut
i terge din baz nregistrarea din tabelul asociat obiectului, care are id-ul
id.Aceast metod nu returneaz nici un rezultat.

pentru UPDATE i INSERT


save(Object) aceast metod primete ca parametru obiectul care trebuie
salvat. Aceast metod reprezint de fapt saveOrUpdate pentru c n urma
analizrii id-ului obiectului el tie dac s fac Update sau s fac Insert. Astfel
dac id-ul obiectului este null, ceea ce nseamn c obiectul nu conine date, se
va face un insert n baz. n caz contrar se va face un Update.

Proiectul presupune rescrierea de la capt a metodelor de lucru pe bazele de date i nu


doar apelarea unor metode existente din alte sisteme asemntoare.
n procesul dezvoltrii acestui sistem, dezvoltatorul este nevoit s fac apel la noiuni
precum:
a) Reflection pentru studierea coninutului claselor
b) JDBC pentru realizarea conexiunilor cu baza de date
9

Pentru a demonstra avantajul sistemului este neesar realizarea unei aplicaii de test care
s permit tipuri de date multiple. Aceast aplicaie are ca tematic medicina i se ocup n
principiu de reete medicale, programri la doctor i vizualizarea acestora i este dezvoltat
folosind API-ul de SWT.

Alegerea Platformei

O platform este un mediu hardware sau software n care poate fi rulat un program.
Platforma aleas pentru dezvoltarea ORM-ului este platforma Java. Aceasta este o platform
software.
Alegerea acestei platforme se justific prin multitudinea de avantaje pe care le pune la
dispoziia dezvoltatorului:

este portabil,

ruleaz pe orice sistem de operare(Windows, Linux , Solaris, Mac OS) datorit


interpretorului integrat ce furnizeaz cod nativ al respectivului sistem

Alte motive sunt reprezentate de faptul c limbajul Java este orientat obiect ceea ce permite
refolosirea codului i duce la micorarea semnificativ a dimensiunii codului, este robust i nu
n ultimul rnd este simplu de utilizat.
Platforma Java are dou componente:
a)
Maina virtual Java (Java Virtual Machine) Este componenta platformei care
face posibil neutralitatea fa de arhitectura folosit. La compilarea fiierelor .java ce conin
codul surs se creeaz nite fiiere cu extensia .class care conin secvene de bytecodes. Java
bytecodes reprezint instruciuni n limbaj main pentru JVM (Java Virtual Machine).
La stadiul actual instruciunile nu sunt nc destinate procesorului. Pentru a putea fi transformate
n cod neles de procesor este necesar o tranformarea din bytecodes n cod nativ al platformei
hardware prin intermediul Interpretorului integrat n structura JVM

Clas.java

Clas.class(
bytecodes)

Compilare

Cod main
JVM

Fig 2.1. Fluxul de compilare i rulare al unei clase

b)
A doua component a platformei Java este API ul de Java (Application
Programming Interface) Acesta reprezint o colectie de librrii ce ajut la dezvoltarea mai
uoar a programelor. API-ul de Java este structurat n pachete, fiecare pachet nglobnd
metode, constante, parametri utilizai de ctre programatori n crearea obiectelor i structurilor
proprii.
10

n continuare voi dezvlui cteva avantaje ce justific alegerea unei astfel de platforme.
Ele sunt dup cum urmeaz:
a)
Simplitatea Java a fost proiectat s fie un limbaj simplu de utilizat i neles, el poate
fi asimilat cu usurin de ctre programatori, mai ales dac acetia au ceva experien si cu C++.
b)
Java este un limbaj orientat obiect Ofer un grad ridicat de abstractizare i ncapsulare.
Aest lucru duce la performane de securitate crescute, programatorul putnd face vizibile doar
informaiile pe care le dorete din interiorul obiectelor i folosind pentru acest lucru metode
dedicate accesrii informaiilor.
c)
Lucrul cu memoria este mult mbuntit, acest lucru datorndu-se n mare parte faptului
c nu mai exist pointeri definii de programator. Acetia erau o surs bogat de erori atunci
cnd se fcea accesul la memorie n C/C++. Limbajul introduce de asemenea un sistem automat
numit Garbage Collector care urmrete structura memoriei i observ obiectele neutilizate
urmnd s elibereze zona ocupat de respectivele obiecte i evitnd astfel fragmentarea
memorie.
d)
Principalul avantaj l reprezint portabilitatea. Un cod scris corect n limbajul Java ar
trebui s ruleze pe orice platform hardware fr nici o problem. Acesta reprezint un avantaj
major chiar i n faa unor limbaje care pot rula mai repede aa cum este C/C++. Este adevrat
c Java consum mai mult memorie i ruleaz ntr-un timp puin mai mare dect C/C++ dat
fiind faptul c este att un limbaj compilat ct i un limbaj interpretat. Totui n ziua de azi
diferenele nu mai sunt aa mari ca la nceputurile limbajului Java, iar portabilitatea limbajului
Java eclipseaz micul avantaj al C++. n cazul n care un program dezvoltat n C++ ar trebui
portat pe alt platform ar fi necesare modificri majore n cod.
n dezvoltarea ORM ului am ales platforma Java Standard Edition din cele trei platforme
oferite de Java, celelale dou fiind Java Micro Edition (platform destinat dispozitivelor
mobile aa cum sunt PDA uri sau telefoane mobile) i Java Enterprise Edition (platform
destinat sistemelor de calcul distribuite sau de mari dimensiuni), deoarece se preteaz cel mai
bine cerinelor proiectului fiind o platform specific aplicaiilor desktop.

Tehnologii folosite

n dezvoltarea acestui ORM am folosit:

un IDE(Mediu Integrat de Dezvoltare),

dou sisteme de management ale bazelor de date relaionale

patru APIuri necesare dezvoltrii sistemului i testrii acestuia.

IDE (Mediu integrat de dezvoltare)


Ca mediu integrat de dezvoltare am folosit Eclipse versiunea 4.2.2 (Eclipse Juno) care
poate fi descrcat gratuit de pe site ul cu acelai nume. Am fcut aceast alegere deoarece
este un IDE foarte popular care ofer numeroase faciliti cum ar fi generarea automat de
11

cod, formatarea automat a codului i folosirea scurtturilor de taste pentru ndeplinirea mai
multor aciuni precum importuri de pachete necesare.
Cele mai folosite facilii din cele amintite mai sus sunt generarea automat a codului i
realizarea importurilor necesare. Generarea automat de cod se refer n general la generarea
de constructori cu sau fr parametri i generarea de getteri i setteri. Exist dou modaliti
de generare a getteri lor i setteri lor:
a) Din meniul Source se alege opiunea Generate Getters and Setters....
n fereastra deschis se pot alege cmpurile pentru care s se genereze getteri i
setteri.

Fig. 3.1. Meniul Source

A doua metod folosete combinaia de taste ALT+S dup care se


apas tasta R.
Dup apsarea tastelor se va deschide aceeai fereastr ca la punctul anterior.
b)

12

Fig. 3.2. Fereastr generare getteri/setteri

De asemenea exist dou modaliti de generare a constructorilor:


a)
Din meniul Source se alege una din opiunile Generate
Constructor using fields... sau Generate Constructors from Superclass.... n
primul caz se pot alege cmpurile ce vor fi introduse n construcor, iar n cel de
al doilea se genereaz un constructor motenit de la clasa Object.
b)
A doua metod folosete combinaia de taste ALT+S i dup
aceea se apas tasta C. Prin aceast combinaie se deschide o list similar cu cea
a meniului Source din care dezvoltatorul poate alege opiunea cea mai
convenabil.

13

Fig. 3.3. Meniu aprut la apsarea combinaiei de taste

Realizarea importurilor pachetelor se face prin combinaia de taste CTRL+SHIFT+O.


Dup apsarea lor, Eclipse va face toate importurile necesare n clasa n care ne aflm. O alt
combinaie de taste util este CTRL+SHIFT+F, combinaie ce realizeaz formatarea codului.
n cazul unei erori de cod, precum greirea numelui unei variabile sau atunci cnd nu
se cunosc toi parametri unei metode se poate folosi combinaia de taste CTRL+1 (Quick Fix)
care i afieaz o list cu soluii posibile la problem.
Un alt avantaj al folosirii acestui IDE l reprezint multitudinea de pluginuri
disponibile gratuit ce vin n ajutorul dezvoltatorului. Din cele mai importante amintim plugin
ul pentru dezvoltarea de aplicaii pe platforma Android, plug-in-ul pentru interfee web de la
google(GWT), plug-in-ul pentru SWT.

Sisteme de management ale bazelor de date relaionale


Am ales ca sisteme de management ale bazelor de date relaionale PostgeSQL i
Microsoft SQL Server 2012 deoarece sunt printre cele mai importante i utilizate sisteme de
acest gen.
PostgreSQL
PostgreSQL este probabil cel mai apreciat sistem de management al bazelor de date
relaionale datorit faptului c este disponibil pentru toate marile platforme(Windows, Linux,
Mac OS X) i este de asemenea apreciat pentru stabilitate, integritatea datelor i corectitudine.
Ofer posibiliatea stocrii de imagini, sunete i chiar clipuri video. De asemenea PostgreSQL
este compatibil i cu PL/SQL de la Oracle. Succesul se datoreaz i faptului c sistemul este
gratuit i open-source.
14

Un alt avantaj al PostgreSQL este faptul c ofer interfee de lucru cu numeroase


limbaje de programare aa cum sunt Java, C++, .NET, PHP, Perl etc.
Lucrul ce a determinat ca PostgreSQL s fie cel mai apreciat astfel de sistem att de
ctre mari companii ct i de utilizatorii de zi cu zi este reprezentat de limitrile pe care sistemul
le impune: dimensiunea unui tabel poate atinge 32TB, dimesiunea unei nregistrri
1,6 TB, numrul de nregistrari poate fi nelimitat, dimesiunea bazei de date poate fi nelimitat,
numrul de coloane poate ajunge la 1600 n funcie de tipul de date i nu n ultimul rnd numarul
de indeci pentru un tabel este nelimitat.

Microsoft SQL Server


Microsoft SQL Server este un sistem de management al bazelor de date relaionale
dezvoltat de Microsoft. Avnd n vedere popularitatea sistemului de operare al celor de la
Microsoft i sistemul de management al bazelor de date relaionale dezvoltat de ei este unul
dintre cele mai populare, unul din dezavantaje fiind c este disponibil doar pentru sistemele de
operare de la Microsoft. Sistemul nu este open-source, exist unele variante gratuite dar la care
se limiteaz dimensiunea bazei de date la 10 GB. Pentru o variant pltit dimensiunea bazei
de date este de 540 PB.
Un motiv pentru care Microsoft SQL Server este popular dei este funcional doar pe
sistemele de operare de la Microsoft sunt limitrile pe care le impune, pe lng dimesiunea
bazei de date mai sus amintit sistemul impune urmtoarele limitri: dimesiunea unei
nregistrri este nelimitat, numrul de coloane pentru fiecare tabel poate ajunge la 30000,
numrul maxim de caractere al numelui unei coloane este de 128, iar dimesiunea maxim a unui
tabel corespunde cu dimensiunea maxim a bazei de date.
Un alt avantaj al Microsoft SQL Server este integrarea cu celelalte unelte software
dezvoltate de Microsoft, care sunt foarte populare, astfel o persoan sau o companie care
utilizeaz software Microsoft nu va avea nevoie de modificri mari sau de upgrade-uri ale
sistemelor deja existente atunci cnd vor dori instalarea acestui sistem de management al
bazelor de date. Microsoft SQL Server ofer interfa de lucru cu toate limbajele suportate de
platforma .NET cum ar fi: C#, J#, Visual Basic, C++, F# etc.
n afara limbajelor suportate de platforma .NET Microsoft SQL Server mai ofer
interfa de lucru cu Java, cu ajutorul unui driver de JDBC, aceasta fiind o tehnologie pe care o
vom trata mai trziu.
Am ales aceste dou sisteme deoarece le-am considerat reprezentative pentru
sistemele de management ale bazelor de date existente.

API-uri folosite
n dezvoltarea acestui ORM am folosit patru API-uri: API-ul de JDBC oferit de
platforma Java, API-ul de Reflection, API-ul de SWT(Standard Widget Toolkit) i API-ul
pentru generarea de PDF-uri.

15

API-ul de JDBC(Java Database Connectivity)


JDBC este un API dezvoltat de compania Oracle care ajut la lucrul cu o baz de date
scriind cod Java. Acest API are suport pentru executarea a diferite operaii pe baza de date cum
ar fi INSERT, UPDATE, DELETE, SELECT.
n continuare voi prezenta modul de lucru cu JDBC i paii necesari extragerii unui set
de date din baz sau executrii oricrei alte operaii pe baza de date. Vom presupune c avem
deja o baz de date format.
Mai nti de toate este necesar descrcarea driver-ului specific bazei de date pe care
o folosim i includerea lui n proiectul nostru.
Urmtorul pas este ncrcarea driver-ului din cod cu ajutorul metodei
forName(numele
driverului) aplicat
pe
un
obiect Class n
felul urmtor: Class.forName(numele driverului). Aceasta metod va cuta driver-ul, iar
dac acesta nu exist va genera o excepie corespunztoare.
n continuare este necesar stabilirea conexiunii cu baza de date. Pentru acest lucru va
trebui s cunoatem:

utilizatorul bazei de date,

parola pentru accesul la baza de date

url-ul bazei de date mpreun cu numele acesteia.

Stabilirea conexiunii se face prin aplicarea metodei getConnection pe un obiect de tip


DriverManager n felul urmtor:

DriverManager.getConnection(url, utilizator, parol) n cazul majoritii sistemelor


de management ale bazelor de date aa cum este i PostgreSQL,

pentru Microsoft SQL Server se folosete metoda getConnection( ir ), care dup


cum se poate observa primete un singur parameru de tip String care conine toate
datele necesare stabilirii conexiunii. Aceast metod va returna un obiect de tip
Connection. Dac conexiunea nu se realizeaz se va genera o excepie n
concordan cu problema aprut.

Dup stabilirea conexiunii vom scrie interogarea pentru aciunea ce urmeaz s o


executm pe baza de date. Aceasta va fi reinut ntr-o variabil de tip String. Pentru executarea
interogrii sunt necesari doi pai.
n primul rnd este necesar crearea unui obiect de tip Statement pe baza conexiunii
deja create. Pot exista trei tipuri de acest fel:

Statement care atunci cnd este folosit ncarc n memorie de fiecare dat
interogarea,

PreparedStatement care ncarc o singur dat interogarea n memorie i o pstreaz


acolo,

CallableStatement care este folosit atunci cnd se apeleaz proceduri stocate ale
bazei de date.
16

n dezvoltarea proiectului am folosit un obiect de tip Statement. Apoi vom aplica


obiectului de tip Statement metoda executeQuery care va primi ca parametru variabila de tip
String n care am reinut interogarea.Dac s-a fcut un SELECT rezultatele vor fi reinute ntrun obiect de tip ResultSet. n cazul n care operaia a fost una de tip UPDATE, INSERT sau
DELETE vom primi ca rezultat doar numrul de rnduri afectate de ctre operaia noastr.
De asemenea cu ajutorul JDBC putem obine informaii si despre tabele, cum ar fi
numele coloanelor, tipul lor, numrul lor. Acest lucru se poate realiza folosind metoda
getMetaData() pe care o aplicm pe un obiect de tip ResultSet. Meta datele sunt reinute ntrun
obiect de tip ResultSetMetaData.
Ultimul pas dup ce ne-am ndeplinit scopul propus este nchiderea conexiunii prin
aplicarea metodei close() asupra obiectului de tip Connection n care am reinut conexiunea. n
cazul n care uitm s nchidem conexiunea Garbage Collector-ul va nchide respectiva
conexiune cnd elibereaz memoria ocupat de obiecte ce nu mai sunt folosite. Totui nu se
ncurajeaz lsarea acestei probleme n seama collector-ului deoarece pot aprea alte probleme.

API-ul de Reflection
Reflection este o tehnologie ce permite studiul structurii unui obiect i modificarea
acesteia sau luarea de decizii n timpul rulrii pe baza structurii din acel moment a obiectului.
n Java API-ul de Reflection permite studierea clasei unui obiect, a cmpurilor
acestuia, a constructorilor, a metodelor din clas. Este posibil aflarea de informaii chiar i
despre cmpurile private.
Despre clase putem afla informaii cum ar fi adnotrile care sunt folosite pentru clasa
respectiv, numele clasei, cmpurile clasei, metodele acesteia, constructorii acesteia, pachetul
din care face parte i pachetele importate, interfeele pe care le implementeaz.
Despre constructorul unei clase putem afla parametrii pe care acesta i primete i
putem crea noi instane ale obiectului studiat prin apelul metodei newInstance(). Aceasta se
aplic pe obiectul de tip Constructor n care am reinut constructorul obiectului studiat. Aceast
metod primete ca parametri exact ce parametri primete i constructorul obiectului studiat.
Atunci cnd vrem s aflm informaii sau s manipulm cmpurile putem folosi
Reflection pentru a afla numele cmpurilor, adnotrile ce sunt folosite pentru cmpul studiat,
tipurile acestora i putem afla i modifica valorile acestora.
Pentru a afla informaiile despre cmpurile private este necesar s folosim metoda
getDeclaredFields().Aceasta, spre deosebire de metoda getFields() care ne va returna un vector
ce va conine doar cmpurile publice, ne va returna un vector cu toate cmpurile clasei inclusiv
cele private.
Despre metode putem afla parametri pe care aceasta i primete i tipul pe care aceasta
l returneaz. De asemenea cu ajutorul Reflection putem executa metode ale obiectului cu
ajutorul metodei invoke() care va primi ca parametri obiectul pentru care se execut metoda i
parametrii pe care aceasta i primete. Metoda invoke() va fi executat pentru obiectul de tip
Method n care am reinut metoda.
Mai putem afla informaii cum ar fii adnotrile prezente pe parametri funciilor sau ai
constructorilor, adnotrile de pe getteri i setteri.
17

API-ul de SWT(Standard Widget Toolkit)


Standard Widget Toolkit este un plug-in destinat dezvoltrii de interfee grafice. Acest
plug-in folosete componente native ale sistemului de operare pe care se face dezvoltarea ns
elementele grafice nu au un aspect nvechit aa cum ne-am atepta. SWT se vrea a fi o
combinaie ntre rapiditatea cu care sunt ncrcate elementele native la AWT i aspectul plcut
al elementelor din Swing.
Dezvoltarea se poate face att din mediul grafic (drag and drop dintr-o palet de
elemente n fereastra noastr ) ct i din cod. Varianta preferat de cei mai muli dintre
programatori este dezvoltarea n mediul grafic, rmnnd ca n cod sa fie scrise doar asculttorii
petru butoane i celelalte elemente grafice folosite.

Fig. 3.4. - Palet de componente

18

Fig. 3.5. - Paleta de elemente n SWT

Fig. 3.6. Exemplu de caset cu proprietile unui element Prin adugarea

unui element din palet n canvas, se va deschide automat o fereastr de proprieti din care
poate fi ajustat design-ul elementului respectiv.
19

Pentru a putea folosi SWT este necesar instalarea plug-in-ului mai nti deoarece
acesta nu este prezent n pachetul standard al Eclipse. Acest lucru se poate face foarte uor din
Eclipse din meniul Help opiunea Install New Software.... Plug-in-ul este gratuit i
opensource. Plug-in-ul este dezvoltat de IBM i de aceea nu vine mpreun cu API-ul standard
de java, n API-ul standard de Java putem gsi Swing i AWT, care sunt dezvoltate de compania
Sun, companie ce deine drepturile asupra Java.
Pentru a putea folosi mediul grafic de dezvoltare este necesar crearea unui tip de
clas ce poate fi gsit dup instalarea plug-in-ului. Crearea acestui tip de clas se face prin
click dreapta pe pachetul n care vrem s creem clasa, din meniul deschis alegem opiunea
New, iar din submeniul deschis vom alege opiunea Other. Din fereastra deschis vom
alege tipul de clas Application Window din folderul SWT aa cum vei vedea n imaginea
urmtoare.

Fig. 3.7. Clas pentru dezvoltarea n mediul grafic

API-ul pentru crearea de fiiere PDF


Pentru crearea de fiiere PDF am folosit API-ul iText. iText este o bibliotec ce permite
crearea, citirea i manipularea de fiiere PDF. Pentru instalarea lui este necesar decrcarea
arhivei de tip jar ce conine biblioteca i introducerea ei n proiect.
iText ofer numeroase faciliti de formare a PDF-urilor:
a) se poate face gruparea mai multor elemente ntr-un paragraf sau ntr-o fraz,
b) se pot seta fonturi pentru diverse elemente cum ar fi un titlu sau un paragraf,
c) se pot aduga imagini, tabele,
d) se pot pune referine,
e) se poate face mprirea pe capitole i seciuni.
20

f) de asemenea se poate scrie cu indici sau cu exponent sau se poate scrie textul
subliniat, tiat, boldat sau nclinat.
iText are elemente cu o structur ierarhic. Cea mai mic unitate din iText se numete
Chunk. Chunk-ul reprezint un String cruia i se poate seta doar fontul. Chunk-urile se pot
organiza n structuri mai mari i anume obiecte de tip Phrase.
Obiectele de tip Phrase permit definirea de spaiere. Pentru definirea mai multor
atribute cum ar fi cele de stil se folosesc obiecte de tip Paragraph. Acestea sunt obiecte ce
motenesc obiectele de tip Phrase.
O clas de obiecte ce motenete clasa Paragraph se numete Anchor i permite
definirea de referine de la anumite poriuni din text la alte poriuni mai ndeprtate sau la care
se face referire n text. Obiectele de tip Paragraph se pot grupa n structuri de tip Chapter.
n iText mai putem ntlni obiecte de tip Section pentru definirea unei seciuni, List
pentru realizarea de liste ordonate sau neordonate, obiecte de tip Font penru definirea de fonturi.

Dezvoltarea aplicaiei
Aplicaia dezvoltat este reprezentat de un mini sistem de mapare a obiectelor din Java
pe tabelele unei baze de date, sistem denumit Object-Relational Mapping.

Cerinele aplicaiei
Scopul acestei lucrri l reprezint dezvoltarea unui sistem ORM care s fie uor de
folosit i neles.
Obiectivele acesti proiect sunt reprezentate de implementarea operaiilor uzuale de
INSERT, UPDATE, DELETE, SELECT, iar mai apoi s poat fi folosite fr a mai scrie cod
SQL. Un alt obiectiv l reprezint funcionarea ORM-ului pe baza unor relaii stabilite ntre
obiectele din Java i tabelele din baza de date. Aceste relaii se pot stabili fie prin folosirea
adnotrilor fie prin folosirea unor fiiere de configurare de tip properties sau xml. n aceast
lucrare am ales s folosesc varianta cu adnotri deoarece este varianta mai modern i care a
ctigat teren n faa celei de-a doua n ultimii ani. De asemenea varianta cu asdnotri este dup
prerea mea mai simplu de neles i mai intuitiv.
Dup definirea relaiilor dintre obiecte i tabele se vor folosi doar obiectele i metodele
implementate n ORM. ORM-ul trebuie s dispun de urmtoarele metode:
a) read(object) citete toate cmpurile obiectului specificat din care iniial
este cunoscut doar id-ul
b)

readAll(object) citete toate obiectele de tipul obiectului specificat fr

c)
doar id-ul

delete(object) terge obiectul specificat din care iniial este cunoscut

vreo
clauz WHERE

21

d) save(object) dac id-ul este null se va face un INSERT n baza de date,


se vor salva cmpurile obiectului specificat i se va genera un id; dac id-ul nu este
null atunci se va face un UPDATE n baza de date
Conexiunea trebuie s fie realizat cu ajutorul unui fiier de configurri. Datele se
vor introduce o singur dat iar apoi pe baza lor conexiunea se va face automat.

Arhitectura
Noiunea de arhitectur software se refer la componentele de nivel nalt ale unui
sistem software. Arhitectura definete att modulele sistemului pe baza unui set de reguli i
relaiile care se stabilesc ntre acestea, ct i proprietile pe care modulele i relaiile dintre ele
le dein.
La cazul general, o arhitectur pentru un sistem software se compune din:
Component de comunicaie cu exteriorul
Component ce se ocup de logica de business a aplicaiei
Component responsabil cu pstrarea datelor
Componenta de comunicaie cu exteriorul poate fi reprezentat n funcie de tipul
aplicaiei de pagini web, interfee grafice desktop .a. Prin intermediul acesteia utilizatorul
introduce date n sistem sau preia date din sistem.
Componenta responsabil cu prelucrarea informaiilor provenite de la utilizator sau a
informaiilor ce i vor fi returnate acestuia este componenta de logic de business i reprezint
partea central a aplicaiei. Toate datele care circul prin sistem sunt ntotdeauna filtrate de
aceast component.
Componenta responsabil de pstrarea informaiilor n sistem este reprezentat de un
sistem de management al bazelor de date. Aceasta permite salvarea unei cantiti mari de date,
preluarea datelor , actualizarea sau tergerea acestora.
O astfel de arhitectur am folosit i n dezvoltarea i testarea proiectului de fa. n
cazul acestui proiect am considerat pentru componenta de baze de date cele mai utilizate dou
sisteme de management ale bazelor de date,PostgreSQL i Microsoft SQL Server.
Componenta care se ocup de comunicaia cu exteriorul este reprezentat aici de o
aplicaie grafic n care utlizatorul interacioneaz cu restul aplicaiei prin intermediul unor
formulare. Totui, aceast component poate fi reprezentat la fel de bine de orice alt aplicaie
ce folosete o conexiune la baza de date.
Componenta de logic de business este reprezentat aici de ORM. Sistemul ORM
funcioneaz ca o legtur ntre aplicaie i baza de date. Prin intermediul lui se preiau datele de
la aplicaia grafic, pe care mai apoi le folosim pentru a accesa baza de date.Totodat el permite
salvarea informaiilor introduse prin aplicaie n baza de date sau poate extrage informaii din
baz n funcie de aciunile fcute de utilizator. Dup preluarea datelor, ORMul, le prelucreaz
i le face disponibile pentru aplicaie.
n imaginea de urmtoare am ilustrat arhitectura unui sistem complet din viaa real
22

Sistem Object-Relational
Mapping

Baz de date

(Insert, Update, Delete,


Read, Mapare tabele)

(PostgreSQL,
Microsoft Server
SQL, etc.)

Aplicaie , Interfa cu
utilizatorul

n care se folosete un ORM.

Fig. 4.1. - Arhitectura unei aplicaii complete ce folosete un ORM

Strucura proiectului
Codul proiectului este organizat pe pachete n funcie de funcionalitile pe care le
ofer.

23

Fig. 4.2. - Organizarea intern a proiectului

Pachetul org.licenta.miniorm.connection se ocup de realizarea legturii cu baza de


date. Acest pachet conine 3 fiiere:

connection_data.properties - conine informaiile necesare unei conexiuni cu baza de


date, nume baz, driver-ul pentru baza respectiv, nume utilizator i parola acestuia
pentru conectare

DataConn.java se ocup de parsarea elementelor din fiierul properties

ConnectionDB.java se ocup de preluarea informaiilor parsate de DataConn i


stabilirea conexiunii cu baza

Pachetul org.licenta.miniorm.queryactions conine clasa QueryActions.java care se


ocup de implementarea operaiilor SELECT, UPDATE,DELETE, INSERT pe baza de date
dar cu ajutorul jdbc-ului.
Pachetul org.licena.miniorm.annotations se ocup de crearea tipurilor de adnotri.
Acesta conine:

Table.java definete structura adnotrii pentru maparea obiectului pe tabel;

PK.java definete structura adnotrii pentru maparea id-ului obiectului pe cheia


primar din tabelul asociat, specificat de adnotarea anterioar;

Column.java definete structura adnotrii pentru maparea unei coloane oarecare pe


un cmp al tabelului asociat din baz;

NotPersistent.java definete structura adnotrii care se asigur c un cmp nu va fi


mapat pe o coloan din baz;

NotNull.java definete structura adnotrii care se asigur c o proprietate din obiect


nu poate fi nul.

Pachetul org.licenta.miniorm.ormhandler conine clasa OrmHandler.java care


implementeaz metodele read, readAll, delete, save utiliznd metodele create n clasa
QueryActions.java i parsnd obiectul pentru obinerea adnotrilor.
24

Acest pachet mpreun cu pachetul de queryactions reprezint centrul propriu zis aplicaiei
i ocupndu-se de ceea ce nseamn un orm.
Pachetul org.licenta.aplicatie.model conine clasele model folosite pentru testarea ormului dezvoltat:

Medic.java este o clas model ce conine cmpurile:


a) idMedic este de tip Long i prezint adnotarea PK
b) idCategorie este de tip Long i prezint adnotarea Column; el face
legtura cu obiectul Categorie
c) numeMedic este de tip String i prezint adnotarea Column

d) codIdentificare este de tip String i prezint adnotarea Column


Categorie Medic.java este o clas model pentru categoriile de medicin existent i
conine cmpurile:
a) idCategorie este de tip Long i prezint adnotarea PK
b) denumireCategorie este de tip String i prezint adnotarea Column

Reteta.java este o clas model ce descrie cmpurile unei reete medicale:


a) idReteta este de tip Long i prezint adnotarea PK
b) idMedic este de tip Long i prezint adnotarea Column; el face legtura
cu obiectul Medic
c) numePacient este de tip String i prezint adnotarea Column
d) nrStrada este de tip Long i prezint adnotarea Column
e) cmpurile varsta (de tip int), sex(de tip String), cetatenie(de tip String),
judet(de tip String), oras(de tip String), strada(de tip String), diagnostic(de
tip String), medicamente(de tip String), compensata(de tip Boolean),
data(de tip Date) nu prezint nici o adnotare Column, iar numele cmpului
din baza va fi automat acelai cu numele proprietii din obiect

RetetaAnimal.java este o clas model ce descrie cmpurile unei reete prescrise de


medicul veterinar:
a) idRetetaAnimal este de tip Long i prezint adnotarea PK
b) idMedic este de tip Long i prezint adnotarea Column; el face legtura
cu obiectul Medic
c) numePosesor este de tip String i prezint adnotarea Column
d) nrTelefon este de tip String i prezint adnotarea Column
e) tipAnimal este de tip String i prezint adnotarea Column
f) varstaAnimal este de tip int i prezint adnotarea Column
25

g) cmpurile tratament(de tip String), diagnostic(de tip String), comentariu(de


tip String), data(de tip Date) nu au adnotare, numele cmpului din tabel
fiind acelai cu numele proprietii din obiect

FormularMedicinaNaturista.java este o clas model ce descrie un formular pe care ar


putea s l elibereze medicul naturist i care conine cmpurile:
a) idFormular este de tip Long i prezint adnotarea PK
b) idMedic este de tip Long i prezint adnotarea Column; el face legtura
cu obiectul Medic
c) numePacient este de tip String i prezint adnotarea Column
d) problemeAnterioare este de tip String i prezint adnotarea Column
e) cmpurile varsta(de tip int), diagnostic(de tip String), remediu(de tip
String) ,data(de tip Date) nu au o adnotare, numele cmpului asociat din
tabel fiind acelai cu numele proprietii

Programare.java este o clas model ce descrie cmpurile unui formular de realizare a


unei programri la medic i conine cmpurile:
a) idProgramare este de tip Long i prezint adnotarea PK
b) numeMedic este de tip String i prezint adnotarea Column; el face
legtura cu obiectul Medic
c) numePacient este de tip String i prezint adnotarea Column
d) dataProgramare este de tip Date i prezint adnotarea Column
e) oraProgramare este de tip int i prezint adnotarea Column

Pentru a ne folosi de aceste obiecte i a le pune la lucru am creat pachetele


org.licenta.aplicatie.medic, org.licenta.aplicatie.farmacist, org.licenta.aplicatie.pacient care fac
apel la aceste modele prin intermediul cmpurilor din interfeele grafice.
Pentru lansarea proiectului este suficient rularea clasei Proiect.java din pachetul
org.licenta.proiect care apeleaz prin elementele de interfa clasele corespunztoare celor trei
pachete descrise anterior.

Funcionalitile sistemului i tratarea problemelor


Prima i una din cele mai importante caracteristici ale sistemului ORM trebuie s fie
independena fa de baza de date. Programatorul trebuie s poat s foloseasc ORM-ul n
acelai mod indiferent de sistemul de management al bazei de date folosit. Pentru realizarea
acestui lucru am ales s folosesc un fiier de configurare n care programatorul introduce datele
de logare n acelai mod indiferent de sistemul de management al bazei de date folosit. Datele
ce trebuie introduse n fiier sunt:numele driver-ului, url-ul bazei de date, numele bazei de date,
numele de utilizator i parola. n continuare vei vedea cum trebuie s arate coninutul unui
astfel de fiier.
26

1.
2.
3.
4.
5.

driver = org.postgresql.Driver
url = jdbc:postgresql://localhost:5432/
databaseName = aplicatie
userName = alin
userPassword = iomanigar

Secvena 4.1.- Date pentru conexiunea la baz

Dup introducerea datelor acestea vor fi preluate i folosite pentru formarea


parametrilor necesari conectrii. Formarea parametrilor este o parte foarte important deoarece
acetia nu sunt la fel pentru toate sistemele de management ale bazelor de date relaionale.
Formarea acestora difer n special pentru Microsoft SQL Server.

1. try {
2.
3.

4.
5.
6.
7.
8.
9.
10.
11.
12.
13.

if
(driverName.equals("com.microsoft.sqlserver.jdbc.SQLServerD
river")){
String con
=url+";databaseName="+databaseName+";user="+usrName+
";password="+usrPass;
connection = DriverManager.getConnection(con);
} else {
connection =
DriverManager.getConnection(url+databaseName,usrName,
usrPass);
}
} catch (SQLException e) {
System.out.println("Conectarea nu a reusit!");
}

Secvena 4.2. Formarea parametrilor i stabilirea conexiunii Dup cum se

poate observa n cazul Microsoft conectarea se face folosind un singur parametru ce conine
toate datele de logare pe cnd la restul SGBD-urilor conectarea se face folosind trei parametri.
n cazul n care conexiunea nu s-a fcut cu succes se va primi un mesaj corespunztor. O alt
parte important sistemului este implementarea celor patru operaii: read(object),
readAll(bbject), delete(object), save(object).
Metoda read(Object) trebuie s citeasc toate cmpurile obiectului specificat din care
iniial se cunoate doar id-ul. Aceast metod, pe lng studierea clasei cu ajutorul API-ului de
Reflection, se folosete de metoda read(Long) din clasa QueryActions ce returneaz un
HashMap(conine nregistrari de forma cheie=valoare) n care cheia este numele coloanei din
tabel i valoarea este valoarea ce o are nregistrarea cutat n tabel. Pentru implementarea
acestei metode am folosit API-ul de JDBC.
Clasa QueryActions are ca i cmp o variabila de tip String creia i se asigneaz o
valoare la instanierea unui obiect de tip QueryActions prin constructor.
Pentru maparea clasei pe tabel am folosit o adnotare denumit @Table. Aceasta
primete ca parametru un String ce reprezint numele tabelului. O parte foarte important a
27

implementrii este reprezentat de studierea adnotrilor. n rndurile urmtoare voi exemplifica


i explica modul de studiu al adnotrilor.

1. public <T> String getTableName(T object) { 2.


3.
4.
5.
6.

Class objectClass = object.getClass();


Annotation annotation =objectClass.getAnnotation(Table.class);
Table table = (Table) annotation;
String tableName = table.name();

7.
8.
9.

return tableName;
}

Secvena 4.3. Extragerea unei adnotri prezent pe clas i studierea parametrului acesteia

n liniile de cod de mai sus se afl o metod ce studiaz dac asupra clasei se afla
adnotri. La linia patru se poate observa c se extrag doar adnotrile de tip Table iar la linia ase
se extrage numele tabelului ce va fi folosit mai departe.
O alt metod folosit n metoda read este metoda getId. Aceasta extrage pe baza
adnotrii @PK id-ul obiectului. Adnotarea @PK este folosit pentru a mapa cheia un cmp din
clas pe cheia primar din tabel. n rndurile urmtoare se poate vedea modalitatea de extragere
a valorii id-ului.

1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.

if (annot instanceof PK
&& field.getType().getSimpleName().equals("Long"))
{
try {
id = (Long) field.get(object);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
return id;

Secvena 4.4. Extragerea valorii id-ului

n liniile de mai sus se verific dou condiii necesare pentru a stabili dac un cmp
este mapat corect pe cheia primar din tabel i anume s dispun de o adnotare de tip @PK si
s fie de tipul Long. Verificarea tipului este necesar deoarece tabele pot ajunge la dimensiuni
foarte mari, iar tipul Long ofer o gam de valori suficient de mare pentru a permite un numr
mare de nregistrri.
n metoda read(object) primi pai sunt reprezentai de folosirea celor dou metode mai
sus menionate pentru a afla numele tabelului pe care este mapat clasa i id-ul obiectului.
Numele tabelului va fi folosit pentru a instania un obiect de tip QueryActions iar id-ul pentru
28

a extrage din baza de date nregistrarea cu id-ul dat ca parametru. Asignarea de valori cmpurilor
obiectului se face pe baza cheii din HashMap-ul rezultat n urma aplicrii metodei read(Long).
Maparea Cmpurilor din obiect pe coloanele tabelului se face cu ajutorul adnotrii
@Column ce primete ca parametru numele coloanei.Maparea se poate face i pe baza numelui
cmpului dac numele acestuia este acelai cu numele coloanei din baza de date. Mai jos putei
vedea liniile de cod prin care se face maparea efectiv.

1.2.

if ( annots. length

3.4.
5.6.
Column ) {

== 0) colName = field.getName();{

} else {
for

(Annotaif (a tion a : annots) {instanceof

7.8.
9.
10.

Column col = (Column) a;


colName = col.name();
} else if (!( a instanceof
NotPersistent)) {

11.
12.
13.
14.
15.

colName = field.getName();
}
}
}

Secvena 4.5. Studul adnotrii Column pentru maparea unui cmp

Variabila annots din codul de mai sus reprezint vectorul ce conine adnotrile unui
cmp.
Adnotarea @NotPersistent ce apare n cod este folosit pentru cmpurile ce nu vor fi
folosite pentru persistena n baza de date.
Urmtoarea metod implementat este readAll(object). Spre deosebire de metoda
anterioar, aceasta nu folosete metoda getId deoarece scopul ei este s citeasc toata obiecte
de tipul celui specificat, i nu unul anume. O metod nou folosit in dezvoltarea acesteia este
metoda getColumns din clasa QueryActions.
Metoda getColumns returneaz o list de String-uri ce reprezint numele coloanelor
exact n ordinea n care acestea se gsesc n tabel. Aceast metod este util deoarece pe baza
rezultatului returnat vom putea asigna valori cmpurilor din obiecte indiferent de ordinea n
care acestea sunt declarate. Astfel programatorul nu va fi obligat s tie exact ordinea coloanelor
din baza de date. O alt utilitate a acestei metode este i faptul c putem extrage din lista
rezultat numele coloanei ce conine id-ul, acest lucru fiind necesar deoarece maparea cmpului
pentru id se face doar cu adnotarea @PK, nespecificnd numele coloanei cu id-ul nicieri n
29

clasa noastr. n metoda readAll(object) am folosit aceast metod pentru cea de-a doua
utilitate. Metoda getColumns a fost implementat cu ajutorul JDBC.

1.
2.
3.
4.
5.
6.

try {
Object firstKey = columns.get(0);
field.set(inst, help.get(i).get(firstKey));
} catch (IllegalArgumentException|IllegalAccessException e) {
e.printStackTrace();
}

Secvena 4.6. Obinerea valorii id-ului n codul de mai sus este

exemplificat modalitatea de extragere a coloanei ce conine


id-ul.
Acest metod returneaz o list cu obiectele de tipul celui specificat gsite n baza de
date. Aceste lucru se realizeaz cu ajutorul Reflection folosind metoda newInstance() pus la
dispoiie de API-ul e Reflection. Pentru fiecare HashMap din lista de HashMap-uri returnat de
metoda readAll() din QueryActions se creeaz o noua instan a obiectului specificat.
1.
2.
3.
4.
5.
6.

for (int i = 0; i < help.size(); i++) {


try {
inst = object.getClass().newInstance();
} catch (InstantiationException |
IllegalAccessException e) {
e.printStackTrace();
}

...

Secvena 4.7. Instanierea unui obiect folosint Reflection

n afar de cmpul ce se mapeaz pe coloana ce conine id-ul restul coloanelor se


mapeaz similar cu cele de la metoda read(object).
Cea de-a treia metod este cea care ne ajut la tergerea unui obiect de tipul celui dat
ca parametru din baza de date, i anume metoda delete(object).
n aceast metod am folosit dou metode amintite mai devreme, getId() i
getTableName(), si o a treia metod din clasa QueryActions.Aceast metod din clasa
QueryActions se numete delete i primete ca parametru o variabil de tip Long(delete(Long)).
Avnd n vedere c este o metod de dimensiune mic voi pune mai jos ntreaga metod.
1. public
<T> void delete(T object) {
2.
3.
Long id = getId(object);
4.
5.
String tableName = getTableName(object); 6.
7.
QueryActions action = new QueryActions(tableName);
9.
action.delete(id);
10.
}

Secvena 4.8. Metoda delete(object)

30

Ultima metod ce trebuie implementat este metoda save(object). Aceast metod


trebuie fie s insereze o nou nregistrare n baza de date dac id-ul obiectului dat ca parametru
este null, fie s fac un update asupra obiectului din baza de date dac id-ul este o valoare ce
exist n baza de date.
Aceast metod folosete metoda getId() pentru a afla id-ul obiectului dat ca
parametru, getTableName() pentru a afla numele tabelului n care se va face salvarea,
getColumns din clasa QueryActions. Aici metoda getColumns() este folosit petru a studia
ordinea coloanelor din tabel. i nu n ultimul rnd metoda save(Long, List<Object>) din clasa
QueryActions. Aceast metodat primete ca parametri id-ul nregistrrii i lista de valori pe
care s le insereze sau s le modifice n baza de date.
1.
2.
3.
4.
5.

if (a instanceof Column) {
Column col = (Column) a;
colName = col.name();
pos = coloane.indexOf(colName) - 1;
}

...

Secvena 4.9. Studiul ordinii coloanelor

n liniile de cod de mai sus se afl un exemplu de aflare a poziiei unei coloane n tabel.
Variabila pos reprezint poziia pe care va fi pus valoarea cmpului obiectului n lista de valori
ce va fi trimis ca parametru metodei save din QueryActions. n metoda save(object) formm
din cmpurile obiectului dat ca parametru lista de valori necesar metodei save(Long, List<
Object >).
n rndurile urmtoare voi vorbi despre metoda save(Long, List< Object >) din clasa
QueryActions. n aceast metod se folosesc alte dou metode implementate n aceeai clas:
update(Long, List< Object >) i metoda insert(List< Object >).

1. public void save(Long id, List<Object> valori) {


2.
3.
if (id != null)
4.
update(id, valori);
5.
else
6.
insert(valori);
7.
}

Sevena 4.10. Metoda save(Long, List)

n aceste dou metode partea cea mai dificil i cea mai important a fost formarea
interogrii. O atenie special au necesitat obiectele de tip String i cele de tip Date.
Obiectele de tip String au valori ce sunt ncadrate ntre ghilimele i nu toate sistemele
de gestiune a bazelor de date relaionale accept valori ncadrate ntre ghilimele, ns absolut
toate accept ncadrarea ntre apostrof. n liniile de cod urmtoare se va vedea cum am nlocuit
ghilimelele cu apostrof n cazul metodei update i cum am format interogarea, aceasta trebuind
s se formeze corect indiferent de numrul de elemente ale listei dat ca parametru.

31

1.
2.
3.
4.
5.
6.
7.
8.

if (valori.get(i).getClass().getName().equals("java.lang.String")) {
help += coloane.get(i) + "=" + "\'" + valori.get(i)+ "\', ";
} else if (valori.get(i).getClass().getName().equals("java.util.Date"))
{
java.sql.Date data =
new Date(((java.util.Date)
valori.get(i)).getTime());
help += coloane.get(i) + "=" + "\'" + data + "\', ";
} else {
help += coloane.get(i) + "=" + valori.get(i) + ", ";
}

Secvena 4.11. Tratarea obiectelor de tip String i Date

Dup cum se poate observa obiectele de tip Date trebuie convertite la un alt tip de
obiect Date care s fie compatibil cu cel din baza de date. De asemenea i valorile unor
asemenea obiecte trebuie ncadrate cu apostrof. Diferena la metoda insert era c nu se adaug
iruri de caractere de forma nume_coloan=valoare, ci dup valoare se pune caracterul virgul.
n ambele metode mai trebuie fcut o verificare, i anume dac valoarea se afl pe
ultima poziie n lista de valori, formarea interogrii fiind puin diferit.
1.if(valori.get(i).getClass().getName().equals("java.lang.String"
2.
)){
3.
help += coloane.get(i) +
"=" + "\'" + valori.get(i)
4.
+ "\' WHERE " + idTabel +
"=" + id;
5.
} else if
(valori.get(i).getClass().g
etName()
6.
.equals("java.util.Date")){
7.
java.sql.Date data = new
8.
Date(((java.util.Date)valor
i.get(i)).getTime());
9.
help += coloane.get(i) +
"=" + "\'" + data + "\'
WHERE "
10.
+ idTabel + "=" +id;
11.
12. }

Secvena 4.12.- Tratarea ultimei poziii la update

1.
2.
3.
4.
5.
6.
7.
8.

if(lista.get(i).getClass().getName().equals("java.lang.String"
)) {
help += "\'" + lista.get(i) + "\') ";
} else if
(lista.get(i).getClass().getName().equals("java.util.Date")) {
java.sql.Date data = new
Date(((java.util.Date)lista.get(i)).getTime());
help += "\'" + data + "\') "; 9. }

32

Secvena 4.13. Tratarea ultimei poziii la insert

Secvenele de cod de mai sus ilustreaz modul n care se formeaz interogarea pentru
ultima valoare din list. Dupa cum se poate observa n prima secven(extras din metoda
update) dup ultima valoare urmeaz caluz WHERE pe cnd n cazul metodei insert , ilustrat
n cea de-a doua secven de cod, dup ultima valoare urmeaz nchiderea unei paranteze.
n cazul metodelor din clasa ORMHandler, i anume read(object), readAll(object),
delete(object), save(object), am implementat astfel nct acestea s accepte orice tip de obiect.
Acest lucru a fost realizat fcnd ca aceste patru metode s fie generice, astfel ele putnd accepta
orice tip de obiect.

public <T> void save(T object)


public <T> List<T> readAll(T object)
public <T> void delete(T object)
public <T> void read(T object)

Secvena 4.14. Metode generice

Aa cum se poate observa n secvena de mai sus la toate cele patru metode este prezent
parametrul care devine tipul obiectului dat ca parametru. Acest lucru face ca metodele s
accepte ca parametru orice tip de obiect. Atunci cnd metodele sunt folosite nu este nevoie de
vreun apel special de metod, se va apela pur i simplu prin numele metodei i i se va da ca
parametru orice tip de obiect se dorete. Mai jos voi ilustra apelul unei astfel de metode.

1.
2.
3.
4.

Serial serial = new Serial();


serial.setId(2L);
ORMHandler h = new ORMHandler();
h.read(serial);

Secvena 4.15. Exemplu de apel metod generic

Dup cum se poate observa faptul c metoda read(object) este una generic nu
complic deloc folosirea ei.
Prima problem ce apare la maparea cheii primare este compatibilitatea numelui
cmpului sau cum putem indica ct mai simplu faptul c un cmp este corespondentul cheii
primare din tabel. n rezolvarea acestei probleme am plecat de la considerentul c pentru un
tabel prima coloan va fi tot timpul reprezentat de cheia primar.
33

1. String helpQuery = "SELECT * FROM " + this.table;


2. try { 3.
4.
Statement helpStmt = connect.createStatement();
5.
ResultSet helpRs = helpStmt.executeQuery(helpQuery);
6.
rsmd = helpRs.getMetaData(); 7. idTabel =
rsmd.getColumnName(1);
8.
9.
} catch (SQLException e) {
10.
e.printStackTrace();
11.
System.out.println("Probleme la metadata!");
12.
}

Secvena 4.16. Extragerea numelui coloanei cu id-ul

Mai sus se afl una din secvenele de cod ce rezolv aceast problem. Executarea
interogrii din prima linie duce la reinerea tuturor datelor despre tabel n variabila helpRs.
Extragerea metadatelor se face cu metoda getMetaData(). Metadatele reprezint numele
coloanelor, tipurile acestora, numrul coloanelor etc. Metoda getColumnName(1) returneaz
numele primei coloane din tabel, adic cea care conine cheia primar. Menionez c metoda
getMetaData returnez coloanele exact n ordinea n care ele se gesc n tabel.
O alt metod de rezolvare folosit n implementarea sistemului este reinerea tuturor
numelor coloanelor ntr-o list i folosirea primului element din list atunci cnd avem nevoie
de coloana pentru cheia primar. Acest lucru se realizeaza cu ajutorul metodei getColumns din
clasa QueryActions.
1.
2.

try {
for (int i = 1; i <
rsmd.getColumnCount() + 1; i++)
3.
rez.add(rsmd.getColumnName(i));
4.} catch (SQLException e) {
5.
e.printStackTrace();
6.
}

Secvena 4.17. Formarea listei cu numele coloanelor

Adugarea acestei secvene de cod la secvena de mai devreme duce la formarea unei
liste cu numele coloanelor.
Un exemplu de folosire a celei de-a doua metode poate fi observat n metoa readAll.
Mai jos se afl secvena de cod ce ilustreaza folosirea celei de-a doua metode.

1.
2.
3.

4.
5.
6.
7.
8.

try {
Object firstKey = columns.get(0);
field.set(inst, help.get(i).get(firstKey)
} catch (IllegalArgumentException|
IllegalAccessException e) {
e.printStackTrace()
}
}

34

Secvena 4.18. Exemplu de utilizare list de nume coloane n liniile de

cod de mai sus columns reprezint lista cu numele coloanelor dintr-un tabel. Numele primei
coloane este extras i este folosit pentru a se extrage valoarea cheii primare dintr-un HashMap
ce conine nregistrri de tip cheie=valoare, cheia fiind numele coloanei.
Cea de-a doua problem la maparea cheii primare este generarea id-ului. Aceast
problem a fost rezolvat innd cont doar de valoarea maxim a id-ului la un moment de timp.
Nu s-a inut cont de valoarea id-ului din sesiunile anterioare.

12. Long idRow = 0L;. String helpQuery =


3.4.

"SELECT * FROM " + this.table;

try Statement helpStmt = connect.createStatement();{

5.6.
resultSet = helpStmt.executeQuery(helpQuery);while
(resultSet.next()) {
7.8.
idRow)
9.
10.
12.
13.
14.
15.
16.

Long idRow1 = resultSet.getLif (idRow1 >


ong(1);
idRow = idRow1;
}
} catch (SQLException e) {
e.printStackTrace();
System.out.println("Probleme la metadata!");
}
idRow++;

Secvena 4.19. Generarea id-ului

n liniile de mai sus se poate observa c este extras valoarea maxim a cheii primare
din tabel. La final valoarea maxim este incrementat, astfel asigurnd unicitatea cheii primare.
Dac n tabel nu exist nregistrri nu reprezint o problema deoarece valoarea este iniializat
cu 0 i este incrementat oricum la final, fie c a gsit valori sau nu n tabel.
Rezolvarea celei de-a doua probleme a fost mai facil deoarece pentru maparea oricrui
tip de dat ce conine caractere am folosit direct clasa String. n Hibernate atunci cnd se preiau
date din baza de date sunt salvate ntr-un array ce conine date de tip char. Apoi fcndu-se castul la String dac este nevoie. De asemenea atunci cnd se salveaz un ir de caractere n baza
de date acestea sunt convertite n array de char-uri si pentru acest lucru este nevoia de
specificarea lungimii dac acesta depete 255.
O alt parte a acestei lucrri ce a rmas neatins sunt adnotrile. Acestea reprezint
metadate ce pot fi adugate claselor, pachetelor, cmpurilor. Sunt caraterizate de prezena
caracterului @ la nceput. Spre deosebire de comentarii ele sunt recunoscute de compilator i
35

apar ca elemente i in API-ul de Reflection. Aici am folosit adnotri pentru maparea claselor i
cmpurilor pe tabele i coloane. Ele pot conine parametrii care de asemenea sunt cunoscui i
pot fi utilizai n cercetarea claselor i a cmpurilor. Pentru mapare am folosit urmtoarele
adnotri:
a) @Table aceasta poate primete ca parametru numele tabelului e care
se mapeaz
clasa. Implementarea adnotrii poate fi observat ma jos.

@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
String name();
}

Secvena 4.20. Adnotarea Table

Adnotarea @Retention este folosit pentru a specifica momentul cnd s fie luat n
considerare adnotarea. Pentru toate adnotrile implementate am ales s fie active la rulare
@PK am folosit-o pentru a mapa cheia primar

b)

@Retention(RetentionPolicy.RUN
TIME)
public @interface PK {
}

Secvena 4.21. Adnotarea PK Aceast

adnotare nu primete nici un parametru.


c) Adnotarea @Column folosit pentru a mapa orice cmp pe o coloan
n cazul n
care numele coloanei i cel al cmpului nu coincid.
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
String name();
String type() default "";
int length() default 100;
}

Secvena 4.22. Adnotarea Column

Primete ca parametru numele coloanei pe care se mapeaz i opional tipul de date i


lungimea. Al doilea parametru i al treilea pot fi folosii mai mult n cazul n care ORM-ul
creeaz i tabele i trebuie specificate tipurile coloanelor i lungimea dac este vorba de date de
tip VARCHAR.
36

d) Adnotarea @NotPersistent este folosit pentru a marca faptul c un


cmp nu se persist n baz, astfel c el nu va fi luat n considerare la operaiile
sistemului cu baza de date.
@Retention(RetentionPolicy.RUNTIME) public @interface
NotPersistent {
}

Secvena 4.23. Adnotarea NotPersistent

e) Adnotarea @NotNull folosit n eventualitatea n care ORM-ul va


genera i tabele pentru a specifica la crearea tabelului c o coloan nu poate lua valori
nule.
@Retention(RetentionPolicy.RUNTIME)
public @interface NotNull {
}

Secvena 4.24. Adnotarea NotNull

f) Adnotarea @FK folosit la la crearea de tabele pentru a mapa cheia


extern din tabel. Primete ca parametru numele tabelului de care se leag tabelul
mapat de clasa n care se afl cmpul cu adnotarea @FK.
@Retention(RetentionPolicy.RUNTIME)
public @interface FK {
String name();
}

Secvena 4.25. Adnotarea FK

37

Concluzii
Un ORM este o soluie viabil pentru programatori atunci cnd doresc s mbine
programarea orientat-obiect cu lucrul cu baze date deoarece este un sistem scalabil, rapid i
uor de folosit.
Un astfel de sistem poate duce la creare de aplicaii stabile ntr-un timp mult mai scurt.
De asemenea duce la scrierea unui cod uor de ntreinut i depanat deoarece reduce cantitatea
de cod i este i uor de neles.
Cea mai bun metod de mapare a obiectelor pe tabele este folosirea adnotrilor
deoarece este o metod mai intuitiv i care nu necesit crearea unor fiiere de configurare mari
i greu de urmrit.
Pentru dezvoltarea unui sistem de mapare a obiectelor pe tabelele dintr-o baz de date
este necesar folosirea att a API-ului de JDBC ct i a API-ului de Reflection.
Acest ORM ncearc s trateze unele probleme a cror rezolvare ar duce la o utilizare
mai uoar i la o funcionare mai aproape de ceea ce se ateapt un programator.
Un astfel de sistem poate fi folosit la implementarea modelului i chiar a unei pri din
controller din pattern-ul de proiectare MVC(Model-View-Controller), care este una din cele
mai utilizate metode la dezvoltarea aplicaiilor att desktop ct i web.

Bibliografie
[1] Tanasa Stefan, Andrei Stefan, Olaru Cristian, 2007. Java de la 0 la
Expert Ediia a II-a revizuit. POLIROM, Iai
[2] Roland Barcia, Geoffrey Hambrick, Kyle Brown, Robert Peterson,
Kulvir Singh
Bhoga. 2008. Persistence in the Enterprise: A Guide to Persistence Technologies. IBM
Press, Boston
[3]Jakob Jenkov. Java Reflection Tutorial. http://tutorials.jenkov.com/javareflection/index.html, accesat la data de 13.06.2013
[4]Jakob
Jenkov.
Java PDF Generation
with
http://tutorials.jenkov.com/java-itext/index.html, accesat la data de 23.06.2013

IText.

[5]Lars Vogel. 2010. Creating PDF with Java and iText - Tutorial.
http://www.vogella.com/articles/JavaPDF/article.html, accesat la date de 23.06.2013
[6]Oracle
Java SE
Documentation,
Annotations.
http://docs.oracle.com/javase/6/docs/technotes/guides/language/annotations.html, accesat la
data de 28.05.2013
38

[8]Hibernate Documentation.
2013 Hibernate
Developer
Guide.
http://docs.jboss.org/hibernate/orm/4.3/devguide/en-US/html/, accesat la data de 30.05.2013
[9] Bitcell. 2009. Tutoriale Java. http://www.bitcell.info/tutorial-java-introduceredespre-platforma-t674.html, accesat a data de 29.06.2013
[10]Eclipse. 2013. SWT
The Standard
http://www.eclipse.org/swt/, accesat la data de 20.06.2013

Widget

Toolkit.

[11] Oracle FAQs. 2013. JDBC. http://www.orafaq.com/wiki/JDBC, accesat la


data de 10.06.2013
[12]Wikipedia.
2013.
Object-relational
mapping.
https://en.wikipedia.org/wiki/Object-relational_mapping, accesat la data de 26.06.2013
[13]Tutorial Debug n
mediul
de
dezvoltare
Eclipse,
2007,
http://eclipsetutorial.sourceforge.net/debugger01/lesson01.html, accesat la data de 6.06.2013
[14] Documentaie Oracle Interface
ResultSetMetadata,
http://docs.oracle.com/javase/1.5.0/docs/api/java/sql/ResultSetMetaData.html, accesat la data
de 8.06.2013
[15] Historical perspective of ORM, Kenneth Downs,2010,
http://databaseprogrammer.blogspot.ro/2010/12/historical-perspective-of-orm-and.html ,
accesat la data de 23.06.2013
[15] O-R Mapping,
http://encyclopedia2.thefreedictionary.com/Objectrelational+mapping, accesat la data
de 23.06.2013
[16] Wikipedia, 2013,
PostgreSQL, http://ro.wikipedia.org/wiki/PostgreSQL,
accesat la data de 24.03.2013
[17] Top 5
best databases,
Ramesh
Natarajan,
2010,
http://www.thegeekstuff.com/2010/03/top-5-best-databases/ , accesat la data de 2.06.2013

39

You might also like