Sala de Lectura Online
Salã de lecturã online
CUPRINS
Lucrare de licențã
2013
1. INTRODUCERE
1.1 DESCRIEREA TEMEI
În trecut, oamenii care erau preocupați de dezvoltarea cunoștințelor generale petreceau majoritatea timpului lor în sãli de lecturã sau împrumutau cãrți și le citeau pânã noaptea târziu la lumina lãmpii. Deoarece nu existau atât de multe activitãți pe care aceștia le puteau desfãșura, cititul era una dintre principalele preocupãri ale tinerilor din vremea respectivã.
Din necesitatea de a pãstra documente importante în siguranțã, ideea de carte electronicã și-a facut apariția încã din anul 1940, când doi preoți italieni Thomas Aquinas și Roberto Busa au creat un sistem electronic de indexare a documentelor. Peste doar nouã ani, o profesoarã din Spania a patentat prima carte electronicã. Intenția acesteia a fost de a reduce numãrul elevilor care renunțã la școalã.
Ideea de cãrți în format electronic a continuat sã se dezvolte, ajungând ca acestea sã fie atât de utilizate în ziua de astãzi încât le pot fi comandate online sau pot fi descãrcate de pe internet .
Aflați în era tehnologiei și a informatizãrii, majoritatea studenților, și nu numai, încearcã sã își obținã cursurile și cãrțile necesare învãțãrii în format electronic, pentru a nu pierde timpul în sãlile de lecturã sau pentru a nu împrumuta cãrți care se dovedesc a nu fi de folos deoarece nu conțin informațiile cãutate.
Deși, în general, majoritatea cãrților se gãsesc în format electronic, problema principalã este legatã de alegerea cãrții potrivită cu necesitãțile.
În majoritatea cazurilor, pentru a gãsi cartea potrivitã studenții folosesc ca punct de reper titlul acesteia. Dacã titlul este sugestiv, atunci cartea este cea cãutatã; acest lucru nu este adevãrat întotdeauna, majoritatea studenților alegând o sursã comunã de informare deoarece nu au la îndemanã o metodã de a analiza conținutul cãrților, precum și un depozit al tuturor cãrților necesare domeniului universitar.
Primul argument în situația prezentatã mai sus ar fi cã existã bibliotecã și salã de lecturã a universitãții, dar lipsa de timp și comoditatea studenților nu-i îndeamnã sã își petreacã timpul în aceste locuri pentru a obține informațiile necesare.
1
Lucrare de licențã
2013
Ideea de a realiza aceastã aplicație a venit din nevoia personalã a unui sistem de cãutare avansatã în conținutul cãrților, deoarece mi s-a întamplat de nenumãrate ori sã pierd ore în șir printre rafturile bibliotecii fãrã a obține ceea ce cãutam de fapt. Ajungeam de cele mai multe ori sã mã întorc acasã cu diferite cãrți interesante, dar care nu aveau legãturã cu ceea ce aveam eu nevoie sau în cel mai rãu caz mã întorceam cu un braț de cãrți al cãror titlu îmi dãdea impresia cã aceste cãrți sunt ceea ce am nevoie; bineînțeles cã adormeam rãsfoindu-le
și gãseam soluția undeva pe internet, dar era soluția gãsitã de 90% dintre noi, deoarece împãrțim același internet.
Aceastã aplicație vine în sprijinul tuturor studenților care au nevoie de a obține informații din cãrți pe baza unor criterii mai avansate decât titlul sau autorul; bineînțeles cã se pot efectua și cãutãri dupã aceste criterii, dar principala caracteristicã este posibilitatea de cãutare în conținutul documentelor a unor cuvinte sau chiar fraze.
1.2 ORGANIZAREA LUCR ÃRII
Aplicația este structuratã în patru capitole plus o anexã, care vor fi prezentate succint în cele ce urmeazã.
Capitolul 2 prezintã o serie de tehnologii și aspecte teoretice care m-au ajutat în dezvoltarea aplicației. Capitolul cuprinde descrierea unor medii de lucru și unelte utilizate în implementarea unor aplicații de tip enterprise precum și a unor concepte noi apãrute privind stocarea și interogarea documentelor, precum Apache Solr și MongoDB. Baze de date NoSQL, indexare și GridFS sunt unele dintre cuvintele cheie ale acestei aplicații.
Capitolul 3 surprinde pașii parcurși pentru structurarea și implementarea soluției. În prima parte a capitolulu este descrisã specificația aplicației împreunã cu diagramele use-case, urmate de prezentarea mediului de lucru și a structurii și modului de funcționare al bazei de date. Nu în ultimul rând sunt descrise arhitectura aplicației și componentele acesteia.
Capitolul 4 este un ghid de utilizare a aplicației, descris atât din punct de vedere al unui administrator cât și al unui student.
Capitolul 5 indicã succint câteva posibilitãți de dezvoltare și îmbunãtãțire a funcționalitãților soluției propuse.
Anexa adãugatã în finalul lucrãrii este un ghid de instalare a serviciului MongoDB sub
Microsoft Windows 7.
2
Lucrare de licențã
2013
2. CONCEPTE TEORETICE Ș I PREZENTAREA GENERA LÃ A
TEHNOLOGIILOR FOLOSI TE
JAVA
SCURT ISTORIC
Limbajul Java a fost conceput în iunie 1991 de cãtre James Gosling în colaborare cu Mike Sheridan și Patrick Naughton(numiți "The Green Team"), sub denumirea de Oak(Stejar). Ulterior din Oak a devenit Green(Verde) și apoi Java, dupã denumirea producãtorului de cafea(Java Coffee), consumatã frecvent de programatorii amintiți.
În 1995, Sun Microsystems, lanseazã prima versiune publicã: Java 1.0. Principalul atuu a fost "Write Once, Run Anywhere"(WORA, "Scrie o datã, Ruleazã Oriunde"), și faptul cã era distribuitã gratuit.
În octombrie 2006, Sun Microsystem declarã open-source, o mare parte din Java, sub licența GNU General Public Licence(GPL), iar în mai 2007, nucleul ce constituie Java este declarat open-source.
Între anii 2009-2010, Sun Microsystem este cumparatã de Oracle, și la aproximativ un an distanțã, iulie 2011, apare ultima variantã de Java și anume Java7, la o diferențã de
5 ani de la lansarea Java 6.
2.1.2 OBIECTIVE PRIMARE
Chiar dacã acest limbaj a trecut prin numeroase schimbãri, cele cinci principii de bazã au rãmas aceleași, timpul și gradul de utilizare al limbajului dovedindu-le încã o datã veridicitatea. Aceste principii afirmã cã Java:
Ar trebui sã fie un limbaj: simplu, obiect-orientat(OO), familiar(similar cu C,C++)
Ar trebui sã fie: robust și sigur
Ar trebui sã fie: neutru, în ceea ce privește arhitectura(programului)
și portabil
Ar trebui sã fie: de înaltã performanțã
3
Lucrare de licențã
2013
Ar trebui sã fie: interpretabil(de orice sistem), sã poata rula mai multe fire de execuție și sã fie dinamic.
2.1.3 IMPLEMENTÃRI
Oracle Corporation este proprietarul actual al implementãrii platformei Java Standard Edition, achiziționatã de ka Sun Microsystem proprietarul actual al implementãrii platformei Java Standard Edition, achiziționatã de ka Sun Microsystem în ianuarie
2012.
Implementarea Oracle este împãrțitã în douã distribuții diferite: Java Runtime Environment (JRE), care conține acea parte din platforma Java SE necesarã pentru a rula programe Java și Java Development Kit (JDK), necesar pentru dezvoltatorii de soft, include Java Compiler, Javadoc, Jar și un debugger.
2.1.4 PERFORMANȚÃ
Programele scrise în Java au o reputație pentru faptul cã se mișcã încet și necesitã multã memorie decât cele scrise în C++. Totuși viteza de execuție a programelor Java s-a îmbunãtãțit semnificativ odatã cu introducerea compilãrii “just-in-time”, în anii
1997/1998.
2.1.5 MANAGEMENTUL AUTOMAT AL MEMORIEI
Java folosește un colector automat de “resturi” (garbage collector), pentru a administra memoria în ciclul de viațã al unui obiect. Programatorii determinã cand obiectul este creat, iar garbage collector-ul este responsabil de recuperarea memoriei odatã ce obiectul nu mai este folosit. Odatã ce nu mai existã referințã cãtre un obiect, memoria inaccesibilã devine eligibilã pentru a fi eliberatã de garbage collector. Pot apãrea situații similare cu un memory leak, dacã se pãstreazã în cod referințe la un obiect care nu mai este folosit.
2.1.6 SINTAXÃ
Sintaxa Java este în mare mãsurã derivatã din C++. Spre deosebire de C++, care combinã sintaxa pentru programare obiect-orientatã, structuratã și genericã, Java a fost construit aproape în totalitate ca un limbaj obiect-orientat. Tot codul este scris în
4
Lucrare de licențã
2013
interiorul claseor și orice este un obiect, cu excepția tipurilor de date primitive, care nu sunt clase din motive de performanțã.
Comparativ cu C++, Java nu suportã supraîncãrcarea operatorilor și moștenirea multiplã a claselor. Acest lucru simplificã limbajul și ajutã la prevenirea unor potențiale erori și a unui design anti-șabloane.
2.1.7 CONCLUZIE
Java are avantaje semnificative, nu doar ca limbaj comercial ci ca și limbaj de învãțare. Permite învãțarea unui limbaj de programare obiect-orientat fãrã a expune complexitatea de care dã dovadã C++.
2.2 BAZE DE DATE NOSQL
2.2.1 INTRODUCERE
Carlo Strozzi a folosit prima oarã termenul NoSQL in 1998 pentru a-și numi baza de date relaționalã și open-source, ce nu prezenta standardele interfeței SQL. Strozzi a sugerat cã mișcarea NoSQL ce presupune îndepãrtarea de modelul relațional, ar trebui sã fie numitã corespunzator, și anume:”NoREL”
Eric Evans a reintrodus termenul NoSQL la începutul anului 2009, când Johan Oskarsson a dorit sa organizeze o întâlnire pe tema bazelor de date distribuite open-source. Prin intermediul acestui nume, Evans a încercat sã eticheteze creșterea numãrului de baze de date ce nu oferã garanții ACID (Atomicitate, Consistențã,
Izolare si Durabilitate).
NoSQL este un sistem de management a bazelor de date; rapid, portabil si fãrã limite arbitrare altele decât memoria și viteza procesorului.
O bazã de date NoSQL prevede un mecanism de stocare și recuperare a datelor ce folosește un model de consistențã mai puțin restrictiv decât cel întalnit la bazele de date relaționale, cu scopul de a obține scalare orizontală și disponibilitate mai mare.
În esențã, sistemele de baze de date NoSQL sunt necesare atunci când lucrãm cu cantitãți uriașe de date (în special big data) deoarece natura datelor nu necesitã un model relațional. Datele pot fi întotdeauna structurate dupã anumite criterii, dar
5
Lucrare de licențã
2013
NoSQL se folosește atunci când este cu adevãrat importantã capabilitatea de a stoca și prelua cantitãți mari de date ,în detrimentul pãstrãrii unei relații între elemente.
Un astfel de sistem poate stoca milioane de perechi cheie-valoare într-un tablou asociativ sau poate stoca milioane de înregistrãri între care nu existã nici o legaturã . O astfel de situație de utilizare a bazelor de date NoSQL este folositã de Twitter pentru a stoca postãrile sau de serverele de Internet pentru a salva jurnalele de server (server logs).
Un alt argument important pentru a folosi o bazã de date NoSQL este dat de flexibilitatea modelului de date; iar instrumente cum ar fi CRM (Customer Relationship Management – Managementul Relațiilor cu clienții), ERP(Enterprise resource planning- Planificarea resurselor înreprinderii), BPM(Business process management –Managementul proceselor de afaceri), etc. ar putea folosi aceastã flexibilitate pentru a-și stoca datele fãrã a efectua modificãri pe tabele și fãrã a crea coloane suplimentare în baza de date. Acest tip de baze de date sunt de asemenea de mare ajutor pentru a crea prototipuri sau aplicatii rapide, deoarece aceastã flexibilitate oferã un instrument pentru a dezvolta noi caracteristici foarte ușor.
Existã un numãr suprinzãtor de sisteme de NoSQL disponibile astãzi. Dintre proiectele open-source amintim: MongoDB, Cassandra, CouchDB, GTM, Chordless, Newo4j.
2.2.2 AVANTAJELE UTILIZÃRII
Scalare „elasticã” : de multã vreme, administratorii de baze de date au mizat pe scalarea verticalã- cumpãrând servere din ce în ce mai mari odatã cu creșterea cantitãții de date stocate- în loc sã scaleze orizontal- distribuind baza de date pe mai multe gazde, pe mãsurã ce cantitatea de date creștea. Bazele da date relaționale nu sunt ușor de scalat orizontal, de aceea bazele de date NoSQL sunt create pentru a se extinde transparent și a accepta noi noduri, de asemenea designul unei astfel de baze de date este ușor de realizat, chiar și în minte.
Big data : volumele de date stocate si tranzacțitranzacționate cresc de la o zi la alta; O‟Reilly numind aceastã situație „revoluția industrialã a datelor”, în situația prezentatã o bazã de date relaționalã nu poate gestiona corespunzãtor datele primite; de aceea bazele de date NoSQL au început sa prindã teren și sã se dezvolte foarte mult. O bazã de date
6
Lucrare de licențã
2013
NoSQL poate pãstra și tranzacționa volume de date ce depãșesc ceea ce poate fi manipulat de cãtre cea mai mare bazã de date relaționalã.
Model de date flexibil : Schimbãrile apãrute in cazul unei scheme pentru o bazã de date relaționalã sunt o mare bãtaie de cap deoarece orice modificare, oricât de micã, trebuie sa fie atent tratatã și este posibil sa necesite închiderea sau restricționarea serviciilor din aplicația pe care o susține. Bazele de date NoSQL au restricții reduse sau inexistente asupra modelelor de date.
2.2.3 PROVOCÃRI
Promisiunile oferite de bazele de date NoSQL au generat mult entuziasm, dar existã multe obstacole ce sunt întampinate in crearea unei astfel de structuri:
Maturitatea: Bazele de date relaționale au rezistat pentru un timp îndelungat, pãstrandu-și principiile stabile, ceea ce nu putem afirma despre bazele de date NoSQL apãrute recent. Aceastã situație trebuie tratatã cu atenție atunci cand se dorește realizarea unei aplicații destinatã afacerilor(enterprise).
Administrare: Acest tip de bazã de date are printre obiective oferirea unei soluții ce nu necesitã existenta unui administrator de baze de date, dar instalarea unei aplicații NoSQL si menținerea ei necesitã suficient de multã experiențã.
Cu toate acestea, bazele de date NoSQL sunt un pas important în evoluția bazelor de date , oferind un adevãrat suport pentru necesitatea sistemelor de gestionare a cantitaților mari de date ce sunt vehiculate.
7
Lucrare de licențã
2013
MONGODB
ISTORIC
Provenind din cuvântul „humongous” ce se traduce „enorm”, MongoDB este un sistem de baze de date document-orientat, dezvoltat și susținut de 10gen.Face parte din familia de sisteme de baze de date NoSQL și folosește ca structurã de stocare a datelor documente JSON(JavaScript Object Notation) cu scheme dinamice (numite de MongoDB documente BSON[ Binary JSON]), fãcand ca integrarea datelor în diferite tipuri de aplicații sã se facã ușor și repede.
10gen a început dezvoltarea acestei aplicații in octombrie 2007,iar în 2009 aplicația a devenit open-source, ajungând astfel cel mai popular sistem de management al bazelor de date NoSQL, fiind folosit de aplicații precum: MTV Networks,Craigslist sau
Foursquare.
2.3.2 CARACTERISTICI PRINCIPALE
1.Interogãri ad-hoc
MongoDB suportã cãutãri dupã câmpuri, dupã interogãri și cãutãri bazate pe expresii regulate.Interogãrile pot returna câmpuri specificate din document sau funcții
JavaScript definite de utilizator.
2.Indexare
Orice câmp dintr-un document MongoDB poate fi indexat( indecșii din MongoDB sunt similari conceptual cu cei din bazele de date relaționale).
3.Replicare
MongoDB suportã replicarea maestru-sclav( master-slave replication). Un maestru poate efectua citiri și scrieri, în vreme ce un sclav copiazã date de la maestru și poate fi folosit doar pentru citiri și backup( nu pentru scriere). Sclavii au abilitatea de a-și alege un nou maestru dacã cel actual a picat.
4.Auto-sharding
8
Lucrare de licențã
2013
MongoDB scaleazã orizontal folosind procedeul de ‚sharding’. Dezvoltatorul unei astfel de aplicații alege o cheie „ciob”(shard), care decide cum vor fi distribuite datele în colecție. Datele sunt împarțite în fragmente ( bazate pe cheia ‚shard‟) și distribuite orizontal pe mai multe ‚shard-uri‟.(Un shard este un maestru cu unul sau mai mulți sclavi). MongoDB poate rula peste mai multe servere, echilibrând încãrcarea și duplicarea datelor pentru a menține sistemul în cazul eșecurilor hardware. Configurãrile automate sunt ușor de desfãșurat și mașini noi pot fi adãugate la o bazã de date ce ruleazã.
5. Stocarea fișierelor
MongoDB poate fi utilizat ca un sistem de fișiere(filesystem). Funcția numitã GridFS este inclusã in driverele MongoDB și este valabilã fãrã probleme în limbajele de dezvoltare( MongoDB suportã o gamã foarte largã de limbaje de dezvoltare). MongoDB expune funcții pentru manipularea fișierelor și a conținutului acestora.
6. Agregarea
Modelul de programare MapReduce poate fi utilizat pentru procesarea datelor si a operațiilor de agregare. Operațiile de agregare se referã la faptul cã utilizatorul poate obține rezultate pentru care într-o bazã de date relaționalã se folosește clauza SQL
GROUP BY.
7. Executarea interogãrilor JavaScript de cãtre server
JavaScript poate fi utilizat în scrierea interogãrilor și a funcțiilor de agregare( de exemplu MapReduce), ce sunt trimise direct cãtre baza de date pentru a fi executate.
8.Colecții „capped”(plafonate)
MongoDB suportã colecții cu lungime fixã numite colecții ‚caped‟.Acest tip de colecții pãstreazã ordinea de inserare, iar odatã ce lungimea specificatã a fost atinsã, se comportã ca o coadã circularã.
2.3.3 CAZURI DE UTILIZARE
MongoDB este alegerea potrivitã pentru una din urmãtoarele situații:
Arhivare și logare de evenimente
9
Lucrare de licențã
2013
Sistem de management a documentului și a conținutului : fiind o bazã de date document-orientatã( JSON), schemele flexibile din MongoDB sunt potrivite pentru aceastã situație
Comerțul electronic: o mulțime de site-uri folosesc MongoDB ca fiind nucleul infrastructurii de gestionare a activitãții( de cele mai multe ori în combinație cu o bazã de date relaționalã pentru procesarea comenzii și pentru gestionarea conturilor).
Jocuri : Performanța mare și operațiile rapide de citire/scriere sunt caracteristici definitorii pentru MongoDB , de aceea pentru anumite jocuri ce necesitã indexare geospațialã este de ajutor.
Probleme legate de volum mare de date
Sisteme mobile
Gestionarea datelor de pe un site web: MongoDB este foarte bun pentru inserãri, update-uri și interogãri în timp real.De aceea MongoDB este potrivit pentru site-uri unde este necesar managementul conținutului, înregistrarea utilizatorilor, sesiuni de date,etc
Proiecte cu utilizeazã metodologii de dezvoltare iterative/agile: Formatul de date BSON este foarte ușor de stocat și regãsește datele într-un format specific documentelor(fara existența unei scheme). Adãugarea de noi proprietãți este ușor de realizat și nu necesitã operații blocante de tipul “ALTER TABLE”.
Statistici/Analize în timp real.
2.3.4 MANIPULAREA DATELOR
MongoDB stocheazã structurile de date ca documente JSON, utilizând scheme dinamice( numite BSON), mai curând decât scheme predefinite.În MongoDB, un element ce conține date se numește document, iar documentele sunt stocate în colecții. O colecție are un numãr de oricâte documente.
Aranjarea datelor în MongoDB are loc într-un mod inovativ, comparativ cu bazele de date relaționale. Într-o bazã de date relaționalã, datele pot fi vãzute ca fiind organizate în tabele, fiecare tabel fiind compus din înregistrãri, iar acestea la rândul lor fiind compuse din câmpuri. O caracteristicã esențialã a bazelor de date relaționale este aceea cã într-o tabelã, fiecare înregistrare are aceleași câmpuri( în general cu valori diferite), în aceeași ordine.
10
Lucrare de licențã
2013
Considerând o instanțã MongoDB, putem spune cã o colecție este exact ca o tabelã și cã documentele sunt ca înregistrãrile. Dar existã o diferențã mare și anume faptul cã orice document dintr-o colecție poate avea câmpurile complet diferite fațã de alt document. Singura cerințã în realizarea schemei este cã fiecare document trebuie sa conținã un câmp „_id” cu o valoare unicã, ce nu trebuie sa fie de tip vector.
O tabelã caracteristicã pentru o bazã de date relaționalã, accesibilã prin intermediul limbajului SQL, este de exemplu:
Fiecare înregistrare are aceleași câmpuri, în aceeași ordine.
Pe de altã parte, o colecție caracteristicã MongoDB poate arãta de exemplu:
{
"_id": ObjectId("4efa8d2b7d284dad101e4bc9"),
"Prenume": "Andrei",
"Nume": "Popescu",
"Data nașterii": "06-21-1977" },
{
"_id": ObjectId("4efa8d2b7d284dad101e4bc7"),
Prenume ": "Mihai",
Nume ": "Ionescu",
Data nașterii ": "11-17-1978",
"Adresã": "Strada Lungã, nr.21",
"Oraș": "Brașov"
}
Fiecare document dintr-o colecție MongoDB poate avea câmpuri diferite fațã de alte documente.
De remarcat faptul cã „_id” este un câmp obligatoriu, creat automat de MongoDB, fiind unicul index prin intermediul cãruia se indetificã un document. Acest câmp poate fi specificat și de cãtre user ca fiind orice valoare care nu este mulțime, cu condiția ca ea sa
11
Lucrare de licențã
2013
fie unicã. Putem gândi acest „_id” ca fiind cheia primarã a unui document. Fiecare document necesitã aceastã valoare.
Într-un document, pot fi adãugate câmpuri noi sau cele deja existente pot fi modificate, redenumite sau șterse în orice moment. Nu existã o schemã predefinitã. O structurã a unui document este foarte simplã: se muleazã pe formatul unui document JSON și este compus dintr-o serie de perechi cheie-valoare, acest tip de document fiind numit în diferite limbaje: „șir asociativ”, „hartã”, „dicționar” sau „tabelã de dispersie”. Cheia din perechea cheie-valoare este numele câmpului, iar valoarea este conținutul câmpului. Cheia si valoarea sunt separate prin caracterul „:”, așa cum este prezentat in exemplul dat. O valoare poate fi: un numãr, un șir de caractere, adevãrat/fals, date binare cum ar fi imagini sau fișiere; mulțimi de valori( unde tipurile pot fi diferite) sau chiar un subdocument.
De exemplu:
{
"_id": ObjectId("4efa8d2b7d284dad101e4bc7"), "Nume": "Popovici",
"Prenume": "Andrei",
"Data nașterii": "09-19-1981",
"numãrDeTelefon": [
{
"tip": "acasã",
"numãr": "0727 034 567"
},
{
"tip": "fax",
"numar": "0245 789 564", "verificat": false
}
],
"Adresã": {
"Strada": "Zizinului",
"Oraș": "Brașov"
},
"Numãrul de luni de când locuiește la noua adresã": 37
}
Se observã cã „Adresã” este un câmp ce conține un subdocument cu alte doua câmpuri:
Strada si Oraș.
12
Lucrare de licențã
2013
COMENZI VALABILE ÎN MONGODB
mongo: MongoDB oferã un shell interactiv numit mongo, ce permite dezvoltatorilor sã execute operații de inserare, vizualizare, ștergere și update pe baza de date. De asemenea pot obține informații replicate, pot opri servere, pot executa JavaScript și multe altele. Informațiile administrative pot fi accesate de asemenea prin intermediul unei interfețe web; o paginã simplã ce oferã informații despre statusul serverului folosit.
mongostat: este o unealtã folositã în linie de comandã ce afișeazã o listã sumarã de caracteristici a instanței curente de MongoDB: câte inserãri, modificãri, ștergeri și interogãri au fost executate, afișeazã de asemenea și timpul cât baza de date a fost blocatã pentru executarea operației și câtã memorie s-a folosit.
mongotop: este o unealtã folositã în linie de comandã ce oferã o metodã de a urmãri timpul petrecut de instanța MongoDB pentru citirea și scrierea datelor.
mongosniff: este o unealtã folositã în linie de comandã ce monitoriseazã(„ sniffing”) traficul în rețea cãtre și dinspre MongoDB.
2.3.4.5 mongoimport, mongoexport: sunt unelte folosite în linie de comandã pentru a importa conținut dintr-un JSON,CSV( Coma-Separated-Value) sau export TSV( Tab-Separated-Value) creat de mongoexport.
13
Lucrare de licențã
2013
2.4 SPRING FRAMEWORK
2.4.1 INTRODUCERE
Spring este un framework open source, creat inițial de Rod Johnson. Acesta a fost creat pentru a simplifica dezvoltarea aplicațiilor de tip enterprise, fãcând posibilã utilizarea clasicelor JavaBeans pentru a obține acest lucru, realizat pânã atunci numai prin intermediul componentelor EJB.
Spring simplificã dezvoltarea aplicațiilor Java folosind urmãtoarele strategii cheie:
Utilizarea claselor Java clasice (POJO- Plain Old Java Objects) .
Interdependențã cât mai scãzutã între obiecte, prin utilizarea conceptului de injectare a dependințelor( DI- Dependency Injection).
Eliminarea codului duplicat folosind șabloane specifice.
2.4.2 PREZENTAREA MODULELOR SPRING
Mediul de lucru Spring este format dintr-o serie de module distincte, permițând dezvoltatorului sã se foloseascã numai de cele de care are nevoie.
Containerul de bazã Spring
Partea centralã a framework-ului Spring o reprezintã un container care supravegheazã modul în care componentele aplicației sunt create, configurate și administrate. Modulele „Core” și „Beans” descriu pãrțile fundamentale ale framework-ului, incluzând implementarea mecanismului de injectare a dependințelor. BeanFactory reprezintã o implementare complexã a șablonului de proiectare „Factory”. Acesta eliminã necesitatea de a implementa manual componente singletone și minimizeazã interdependența dintre specificarea dependințelor și logica programului efectiv.
Modul „Context” furnizeazã un mijloc de a accesa obiectele într-o manierã specificã framework-ului. Modului „Context” își moștenește facilitãțile de la modului „Beans”, la care adaugã suport pentru internaționalizare, propagarea evenimentelor, încãrcarea resurselor și crearea transparentã a contextelor. Interfața „ApplicationContext” reprezintã cel mai important punct al acestui modul.
14
Lucrare de licențã
2013
Modulul „Expression Language” furnizeazã un limbaj format din expresii pentru a interoga și manipula structura de obiecte în timpul rulãrii aplicației. Limbajul suportã operații precum setarea și obținerea de valori ale proprietãților, asignarea de proprietãți, invocarea de metode, accesul al structuri de date, operatori aritmetici și logici, obținerea obiectelor dupã nume din containerul Spring.
Modulul AOP (Programarea orientatã pe aspecte)
Acest modul oferã programatorului tot suportul necesar pentru a-și dezvolta propriile sale aspecte. Cu ajutorul aspectelor, rezolvarea problemelor globale ale aplicației, precum tranzacțiile sau securitatea, este “decuplatã” de obiectele asupra cãrora acestea sunt aplicate.
Modulul de acces la date
Adeseori, când se lucreazã cu JDBC, se ajunge la scrierea de cod repetitiv, pentru a obține o conexiune a bazei de date, pentru a crea o interogre, pentru a procesa un rezultat returnat și pentru a închide o conexiune deschisã anterior. Modulul Spring JDBC și DAO (Data Access Objetcs) abstractizeazã aceste operații menținându-se astfel codul legat de baza de date mult mai lizibil. De asemenea, acest modul construiește un nivel de excepții ce îmbracã erorile SQL în mesaje mult mai sugestive.
Modulul web
Paradigma Model-View-Controller (MVC) reprezintã o abordare comunã pentru a dezvolta aplicații web astfel încât interfața cu utilizatorul sã fie complet separatã de logica aplicației. Deși Spring poate fi integrat cu alte framework-uri precum Java
Server Faces sau Apache Struts, acesta vine cu un framework MVC capabil sã promoveze tehnicile de minimizare a interdependenței dintre componente și la nivelul web al unei aplicații Spring MVC vine cu douã forme: un framework bazat pe servlets și unui bazat pe portlets.
15
Lucrare de licențã
2013
Figura 2.4.2.1 Modulele Spring Framework (http://static.springsource.org/)
2.4.3 INJECTAREA DEPENDINȚELOR
Conceptul de injectare a dependințelor este cunoscut și sub numele de “Inversiune de control” (IoC – Inversion of Control). Acest concept se referã la faptul cã obiectele sunt cuplate la run-time de cãtre assembler iar legãturile dintre obiecte nu sunt cunoscute la momentul compilãrii.
Mai exact, obiectele își definesc propriile dependințe numai prin intermediul argumentelor constructorului, al argumentelor unei metode de tip factory sau prin propretãțile setate unui obiect dupã ce acesta a fost construit. Ulterior, containerul injecteazã aceste dependințe atunci când creeazã componenta. Inversiunea de control este exact inversul procesului în care componenta își autocontroleazã instanțierea sau localizarea dependințelor, prin construirea directã de clase.
16
Lucrare de licențã
2013
Exemplu:
Construirea unei componente simple Spring:
public class Persoanã{ private String nume;
private String prenume; public String getNume(){
return nume;
}
public String getPrenume(){ return prenume;
}
public void setNume(String nume){ this.nume=nume;
}
public void setPrenume(String prenume){ this.prenume=prenume;
}
public Persoanã(String nume, String prenume){ this.nume =nume; this.prenume=prenume;
}
}
Declararea componentei folosind injectarea valorilor prin intermediul constructorului:
<bean name=”persoanã” class=”ro.unitbv.exemplu.mvn.controller.Persoanã”>
<constructor-arg value=”Ionel”/>
<constructor-arg value=”Popescu”/>
</bean>
Declararea componentei folosind injectarea prin intermediul proprietãților:
<bean name=”persoanã” class=”ro.unitbv.exemplu.mvn.controller.Persoanã”>
<property name=”nume” value=”Popescu”/>
<property name=”prenume” value=”Ionel”/>
</bean>
17
Lucrare de licențã
2013
Pachetele org.springframework.beans și org.springframework.context formeazã baza pentru containerul de inversiune de control. Interfața BeanFactory oferã un mecanism avansat, capabil sa administreze orice tip de obiect. ApplicationContext este o sub-interfațã ce adaugã suport pentru a ușura integrarea cu facilitãțile oferite de Spring AOP( modulul orientat pe aspecte) și manipularea resurselor pentru mesaje.
Pe scurt interfața BeanFactory furnizeazã mediul de configurare și funcționalitatea de bazã, pe când ApplicationContext aduce funcționalitãți specifice aplicațiilor de tip enterprise.
Figura 2.4.3.1 Interfața BeanFactory (http://static.springsource.org/)
2.4.4 DURATA DE VIAȚÃ A UNEI COMPONENTE SPRING (BEAN)
Într-o aplicație tradiționalã Java, ciclul de viațã al unei componente este simplu: Cu ajutorul cuvântului cheie “new” se instanțiazã componenta, fiind pregãtitã pentru utilizare. Odatã ce componenta nu mai este folositã, ea este preluatã de garbage collection.
Într-o aplicație Spring ciclul de viațã este mult mai elaborat.
Figura de mai jos prezintã începutul de viațã al unei componente standard și felul în care este încãrcatã în contextul aplicației. Dupã cum se poate observa, BeanFactory efectueazã o serie de pași pregãtitori înainte ca bean-ul sã fie gata de utilizare.
18
Lucrare de licențã
2013
Spring instanțiazã componenta și injecteazã valorile și referințele cãtre alte
componente, în proprietãțile componentei create.
În cazul în care componenta implementeazã interfețele prezentate în figura de mai jos și anume: BeanNameAware, BeanFactoryAware, ApplicationContextAware,
BeanPostProcessor, InitializingBean sau DisposableBean, metodele aferente interfețelor vor fi chemate de-a lungul procesului de creare.
Figura 2.4.4.1 Durata de viațã a unei componente Spring ((http://static.springsource.org/))
2.4.5 PROGRAMAREA ORIENTATÃ PE ASPECTE
Aspectele ajutã și încurajeazã modularizarea felului în care sunt implementate problemele comune ale modulelor unei aplicații. Mai concis, o problemã comunã
19
Lucrare de licențã
2013
poate fi descrisã ca orice funcționalitate care afecteazã mai multe puncte ale aplicației. De exemplu, problema securitãții poate fi consideratã o “problemã transversalã”( cross-cutting concern), deoarece, o mare parte din metode pot avea aplicate asupra lor reguli de securitate. O descriere mai explicitã este redatã în figura de mai jos. Acestã figura schițeazã o aplicație clasicã, structuratã pe module. Fiecare modul are grijã sã furnizeze serviciile necesare domeniului sãu, dar, fiecare modul are nevoie, la rândul sãu de astfel de servicii pentru a funcționa corespunzãtor.
O tehnicã comunã de a reutiliza funcționalitãțile comune poate fi aplicarea moștenirii sau delegarea.
Alegerea moștenirii poate duce la dezvoltarea unor ierarhii de clase complexe, iar delegarea poate deveni greoaie din cauza apelurilor complicate ce trebuiesc fãcute obiectului delegat.
Figura 2.4.5. Modularizarea implementãrii problemelor comune ((http://static.springsource.org/))
Aspectele pot oferi în multe circumstanțe o alternativã mai flexibilã și lizibilã celor douã soluții menționate anterior. Folosind AOP, funcționalitatea comunã va fi definitã într-un singur loc, iar declarativ, ea va fi aplicatã fãrã a fi necesarã efectuarea de modificãri asupra clasei pe care se aplicã noua facilitate. Astfel, modulele aplicației rãmân nemodificate, conținând cod legat numai de funționalitatea acestora, iar probșlemele secundare fiind încapsulate folosind aspecte.
20
Lucrare de licențã
2013
2.4.6 SPRING MVC
Spring MVC oferã toate funționalitãțile necesare pentru a dezvolta aplicații web robuste.Acesta este disponibil ca și modul separat în cadrul distribuției. Framework-ul
Spring MVC este proiectat și conceput în așa fel încât fiecare componentã sã fie în întregime configurabilã. De asemenea Spring se integreazã fãrã efort și cu alte framework-uri web precum Java Server Faces sau Struts. Mai mult decât atât, Spring nu este limitat la utilizarea tehnologiilor Servlets și JSP pentru a reda partea de View clientului. Integrarea cu alte tehnologii precum Freemarker sau Velocity este posibilã.
Bazat pe șablonul Model-View-Controller (MVC), acest framework ajutã dezvoltatorii sã implementeze aplicații web la fel de flexibile și slab interconectate, ca și modul în care framework-ul Spring funcționeazã.
Șablonul MVC este un model software proiectat pentru ușurarea implementãrii interfețelor utilizator interactive. Acest șablon separã reprezentarea informației de interacțiunea utilizatorului cu aceasta.
Cele trei componente ce colaboreazã sunt:
Controller : se ocupã de logica navigãrii intre pagini și interacționeazã cu nivelul serviciul pentru logica business
Model: este un contract între Controller și View, conținând datele necesare
View-ului pentru a fi redat; valorile modelului sunt setate cu ajutorul Controllerului
View: redã utilizatorului un rãspuns în urma unei cereri, utilizând datele din
Model.
2.4.7 CICLUL DE VIAȚÃ AL UNEI CERERI
Framework-ul web MVC oferit de Spring, la fel ca și alte framework-uri MVC. este bazat pe cerere și este proiectat în jurul unui Servlet , responsabil cu expedierea cererilor cãtre controlleri. DispatcherServlet este integrat în totalitate în containerul
IoC (Inversion of Control).
21
Lucrare de licențã
2013
Fluxul de procesare al unei cereri de cãtre DispatcherServlet este ilustrat în diagrama de mai jos:
Figura 2.4.7.1 Fluxul de procesare al unei cereri ((http://static.springsource.org/))
De fiecare datã când un utilizator acționeazã un link sau trimite cãtre server un formular, o cerere (request) începe sã fie procesatã; din momentul în care cererea pãrãsește browserul și pânã cand se returneazã rãspunsul (response), ea face câteva opriri pentru a lãsa sau reține informații. Când o cerere pãrãsește broserul, ea conține informații despre ceea ce solicitã utilizatorul. în primul rand va reține URL-ul cerut, dar și date obținute din formularul completat de utilizator.
Prima “oprire” a cererii este la DispatcherServlet. La fel ca și alte framework-uri,
Spring trateazã cererile folosind un controller principal( Front controller), acest controller este un șablon web unde un singur servlet deleagã responsabilitatea tratãrii cererii altor componente ale aplicației, pentru a efectua procesarea propriu-zisã. În esențã, DispatcherServlet-ul trimite cererea cãtre un controller Spring.
Un controller reprezintã o componentã Spring capabilã sã proceseze o cerere primitã. În general aplicațiile conține mai multe componente de acest tip, iar
DispatcherServlet-ul are nevoie de mai multe informații pentru a hotarî care controller este cel potrivit cu cererea. Aceastã decizie se bazeazã pe URL-ul reținut de cerere,
DispatcherServlet-ul consultând una sau mai multe componente de tip handler mapping și decizând cine este controllerul destinație.
22
Lucrare de licențã
2013
Dupã gãsirea controllerului corespunzãtor, cererea oferã acestuia informațiile reținute și așteaptã ca ele sã fie procesate. Logica efectuatã de controller, de cele mai multe ori, are ca rezultat o serie de informații ce trebuie afișate în browser pentru a fi vizualizate de utilizator. Aceste informații poartã denumirea de model. De asemenea ele trebuie sa fie formatate într-o manierã compatibilã cu browserul (format HTML), fiind necesar ca modelul sã fie transmis mai departe unui view (de exemplu
Freemarker).
Printre ultimele lucruri pe care le face un controller, este împachetarea modelului de date și identificarea numelui view-ului ce trebuie sã redea informațiile. În final cererea
(request-ul) împreunã cu numele view-ului și modelul de date sunt trimise cãtre
DispatcherServlet. Numele view-ului trimis cãtre DispatcherServlet nu definește un fișier în mod direct ca fiind de un anumit tip, acest nume nu sugereazã ca view-ul este de tip Freemarker sau JSP sau orice alt tip de fișier, în schimb controller-ul trimite un nume logic ce se folosește pentru identificarea view-ului destinat producerii rezultatului final. DispatcherServlet va consulta o componentș de tip view resolver pentru a mapa numele logic al view-ului împreunã cu implementarea sa.
Știind ce view va reda rezultatul, ultima “oprire” a DispatcherServlet-ului va fi implementarea view-ului, unde este “livrat” modelul de date. Folosind datele obținute, view-ul va reda rãspunsul clientului.
Ca orice alt servlet, DispatcherServlet se configureazã folosind fișierul web.xml.
Exemplu de configurare:
<servlet> <servlet-name>lecturehall</servlet-name> <servlet-
class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup>
</servlet> <servlet-mapping>
<servlet-name>lecturehall</servlet-name> <url-pattern>/*</url-pattern>
</servlet-mapping>
23
Lucrare de licențã
2013
În Spring, instanțele de ApplicationContext pot avea domeniu de viațã, fiecare DispatcherServlet are propriul sãu WebApplicationContext, acesta moștenind toate componentele deja definite în WebApplicationContext-ul rãdãcinã. Aceste componente moștenite, pot fi suprascrise în domeniul de viațã specific servletului și pot fi definite local de noi componente ce sunt legate de o instanțã a servletului dat.
DispatcherServlet folosește componente speciale pentru a procesa cererile și pentru a reda rãspunsul. Aceste componente fac parte din framework-ul Spring MVC.
Programatorul poate alege ce componente speciale vrea sa foloseascã, configurându-le in WebApplicationContext. Aceastã configurare nu este obligatorie, deoarece Spring MVC menține o serie de componente implicite pe care sã le foloseascã în cazul în care programatorul nu definește nici una. În tabelul de mai jos sunt notate cele mai importante componente pe care DispatcherServlet se bazeazã.
Componente speciale Spring MVC
2.4.8 IMPLEMENTAREA UNUI CONTROLLER
Un controller oferã acces la comportamentul aplicației, definit în mod normal, prin intermediul unui nivel de serviciu. Acesta interpreteazã datele de intrare și le transforma într-un model, reprezentat ulterior prin intermediul unui view.
Conform API-ului (Application Programming Interface ) Spring, o implementare a unui controller trebuie sã fie reutilizabilã,thread-safe și capabilã sã manipuleze cereri HTTP multiple de-a lungul ciclului de viațã al unei aplicații.
24
Lucrare de licențã
2013
Începând cu versiunea 2.5, Spring introduce modul de programare bazat pe adnotații, precum @RequestMapping, @RequestParam, @ModelAttribute, etc. Controller-ii implementați folosind aceastã manierã nu trebuie sã extindã nici o clasã de bazã sau sã implementeze vreo interfațã. Mai mult, aceștia nu depind de API-ul Servlet.
Exemplu: @Controller
public class HelloWolrldController {
@RequestMapping(“/helloWorld”) public String helloWorld( Model model){
model.addAttribute(“message”,”Hello World!”); return “helloWorld”;
}
}
Dupã cum se poate observa în exemplul precedent, adnotațiile @Controller și @RequestMapping permit nume și semnãturi flexibile metodelor. În acest exemplu, metoda helloWorld primește ca parametru un model și returneazã un nume de view.
Adnotația @Controller indicã faptul cã o anumitã clasã servește rolul unui controller Spring. DospatcherServlet scaneazã clasele astfel adnotate pentru a indetifica metodele mapate, detectând adnitațiile @RequestMapping.
Adnotația @RequestMapping se poate folosi pentru a mapa URL-uri unei întregi clase sau doar unei anumite metode. În mod normal. adnotația de la nivelul clasei specificã o anumitã cale, pe cãnd cele de la nivelul metodei specificã și metoda HTTP pentru cerere (“GET” sau “POST”).
25
Lucrare de licențã
2013
Exemplu:
@Controller @RequestMapping(value = "/book") public class BookController {
@RequestMapping(method = RequestMethod.GET, value = "/search/searchByCategory")
public ModelAndView showCategory(ModelMap model, HttpServletRequest request) throws MalformedURLException, SolrServerException {
ModelAndView modelAndView = new ModelAndView("searchCategory"); SearchingProcess searchingProcess = new SearchingProcess();
ArrayList<String> authors = searchingProcess.receiveFacetDataFromSolr("category"); modelAndView.addObject("categories", authors);
return modelAndView;
}
@RequestMapping(method = RequestMethod.POST, value = "/search/searchByCategory") public ModelAndView searchBookByCategory(ModelMap model,
@RequestParam("categories") String searchCategory) throws MalformedURLException, SolrServerException {
if (searchCategory.isEmpty() == true) {
ModelAndView mav = new ModelAndView("searchPage"); mav.addObject("message", "Nu a-ți introdus termen pentru cãutare!"); return mav;
}
}
Dupã cum se poate observa, Spring oferã un framework flexibil și puternic pentru dezvoltarea aplicațiilor web. Utilizând adnotațiile, Spring furnizeazã un model de lucru bazat pe POJO-uri (Plain Old Java Object), simplificând dezvoltarea controller-ilor. Acești controller-i nu proceseazã direct cererile, ci deleagã alte componente, prezente în contextul aplicației, fiind injectate folosind conceptul de Dependecy Injection, sã îndeplineascã sarcina.
Delegând componentele handler mappings pentru a selecta ce controller sã trateze o anumitã cerere și delegând view resolvers pentru stabilirea modului în care rezultatul este redat, Spring MVC menține o interdependențã scãzutã între modul în care un controller trateazã cererea și modul în care un view afișeaza rãspunsul. Acest lucru oferã avantaj major framework-ului Spring în fațã altor framework-uri.
26
Lucrare de licențã
2013
2.4.9 CONCEPTE LEGATE DE LUCRUL CU BAZE DE DATE
Interfața centralã din repository-ul Spring Data este Repository. Este de remarcat faptul cã aceastã interfațã joacã rolul de interfațã marcator ce obține tipul elementului cu care lucreazã și ne ajutã când descoperim interfețe ce o extind. Dincolo de aceastã noțiune existã CrudRepository, o interfațã ce oferã câteva funcționalitãți ale operațiilor
CRUD (Create Read Update and Delete) , asupra entitãții pe care o gestioneazã.
public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID> {
<S extends T> S save(S entity);
T findOne(ID primaryKey);
Iterable<T> findAll();
Long count();
void delete(T entity);
Figura 2.4.9.1 Interfața CrudRepository
Salveazã entitatea primitã.
Returneazã entitatea indentificatã prin id-ul dat ca parametru.
Returneazã toate entitãțile.
Șterge entitatea primitã ca parametru.
Returneazã true dacã existã o entitate pentru id-ul dat ca parametru.
SPRING DATA –MONGODB
Orice proiect Spring data suportã urmãtoarele trei aspecte: crearea de șabloane, maparea obiectelor și suport pentru depozitarea datelor.
2.5.1 DE CE SPRING DATA-DOCUMENT ?
Scopul framework-ului Spring Data Document (sau DATADOC) este de a oferi o extensie a modelului de programare oferit deSpring, extensie ce suportã dezvoltarea de
27
Lucrare de licențã
2013
aplicații ce folosesc baze de date ce rețin documente. Framework-ul Spring promoveazã intotdeauna modelul de programare bazat pe POJO cu un puternic accent pe productivitate și portabilitate.
Modelul de programare urmeazã șablonul specific Spring-ului, deci dacã ești familiar cu șabloanele de clase Spring, precum JdbcTemplate, JmsTemplate, RestTemplate, acestea se gãsesc și in acest framework.
De exemplu, MongoTemplate eliminã o mare parte din boilerplate code-ul ce ar trebui scris când folosești driver-ul MongoDB pentru a salva obiecte POJO. Acest model de programare oferã de asemenea o nouã abordare de depozit de date (“repository”) , unde containerul de Spring oferã o implementare a depozitului, bazatã pe definirea unei interfețe ce poate include metode de cãutare definite de utilizator.
2.5.2 DRIVERE MONGODB
Existã implementate drivere pentru marea majoritate a limbajelor de programare (C,
C++, C#, Erlang, Java, Javascript, Node.js, PHP, Python, Ruby, etc).
Responsabilitãțile acestui driver sunt de a converti structurile de date dependente de limbaj in format BSON (Binary JSON) și de a genera ObjectId-ul pentru câmpul _id din colecție.
Driver-ul de Java
Utilizarea driver-ului de Java este simplã. În primul rând trebuie inclusã biblioteca mongo.jar în classpath, aceasta reprezentând driverul de conexiune.
Pentru a realiza o conexiune cãtre MongoDB, minimul necesar este numele bazei de date la care dorim sã ne conectãm. Baza de date nu este obligatoriu sã existe, dacã nu existã MongoDB va crea una.
În plus, se poate specifica adresa serverului și portul de conectare. Dependința de biblioteca Java folositã în aceastã aplicație aratã de forma:
Lucrare de licențã
2013
2.5.3 ȘABLOANE
Scopul principal al șabloanelor Spring Data (și a altor șabloane Spring, de altfel) este de a oferi suport pentru alocarea resurselor și pentru traducerea excepțiilor.
În cazul lucrãrii de fațã, o resursã înseamnã un depozit de date (datastore), ce este accesibil de la distanțã prin termediul unei conexiuni TCP/IP.
În urmãtorul exemplu este ilustratã configurarea șablonului MongoDB
(MongoTemplate):
<mongo:db-factory id="mongoDbFactory" dbname="${mongo.database}" mongo-ref="mongo" />
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/> </bean>
În primul rând, se definește o “fabricã”(factory) de conexiuni, ce este referitã ulterior de Mongo Template.
Un șablon oferã operații de stocare a datelor specifice ca: salvare, modificare și ștergere a unei singure înregistrãri, oferã de asemenea suport pentru executarea de interogãri și operații map/reduce (pentru rezolvarea cazurilor complexe de agregare).
Maparea obiectelor în vederea salvãrii in baza de date
@Document(collection=”user”) public class User{
@Id
private String id;
@Field(“nm”) private String name;
…
}
Adnotația @Document identificã un domeniu de obiecte ce urmeazã a fi salvate in MongoDB, pentru asigurarea persistenței.
29
Lucrare de licențã
2013
MongoDB folosește adnotația @Id pentru definirea id-ului unic al unei înregistrãri
(similar cu conceptul de cheie primarã din structura bazelor de date relaționale). Pentru acele atribute al cãror nume din documentul MongoDB diferã de cel din obiectul Java, se folosește adnotația @Field.
APACHE SOLR
INTRODUCERE
Apache Solr este o platformã de cãutare open-source bazatã pe proiectul Apache Lucene. Cele mai importante caracteristici includ: cãutarea în conținutul integral documentelor (full-text), sublinierea elementelor cãutate în textul returnat
(highlighting), cãutare fațetatã (faceted search), procesare de documente în diferite formate (Word, PDF, etc).
Solr este cel mai popular motor de cãutare, oferind cãutare distribuitã și replicare de indecși.
Solr este scris folosind limbajul Java și ruleazã ca un server independent pe baza unui servlet ca Apache Tomcat sau Jetty.
Solr folosește biblioteca Lucene, scrisã de asemenea in Java, pentru cautarea full-text , pentru indexare și cãutare.
Pe scurt, prin intermediul acestei platforme, se pot adãuga documente (se indexeazã) via XML, JSON, CSV sau documente binare prin HTTP (Hypertext Transfer
Protocol). Obținerea documentelor (interogãrile) au loc via cereri HTTP GET. obținându-se rezultate în format binar, XML, CSV, JSON.
2.6.2 ISTORIC
În 2004, Solr a fost creat de Yonik Seeley la firma CNET Networks, ca un proiect intern pentru a adãuga capabilitãți de cãutare pentru website-ul companiei.
În ianuarie 2006, CNET Networks a decis sã facã public codul sursã, donându-l cãtre
Apache Software Foundation ca proiect top-level sub Lucene. Ca orice proiect nou la Apache Software Foundation, a fost introdus intr-o perioadã de incubare pentru a rezolva problemele organizaționale și financiare.
30
Lucrare de licențã
2013
La un an dupã, Solr a evoluat de la stadiul de incubare, fiindu-i adãugate noi capabilitãți. În septembrie 2008 a fost lansatã versiunea 1.3 cu multiple capabilitãți legate de cãutarea distribuitã.
În 2011 a fost lansatã versiunea 1.4, imediat dupã aceastã lansare a apãrut o nouã versiune 3.1 , numerotatã astfel pentru a avea același numãr de versiune ca Lucene.
În octombrie 2012 a fost lansatã versiunea Solr 4.0 ce include caracteristici noi printre care și conceptul de SolrCloud.
2.6.2 CARACTERISTICI SOLR
În mare, principalele caracteristici sunt:
Capablitãți de cãutare full-text (în tot conținutul documentului) avansate.
Este optimizat pentru trafic web al unui volum mare de informație
Standarde bazate pe interfețe comune ca: XML, JSON, HTTP
Interfațã HTML de administrare a datelor
Apropiatã de indexarea în timp real
Flexibil și usor de adaptat folosind configurãri XML.
Arhitecturã ușor de extins prin intermediul plugin-urilor.
Folosește biblioteca Lucene, extinzându-i capabilitãțile.
Figura 2.6.2.1 Intefața HTML de administrare a datelor
Apache Solr funcționeazã pe baza câtorva concepte de bazã:
31
Lucrare de licențã
2013
1. Schema
Este un fișier XML în care se definesc câmpuri de documente și tipurile acestora. Poate ajuta la dezvoltarea unei procesãri inteligente a documentelor prin aplicarea unor filtre predefinite sau crearea unor configurãri ce conțin liste de sinonime, liste de cuvinte ce pot fi ignorate sau expresii regulate.
Pentru a înțelege mai bine noțiunea de schemã, vom face un pas înapoi pentru a întelege noțiunea de Document din Lucene. Un Document este o colecție de unui sau mai multe Field-uri (câmpuri), iar un Field este format dintr-un nume, un conținut și o metadatã despre cum sã se manipuleze conținutul. Acest conținut este oferit spre cãutare dupã ce este analizat; analiza se realizeazã prin înlãnțuirea unor
Tokenizer-i , ce împart conținutul în cuvinte (tokeni), și a unori TokenFilter-e care modificã sau înlãtura token-ul .
Se pot declara câmpuri dinamice, prin intermediul cãrora se pot adãuga noi câmpuri în momentul procesãrii de documente. Funcționalitatea CopyField permite indexarea unui singur câmp în mai multe moduri sau combinarea mai multor câmpuri într-unul singur, pe care se va efectua cãutarea.
Schema Solr face mai ușor de configurat procesul de analizare fãrã a fi nevoie de cod implementat, de asemenea oferã o tipizare puternicã, facând posibilã specificarea unui Field ca fiind String, int, float , sau o altã primitivã, sau chiar un tip definit de utilizator.
Schema folositã în aceastã aplicație este ilustratã mai jos, amãnunte legate de conținutul ei vor fi prezentate în capitolul legat de implementarea aplicației.
32
Lucrare de licențã
2013
Câmpuri(Fields) :
copyField : aceste câmpuri oferã posibilitatea de a indexa un câmp în altul, adicã un câmp este copiat în interiorul altuia și sunt considerate ca fiind aceeași informatie. Acest tip de câmp este valabil doat pentru tipurile text sau string (tipuri specifice schemei Solr) .
dynamicField : sunt , într-un fel, inversul copyField-urilor , adicã permit procesarea mai multor câmpuri în același fel. Sunt folosite în general pentru a potrivi câmpuri din documente cu șabloane.
Indexarea
Indexarea datelor este un crucial în desfãșurarea unei aplicații ce folosește Lucene sau Solr. Atunci când datele nu sunt indexate, rezultatele unei cãutari ulterioare vor fi nesatisfcãcãtoare. Când sunt rezultate nesatisfãcãtoare, utilizatorii vor înceta sa
33
Lucrare de licențã
2013
mai foloseascã Solr, așa cã datele trebuie sã fie indexate, lucru nu tocmai ușor de realizat.
Un index Solr acceptã date din numeroase surse precum : fișiere XML, fisiere
CSV (Comma-Separated-Value), date extrase din tabele ale unei baze de date și fișiere în formate comune cum ar fi Microsoft Word sau PDF.
Existã trei modalitãți de a încãrca date într-un index Solr:
Prin intermediul analizatorului Apache Tika ce extrage conținut de text structurat și metadate din documente
Prin încãrcarea documentelor XML prin intermediul unei cereri HTTP cãtre serverul de Solr
Prin scrierea unei aplicații Java ce extrage conținutul documentelor prin intermediul unui API (Application Programming Interface) Java.
Indiferent de metoda folositã pentru încãrcarea datelor, existã o structurã comunã pentru introducerea datelor într-un index Solr și anume documentul, descris mai sus.
O interogare se bazeazã pe urmãtoarele componente din schema.xml :
Analizator (Analyzer) : un analizator convertește textul unui câmp și îl modificã în formatul în care exte indexat. Analizatorii sunt alcãtuiți din unui sau mai mulți tokenizeri sau filtre.
Tokenizer-ul : împarte fluxul de date dintr-un text în unitãti numite
“tokeni”.
Filtrul : ia tokenii, îi transformã și dã mai departe rezultatul transformat. (De exemplu: transformã tot textul în text cu litere mici).
Interogarea
Interogãrile în Solr au loc via unei cereri HTTP GET, parametrul “q” este folosit pentru a preciza cãrui câmp i se aplicã interogarea.
De exemplu, pe baza schemei prezentatã mai sus, dorim sã facem o interogare prin intermediul interfeței HTTP:
34
Lucrare de licențã
2013
Dacã dorim afișarea autorului cu numele de Mihai Eminescu vom scrie în interfațã: author:Mihai Eminescu, iar URL-ul va conține : q=author%3AMihai+Eminescu
Dacã dorim afișarea tuturor autorilor vom scrie : author:* , iar URL-ul va conține : q=author%3A*.
Evidențierea rezultatelor (Highlighting)
Așa cum sugereazã și numele, prin intermediul procesului de highlighting se returneazã fragmente din fiecare document returnat, unde au fost gãsiți termeni relevanți pentru cãutare.
Cãutarea fațetatã (Faceted search)
Cãutarea fațetatã reprezintã o modalitate de grupare dinamicã a
rezultatelor cãutarii pe categorii, oferindu-i utilizatorului o modalitate de a-
și rafina cãutarea. De asemenea numãrã elementele conținute de proprietãți sau categorii ale cãutarii.
2.6.3 INTEGRAREA SOLR
Existã implementate numeroase proiect pentru integrarea Solr în limbajele și mediile de programare.
Dintre acestea sunt prezentate cele mai semnificative:
35
Lucrare de licențã
2013
FREEMARKER
INTRODUCERE
Freemarker este un “instrument șablon”, un instrument generic pentru a genera ieșire de tip text (orice, începând de la cod HTML și pânã la cod sursã autogenerat) bazatã pe șabloane. Este un pachet Java, o bibliotecã pentru programatorii Java. Este ceva care poate “trãi” doar “ziditã”(embed) în interiorul unei aplicații.
FreeMarker este proiectat pentru generarea de pagini web HTML, în special pentru aplicații bazate pe servleți ce urmeazã șablonul MVC (Model View Controller). Idea din spatele șablonului MVC pentru pagini web dinamice, este de a separa designerii (autorii de cod HTML) de programatori, fiecare lucrând la ce este el bun.
Deși FreeMarker are câteva capabilitãți de programare, nu poate fi numit cu adevãrat un limbaj de programare, așa cum este PHP. Programele Java pregãtesc datele pentru a fi afișate și FreeMarker doar genereazã pagini textuale ce afișeazã datele primite, folosind șabloane.
Figura 2.7.1 Schema de funcționare (http://freemarker.sourceforge.net/)
FreeMarker nu este un cadru de lucru Web, dar este potrivitã ca fiind o componentã într-o aplicație Web doar pentru partea de view, deoarece nu știe nimci despre HTTP sau servleți, ci doar genereazã text.
2.7.2 ISTORIC
FreeMarker a fost creat de cãtre Benjamin Geer și Mike Bayer, din anul 2002 șeful de proiect a fost Jonathan Revusky, el lansând versiunea FreeMarker 2, care a venit cu modificãri substanțiale.
36
Lucrare de licențã
2013
În aceastã versiune, principala schimbare a fost de a face șablonul mult mai strict, detectând cât mai multe erori, cât mai repede. O altã mare schimbare adusã a fost câștigarea multor capabilitãți de programare prin intermediul macro-urilor.
Ultima versiune apãrutã a fost în 2004, de atunci s-a mai anuntat o lansare de versiune
în 2008 dar se pare cã încã se mai lucrezã la ea.
2.7.3 MOD DE UTILIZARE
Având urmãtorul șablon, scris într-un fișier cu extensia *.ftl :
<html>
<body>
<p>Bunã ${name}! Ai un mesaj: <#list messages as m>
<p><b>${m.from}:</b> ${m.body}</p> </#list>
</body>
</html>
Dupã obținerea datelor necesare de pe server, browser-ul îl va interpreta în forma :
<html>
<body>
<p> Bunã Andreea! Ai un mesaj:
<p><b>1:</b> Te rog nu uita cã trebuie sã îți termini documentația!</p> <p><b>2:</b> Aplicația ai terminat-o?</p>
<p><b>3:</b> Nu uita ca timpul e limitat!</p>
</body>
</html>
Variabilele “name” și “messages” vin din afara șablonului, din câte se observã “messages” pare a fi o mulțime ce are ca proprietãți “body” și “form”, dar ar putea fi de asemenea și ceva cu totul diferit, ceea ce nu afecteazã șablonul.
37
Lucrare de licențã
2013
3.IMPLEMENTAREA SOLUȚIEI
Pentru evidențierea modului de lucru cu tehnologiile descrise în capitolele anterioare, am ales dezvoltarea unei aplicații web care propune rezolvarea unei probleme, destul de des înfruntatã de studenți, și anume implementarea unei sãli de lecturã online, unde studenții pot cãuta cãrțile dupã mai multe criterii: dupã autor, dupã titlu, dupã categorie și cel mai important este faptul cã pot cãuta în conținutul acestora cuvinte cheie sau chiar fraze întregi.
De asemenea, aceastã aplicație pãstreazã evidența studenților înscriși pe site și a personalului ce gestioneazã conturile și documentele existente în sistem.
3.1 CERINȚE FUNCȚIONALE
Scopul acestui proiect este de a oferi studenților accesul online la cărțile existente in biblioteca facultății. Proiectul implică existența a două tipuri de utlizatori: student si administrator.
Orice student care dorește să acceseze această aplicație este obligat să se prezinte la sediul bibliotecii facultății
pentru a-i fi creat un cont de către unul dintre angajații acesteia.
Odată creat acest cont, studentul poate accesa aplicația pe baza unei parole și al unui nume de utilizator setate la crearea contului. Prin accesarea aplicației de către student se înțelege posibilitatea de a efectua căutari după unul dintre criteriile: titlu, autor, categorie, căutare după un anumit cuvânt sau expresie în conținutul cărților sau cãutare avansatã dupã categorie sau autor, ce presupune afișarea tuturor autorilor sau categoriilor salvate în sistem și a numãrului de documente existente pentru fiecare dintre aceștia(acestea). Rezultatele returnate în urma căutării vor fi disponibile pentru vizualizare în browser sau pentru descărcare in format .pdf, în funcție de tipul de browser folosit.În plus, studentul își poate modifica date ale contului.
În figura de mai jos sunt ilustrate cazurile de utilizare pentru un student.
38
Lucrare de licențã
2013
Figura 3.1.1 Cazuri de utilizare pentru un student
Administratorul are următoarele responsabilități: crearea de conturi pentru studenți, crearea de conturi cu drepturi depline și adăugarea de cărți în sistem. Administratorul poate de asemenea să șteargă orice cont de student, sã-și modifice sau sã-și șteargã propriul cont. De altfel, administratorul are acces la motorul de cãutare pus la dispoziția studenților.În figura de mai jos se pot observa cazurile de utilizare pentru un administrator.
Figura 3.1.2 Cazurile de utilizare pentru un administrator
39
Lucrare de licențã
2013
3.2 CERINȚE NON-FUNCȚIONALE
Mediul de rulare al acestei aplicații web trebuie sã aibe urmãtoarele tehnologii
instalate:
JRE (Java Runtime Environment) cu versiunea minimã recomandatã : jre6.
Serverul pe care va rula Apache Solr și anume Apache Tomcat, cu versiunea minimã recomandatã: Apache Tomcat 7.0.
Serverul de MongoDB instalat și rulat ca serviciu sub sistemul de operare, în cazul de fațã sistemul de operare este Microsoft Windows 7, este recomandatã
utilizarea unei versiuni cât mai recente a sistemului de operare, deoarece ultimele versiune de MongoDB apãrute nu sunt suportate pe sisteme de operare mai vechi, asa cum este Microsoft Windows XP.
Serverul de aplicație Apache Tomcat, cu versiunea minimã recomandatã :
Apache Tomcat 7.0.
Aplicația poate rula sub orice platformã pentru care existã un JVM (Java Virtual Machine) și care are instalat MongoDB ca serviciu. Instalarea MongoDB ca serviciu sub Microsoft Windows este prezentatã în Anexa 1. De asemenea, aplicația poate fi rulatã pe orice server web care implementeazã tehnologia Java Servlet .
3.3 BAZA DE DATE
Serverul de baze de date ales ca și sistem de stocare a informațiilor persistente este
MongoDB, el face parte din categoria serverelor NoSQL.
Comparativ cu bazele de date relaționale, unde schema trebuie definitã înainte de a începe sã adaugi date în baza de date, în cazul bazei de date NoSQL, se perminte inserarea de date fãrã o schemã predefinitã. Recomandat este, ca atunci când datele introduse fac parte din categorii diferite, sã fie grupate în colecții.
O schemã reprezentativã a bazei de date, la momentul actual, este:
40
Lucrare de licențã
2013
Figura 3.3.1 Schema bazei de date
În vocabularul NoSQL, noțiunea de tabelã este înlocuitã de noțiunea de colecție; așa cum se observã în schema de mai sus, existã douã colecții:
Student :
În aceastã colecție sunt stocate datele pentru toți studenții care sunt înregistrați ca utilizatori ai aplicației
Administrator :
În aceastã colecție sunt stocate datele pentru toți administratorii care sunt înregistrați ca utilizatori ai aplicației.
Pentru stocarea documentelor am folosit o specificație de tipul GridFS, care este o specificație atribuitã unei colecții, în cazul în care se dorește persistența fișierelor ce depãșesc limita unui document BSON și anume de 16MB.
41
Lucrare de licențã
2013
GridFS nu stocheazã un fișier ca un singur document BSON, ci îl divide în pãrți, numite „bucãți‟ (en:’chunks’), care sunt salvate ca documente separate.
În mod implicit, GridFS limiteazã marimea unei „bucãți‟ la 256k. Pentru stocarea fișierelor, GridFS folosește douã colecții, una stocheazã „bucãțile‟ de fișiere și cealaltã stocheazã metadatele fișierelor. Atunci când se executã o interogare pe un
GridFS, driverul sau clientul vor reasambla „bucãțile‟ în forma inițialã a fișierului care a fost stocat.
În colecția în care se salveazã “bucãțile” de fișiere s-a introdus conținutul cãrților, iar ca nume de fișier (filename), s-a introdus titlul cãrților salvate. În colecția de metadate, s-au introdus autorul și categoria din care face parte cartea.
Pentru ca aplicația sã aibã conexiuni la serverul de baze de date , este necesar ca serverul de baze de date sa fie pornit,; în cazul de fațã, este necesar sa serviciul MongoDB, ce ruleazã sub sistemul de operare, sã fie pornit.
Este necesar, de asemenea, ca un obiect de tipul MongoTemplate, sã conținã toate datele necesare conectãrii la baza de date.
Figura 3.3.2 Conținutul fișierului de proprietãți mongo.properties
42
Lucrare de licențã
2013
mongo.host – reprezintã gazda pe care ruleazã serverul de MongoDB, în cazul de fațã localhost.
mongo.port – reprezintã portul pe care ruleazã serverul de MongoDB, și anume 27017 fiind și cel implicit.
mongo.database – reprezintã numele bazei de date la care se va face conexiunea.
mongo.connectionsPerHost – reprezintã numãrul de conexiuni la baza de date alocate per host. În cazul în care acest numãr este depãșit, conexiunea se va bloca pana la încheierea unei ale conexiuni.
mongo.connectTimeout – reprezintã timpul alocat pânã la obținerea unei conexiuni.
mongo.maxWaitTime – reprezintã timpul maxim de așteptare a unui fir de execuție blocant pentru o conexiune.
mongo.autoConnectRetry – acest atribut controleazã dacã sistemul sã încerce sã se reconecteze automat în cazul unei perderi a conexiunii.
mongo.socketKeepAlive – controleazã menținerea socketului deschis.
mongo.socketTimeout – reprezintã timeout-ul socketului
mongo.writeNumber – reprezintã numãrul de servere dupã care trebuie sã se aștepte în cazul unei operații de scriere în baza de date.
Aceste proprietãți sunt atribuite instanței de MongoDB, care este înregistratã în Spring ca un spațiu de nume (namespace). Înregistrarea unei instanțe MongoDB ca spațiu de nume permite crearea unei instanțe a serverului și atribuirea proprietãților prezentate mai sus.
Un exemplu de configurare a unei instanțe MongoDB este prezentatã mai jos:
43
Lucrare de licențã
2013
Figura 3.3.3 Model de configurare a unei instanțe de MongoDB
Dupã cum se poate observa, în primul rând al acestei scheme de configurare este importat fișierul de proprietãți mongo.properties, în care sunt setate valorile necesare rulãrii serverului de MongoDB (acestea sunt prezentate în pagina anterioarã). În urmãtoarea structurã, care începe cu <mongo .. .>, valorile obținute din fișierul de proprietãți sunt setate pe spațiul de nume mongo.
Spațiul de nume mongo oferã o cale ușoarã de a crea o SimpleMongoDbFactory,ce permite conexiunea la serverul de MongoDB, pe baza proprietãților setate anterior în componenta numita mongo și referențiatã dupã cum urmeazã:
<mongo:db-factory id="mongoDbFactory" dbname="${mongo.database}" mongo-ref="mongo" /> .
Dupã configurarea conexiunilor cãtre serverul de baze de date, este necesarã instanțierea unui obiect pentru comunicarea și interacțiunea cu baza de date, acest obiect face parte din clasa MongoTemplate și este localizatã în pachetul org.springframework.data.document.mongodb. Aceastã clasã oferã posibilitatea realizãrii operațiilor CRUD (Create, Update, Insert, Delete) și interogarea documentelor MongoDB, de asemenea oferã o mapare între obiectele specifice Java și documentele MongoDB.
44
Lucrare de licențã
2013
Conform schemei de mai sus, configurarea MongoTemplate presupune adãugarea unor
proprietãți bean-ului “mongoTemplate” și anume:
mongoDBFactory, setat ca și constructor-arg, este folosit ã injectarea în constructorul pentru MongoTemplate, a valorilor conținute în el.
proprietatea writeConcern este folositã pentru obținerea confirmãrii de la server, înainte de a scrie diferite operațiuni.
proprietea writeResultChecking este folositã pentru a returna excepție în program, în cazul în care operațiunea de scriere în baza de date nu a fost cu succes.
Pentru a putea lucra cu GridFS este necesarã înregistrarea acestuia ca bean, dupã
cum urmeazã:
<bean id="gridTemplate" class="org.springframework.data.mongodb.gridfs.GridFsTemplate">
<constructor-arg ref="mongoDbFactory" /> <constructor-arg ref="converter" />
</bean>
Prin intermediul acestei configurãri, este injectatã o componentã de tip
GridFSTemplate în aplicație.
45
Lucrare de licențã
2013
3.4 ARHITECTURA APLICAȚIEI
Dupã cum se poate observa în schema de mai jos, aplicația este realizatã dupã pattern-ul de arhitecturã de software MVC (Model-View-Controller).
Figura 3.4.1 Schema arhitecturii aplicației
COMPONENTA MODEL
Aceastã parte componentã a arhitecturii aplicației se ocupã de inserarea și extragerea datelor din baza de date MongoDB, precum și de indexarea documentelor și interogarea indecșilor cu ajutorul Solr.
GESTIONAREA DATELOR CU MONGODB
Inserarea datelor în MongoDB se referã atât la inserarea unui utilizator nou înregistrat (student sau utilizator cu drepturi depline), cât și la inserarea cãrților. Diferența între cele douã tipuri de inserãri este structura de date în care se vor adãuga datele; pentru inserarea utilizatorilor se vor folosi colecții, iar pentru inserarea cãrților se va folosi un
GridFS.
Pentru inserarea utilizatorilor existã douã colecții denumite : „Administrators” și
„Students”,pentru a face posibilã inserarea în aceste colecții existã implementate trei
46
Lucrare de licențã
2013
clase: User, Student și Administrator. Clasa User a fost creatã din motive de evitare a codului duplicat, deoarece anumite caracteristici ale celor douã tipuri de utilizatori sunt comune, dupã cum urmeazã :
Din câte se observã, id-ul unui utilizator este adnotat cu @Id, acest lucru este necesar pentru ca instanța de Mongo sã-l mapeze pe câmpul document_id, care este un câmp obligatoriu.
Mai departe, în fiecare din cele douã clase Administrator și Student , s-a folosit adnotația @Document, dupã cum urmeazã:
Adnotația @Document identificã domeniul unui obiect ce urmeazã a fi persistat cãtre MongoDB, în cazul de fațã, un obiect de tipul oricãreia dintre clasele de mai sus poate fi inserat în MongoDB; precizând și colecția, nu mai este necesar ca atunci când inserãm un document sã precizãm colecția sau sã lãsãm sã se facã inserarea în colecția predefinitã.
47
Lucrare de licențã
2013
Având clasele adnotate astfel, putem realiza operații CRUD (Create Read Update
Delete). Pentru a realiza aceste operații este necesarã existența unui obiect de tipul
MongoOperations, injectat în fiecare din cele douã clase.
Acest obiect va fi declarat de forma:
Adnotația @Autowired marcheazã setter-ul pentru MongoOperations ca fiind injectat de cãtre Spring din cadrul fișierului applicationContext.xml . Adnotația @Required se folosește pentru a avea asigurarea cã MongoOperations are o instanțã validã și setatã (de aceea se aplicã pe setter).
Exemple de operații CRUD asupra instanței de MongoDB sunt:
Inserarea unui student în MongoDB se executã astfel:
Precizez cã execut o operație de verificare a unicitãții numelui de utilizator, astfel încât sã nu aparã confuzii la autentificare.
Inserarea unui administrator, se executã similar, verificându-se de asemenea unicitatea numelui de utilizator:
48
Lucrare de licențã
2013
Obținerea unui obiect de tip administrator, similar și student, dupã criteriul nume de utilizator și vârstã ale loc astfel:
Modificarea datelor unui administator (similar și student) :
Ștergerea unui cont de administrator (similar și student) :
Adãugarea unei cãrți în MongoDB, presupune existența unui GridFsTemplate configurat dupã modelul prezentat în capitolul 2; având acest GridFsTemplate configurat și injectat astfel:
, putem executa operații CRUD asupra acestuia, dupã cum urmeazã:
Inserarea unei cãrți :
49
Lucrare de licențã
2013
Parametrii acestei metode conțin urmãtoarele date:
inputStream: reține conținutul cãrții
filename: reține titlul cãrții
author: reține numele autorului
category: reține numele categoriei din care face parte cartea
Pentru a insera o carte într-un GridFS, sunt necesare urmãtoarele:
Crearea unui obiect GridFS care are referințã cãtre informațiile de conexiune la baza de date
Crearea unui obiect GridFSInputFile care va conține inputStream-ul ca fișier, filename va fi numele fișierului iar autorul și categoria vor si setate ca metadate.
salvarea chunks-urilor din GrisFSInputFile și inclusiv a acestuia
Cãutarea unei cãrți dupã nume :
50
Lucrare de licențã
2013
Pentru a cãuta o carte dupã titlu, este suficientã o interogare pe câmpul „filename”. Din câte se observã, cãutarea a fost fãcutã pe baza unei expresii regulate, deoarece s-a dorit a primi rezultate și în cazul în care titlul era incomplet.
Metoda returneazã o listã de cãrți, ale cãror detalii sunt obținute din lista de GridFSDBFile (GridFSDBFile este o clasã destinatã lucrului cu metadate și conținut din GridFS), extragându-se toate datele necesare.
Ștergerea unei cãrți pe baza id-ului:
Deoarece id-ul este unic, ștergerea se face intr-o variantã foarte simplã, eliminând din
GridFs componenta cu id-ul precizat în parametrul metodei.
3.4.1.2 GESTIONAREA DATELOR CU APACHE SOLR
Atunci când are loc inserarea unei cãrți în sistem, dupã ce este prelucratã de MongoDB, vine rândul serverului de Solr sã intre în acțiune, pentru a indexa conținutul cãrții și datele referitoare la aceasta. Acest lucru este necesar deoarece MongoDB nu deține capabilitãți suficient de dezvoltate pentru full-text search (cãutarea în conținutul documentelor).
Legãtura între entitãțile salvate în MongoDB și cele salvate în Solr este realizatã prin intermediul id-ului returnat la salvarea unui nou fișier în MongoDB, care este trimis mai departe.
Având documentul și datele despre acesta, pe serverul de Solr este realizatã o cerere de indexare a unui document.
Acest proces are loc astfel:
51
Lucrare de licențã
2013
Aceastã indexare se produce pe baza schemei prezentatã anterior, dupã cum se poate observa se instanțiazã un obiect de tipul SolrInputDocument și i se adaugã câmpurile : id, category, author, title, mongoId (toate aceste câmpuri existã precizate în schema.xml din configurarea Solr).
Solr are configurãri necesare pentru extragerea textului din conținutul unui document, așa cã s-a apelat o clasã numitã TextExtractor, ce utilizeazã un instrument denumit
Apache Tika, destinat pentru extragerea textului și a metadatelor din numeroase tipuri de fișiere.
Dependința din pom.xml este :
Utilizarea acestui instrument, pentru extragerea textului din fișierul trimis cãtre Solr se realizeazã astfel:
, unde metoda process este definitã astfel:
52
Lucrare de licențã
2013
Pe baza cãii complete și a metadatelor (atunci când este cazul) cãtre document, o instanțã de Tika, denumitã TikaInputStream extrage conținutul acestuia . Cu ajutorul unui ContentHandler și a unui Parser este parcurs tot conținutul documentului și returnat cãtre Solr.
Dupã extragerea conținutului unui document și obținerea acestuia, urmãtorul pas este setarea câmpului „text” din schema.xml cu acest conținut extras. Având toate datele necesare salvãrii indexului, documentul Solr este adãugat pe server și este realizatã o operație de commit pe server pentru a fi executate modificãrile.
Având indexarea documentelor realizatã, urmãtorul pas este interogarea indecșilor;acest pas este realizat prin intermediul metodei receiveDataFromSolr, care pe baza a doi parametrii: whatToSearch (ce anume sã se caute) și whereToSearch( în care câmp anume sã se caute), returneazã o listã de cãrți în care seteazã mongoId și un fragment de text de acolo de unde a fost gãsit cuvântul sau expresia cãutatã, în cazul în care cãutarea a fost fãcutã pe câmpul text.
Având opțiune de highlighting, acest fragment se obține pe baza unei metode numite getHighlighting, setând anterior marimea fragmentului returnat; care implicit are valoarea 1. Dacã existã astfel de fragmente, este adãugat fiecãrei cãrți, pe câmpul highlightContent primul dintre aceste fragmente.
53
Lucrare de licențã
2013
Pentru cazurile de cãutare avansatã s-a apelat la o altã caracteristicã a Solr și anume cãutarea fațetatã, adicã atunci când se dorește cãutarea dupã un anumit câmp , dar se doresc informații mai exacte, adicã ce anume existã indexat pe acel câmp și câte documente conțin fiecare dintre valorile setate pe respectivul câmp. Aceastã cãutare are loc cu ajutorul metodei receiveFacetDataFromSolr, dupã cum urmeazã:
Din câte se observã, se realizeazã o interogare de forma „*:*”, ceea ce înseamnã cã se dorește obținerea tuturor documentelor din baza de date, pe baza unui câmp de fațetare addFacetField(whereToSearch). Se returneazã o listã de șiruri de caractere, în care, pe fiecare poziție este setat numele câmpului respectiv și numãrul de valori gãsite pentru acest câmp.
54
Lucrare de licențã
2013
Pentru manipularea cãrților s-a implementat o clasã denumitã Book, cu urmãtoarele atribute:
Dintre aceste atribute sunt folsite în comun de MongoDB și de Solr urmãtoarele: autorul, titlul cãrții, categoria și mongoId-ul. Path-ul (calea) este utilizatã de Apache
Tika pentru a extrage conținutul și highlightContent este utilizat pentru a returna conținut în cazul în care cãutarea a fost fãcutã în conținut.
3.4.2 COMPONENTA CONTROLLER
Aceastã parte componentã a arhitecturii aplicației are rolul unui intermediar între Model și View.
Pentru ca o clasã sã devinã Controller este necesar sã fie adnotatã cu @Controller și sã se mapeze pe url-ul unei operații de submit din cadrul unui View sau din cadrul unui alt Controller. În cazul de fațã existã implementați 5 Controlleri ce executã și rãspund la toate cererile venite de la View, acestea sunt:
AdministratorController : acest Controller se ocupã exclusiv de operațiile executate de un administrator în contul sãu. Link-urile pe care se mapeazã cererile venite de la administrator sunt prefixate de „/administrator”. Acest controller folosește, pentru executarea operațiilor CRUD o instanțã a unei clase din Model și anume AdministratorDAO.
StudentController : acest controller se ocupã exclusiv de operațiile executate de un student în contul sãu. Link-urile pe care se mapeazã cererile venite de la un student sunt prefixate de „/student”. Acest controller folosește, pentru executarea operațiilor CRUD o instanțã a unei clase din Model și anume
StudentDAO.
55
Lucrare de licențã
2013
HomepageController : acest controller este destinat primei pagini din aplicație, unde are loc logarea utilizatorului. Prin intermediul acestui controller se face logarea corectã în funcție de tipul de utilizator. De asemenea în acest controller se executã operația de recuperare de parolã. Acest controller folosește, pentru executarea operațiilor CRUD cate o instanțã a claselor StudentDAO și AdministratorDAO din Model.
BookController : acest controller este destinat operațiilor de cãutare de cãrți în sistem și descãrcare a acestora. Aceastã cãutare are loc dupã numeroase opțiuni. Linkurile pe care se mapeazã cererile cãtre acest controller sunt prefixate de „/book”. Descãrcarea unei cãrți presupune preluarea unui InputStream din BookDao, ce cuprinde conținutul cãrții și setarea acestui InputStream pe HttpServletResponse. Pentru a fi deschisã ca .pdf este necesarã precizarea tipului de conținut, acest lucru se realizeazã astfel:
response.setContentType("application/pdf");
Pentru ca datele adãugate pe HttpServletResponse sã fie „umplut”(flush) cu respectivele date:
response.flushBuffer();
FileUploadController : acest controller se ocupã de adãugarea cãrților în sistem. A fost necesarã excluderea acestei operatii din BookController deoarece, upload-ul unui document presupune existența unui controller specific pentru acest tip de operație, precum și o configurare specialã.
Aceastã configurare presupune existența unui bean și anume:
Se observã faptul cã este necesarã precizarea unui „formView” si a unui
„successView”, aceste fiind douã fișiere .ftl care se vor afișa, prima la afișarea paginii de upload și a doua dupã ce operația a fost realizatã cu succes. De
56
Lucrare de licențã
2013
asemenea existã un validator care verificã dacã a fost adãugat document înainte de a executa operația de submit.
Operația de validare este din clasa FileUploadValidator este :
3.4.3 COMPONENTA VIEW
Aceastã componentã este însuși informația prezentatã utilizatorului. Un View este, în general, o paginã web, dar poate fi de asemenea un fragment dintr-o paginã, un header
(antet) sau un footer (subsol) pentru alte pagini.
Pentru implementarea componentei View s-a utilizat Freemarker, extensia tipului de fișiere specific este .ftl. Pentru a elimina rescrierea aceluiași cod s-au implementat un header.ftl și un footer.ftl care conțin antetul și subsolul comun tuturor paginilor.
Pagina principalã, numitã loginPage.ftl aduce utilizatorului:
57
Lucrare de licențã
2013
Aici utilizatorul se poate loga în contul sãu sau își poate recupera parola, prin resetarea acesteia, în cazul în care a uitat aceastã informație.
În funcție e tipul de utilizator, dacã este administrator sau student, dupã logare aceștia sunt redirectați cãtre pagina specificã, dupã cum urmeazã :
pagina administratorului :
Din aceastã paginã, administratorul își poate alege operația doritã a fi executatã.
pagina studentului :
58
Lucrare de licențã
2013
4. GHIDUL APLICAȚIEI
4.1 GHIDUL APLICAȚIEI- PERSPECTIVA ADMINISTRATORULUI
Dupã logarea unui administrator, el este redirectat cãtre o paginã ce prezintã opțiunile oferite de aceastã aplicație pentru respectivul tip de utilizator.
Aceste opțiuni sunt:
Deconectarea : prin intermediul acestei opțiuni, administratorul se deconecteazã de la aplicație, revenind în pagina principalã. Pentru a se reîntoarce în pagina sa, este necesarã o logare.
Creeazã cont cu drepturi depline : prin intermediul acestei opțiuni, administratorul poate crea un nou cont ce deține drepturi depline asupra gestionãrii aplicației, adicã poate șterge conturi de student, poate crea conturi de student și poate înregistra cãrți în sistem. . În cazul în care nu dorește aceastã opțiune, se poate întoarce în meniul anterior prin accearea butonului „Înapoi”. Accesarea acestei opțiuni, conduce spre pagina:
Modificã date cont : prin intermediul acestei opțiuni, administratorul își poate modifica datele înregistrate la crearea contului. În cazul în care nu
59
Lucrare de licențã
2013
dorește aceastã opțiune, se poate întoarce în meniul anterior prin accearea
butonului „Înapoi”.
Șterge-ți contul : prin intermediul acestei opțiuni, administratorul își poate șterge contul, pierzând toate informațiile salvate. Înainte de executarea acestei opțiuni, existã o paginã de confirmare a acțiunii. În cazul în care nu dorește aceastã opțiune, administratorul va alege opțiunea „Nu”, altfel va alege „Da”:
60
Lucrare de licențã
2013
Șterge cont de student : prin intermediul acestei opțiuni, administratorul poate șterge contul unui student (în cazul unei exmatriculãri, a unei sancțiuni etc), acesta nemaiputându-și accesa ulterior contul. La selectarea acestei opțiuni, va apãrea o paginã de cãutare a studentului dupã nume și prenume, aceastã paginã conține forma:
Dupã introducerea numelui și a prenumelui și apãsarea butonului „Cautã”, administratorul va fi redirectat cãtre o paginã ce conține forma:
Select-box-ul din figurã va conține datele tuturor studenților cu numele și prenumele introduse în forma de cãutare. Dupã selectarea studentului al cãrui cont de dorește a fi șters, se apasã „Șterge student” , altfel se apasã „Înapoi”.
Creeazã cont de student: prin intermediul acestei opțiuni, administratorul poate crea un nou cont de student. În cazul în care nu dorește aceastã opțiune, se poate întoarce în meniul anterior prin accearea butonului „Înapoi”. Accesarea acestei opțiuni, conduce spre pagina:
61
Lucrare de licențã
2013
Adaugã carte : prin intermediul acestei opțiuni, administratorul poate adãuga cãrți în sistem pentru a îmbogãți numãrul de cãrți din sistem. În cazul în care nu dorește aceastã opțiune, se poate întoarce în meniul anterior prin accearea butonului „Înapoi”. Accesarea acestei opțiuni, conduce spre pagina:
62
Lucrare de licențã
2013
Dupã introducerea titlului, a autorului și a categoriei, este necesar upload-ul unui document ce conține respectivele caracteristici, adãugând un fișier, pentru a fi încãrcat în sistem, trebuie apãsat butonul „Încarcã”. Se acceptã doar documente in format .pdf.
În majoritatea cazurilor, dupã apãsarea butonului, o perioadã de tip, uneori destul de îndelungatã, aplicația va fi blocatã, deoarece datele trimise din acest View ajung în Controller și de acolo sunt trimise atât cãtre MongoDB cât și cãtre Solr pentru a fi extrase toate datele necesare. Procesul de indexare a unui document de cãtre Solr este destul de costisitor ca timp. deoarece textul nu este numai parcurs, ci și analizat.
Cautã carte : prin intermediul acestei opțiuni, administratorul poate efectua operații de cãutare asupra cãrților din sistem. În cazul în care nu dorește aceastã opțiune, se poate întoarce în meniul anterior prin accearea butonului „Înapoi”. Accesarea acestei opțiuni, conduce spre pagina:
Se pot observa numeroase posibilitãți de a efectua cãutãri:
-cãutare în conținutul documentului : este cea mai complexã cãutare
și presupune cãutarea unui cuvânt sau a unei fraze în conținutul documentelor.
63
Lucrare de licențã
2013
Aceastã opțiune apare la accesarea Cautã carte, pentru a efectua o cãutare, se introduce un cuvânt(frazã) în cãsuța de lângã textul „Introduceți textul de cãutat” și se apasã „Cãutare”, pentru o situație de tipul:
, se vor afișa urmãtoarele:
Aceasta este pagina de rezultate, iar în cazul unei cautãri de tipul celei prezentate, se va afișa și un fragment din conținutul documentului, acolo unde s-a gãsit cuvântul (fraza) cãutatã. Butonul „Descãrcare”, oferã utilizatorului posibilitatea de a vizualiza sau descãrca documentul; în funcție de tipul browserului. La accesarea acestui buton, în Google Chrome se va afișa :
64
Lucrare de licențã
2013
Aceastã capturã reprezintã prima paginã a documentului returnat.
cãutare dupã titlu : acest tip de cãutare presupune introducerea în forma:
a unui titlu de carte, nu este necesarã introducerea titlului complet.
Cãutând dupã caracterul „l” în titluri, aplicația a returnat ca rezultate ale
cãutãrii:
65
Lucrare de licențã
2013
cãutare dupã autor : acest tip de cãutare presupune introducerea în forma:
a unui autor, nu este necesarã introducerea numelui complet.
Cãutând dupã caracterul „l” în numele autorilor, aplicația a returnat ca rezultate ale cãutãrii:
cãutare avansatã : prin selectarea acestui tip de cãutare, pagina în care administratorul este redirectat conține urmãtoarele opțiuni:
66
Lucrare de licențã
2013
Prin selectarea primei opțiuni, se va deschide urmãtoarea paginã:
Acest tip de cãutare afișeazã autorii existenți în sistem, alãturi de numãrul de cãrți pe care aceștia le dețin ca fiind înregistrate. Apãsând butonul de cãutare, va apãrea pagina de rezultate cu toate cãrțile scrise de autorul selectat.
Cãutarea avansatã dupã categorie va deschide o paginã de forma:
67
Lucrare de licențã
2013
Dupã selectarea categoriei dorite, și apãsarea butonului „Cãutare”, va apãrea pagina de rezultate ce va conține toate cãrțile din categoria selectatã.
4.2 GHIDUL APLICAȚIEI – PERSPECTIVA STUDENTULUI
Dupã logarea unui student, el este redirectat cãtre o paginã ce prezintã opțiunile oferite de aceastã aplicație pentru respectivul tip de utilizator.
Aceste opțiuni sunt :
Deconectarea : prin intermediul acestei opțiuni, studentul se deconecteazã de la aplicație, revenind în pagina principalã. Pentru a se reîntoarce în pagina sa, este necesarã o logare.
Modificã date cont : prin intermediul acestei opțiuni, studentul își poate modifica anumite date ale contului, mai puțin data nașterii, dupã cum urmeazã:
Figura 4.2.1
Cautã carte : aceastã opțiune oferã aceleași capabilitãți ca în cazul unui administrator, dupã cum este prezentat mai sus .
68
Lucrare de licențã
2013
5. POSIB ILITÃȚI DE DEZVOLTAR E
Folosind tehnologii relativ noi și aflate în curs de îmbunãtãțire, aceastã aplicație se poate dezvolta pentru a acoperi orice nevoie a a unui utilizator vis-a-vis de conceptul de salã de lecturã.
La momentul actual, aceastã aplicație acoperã doar funcționalitãțile de bazã ale acestui concept. Facilitãțile oferite pot fi extinse în multiple direcții, dupã cum urmeazã:
O primã îmbunãțãțire, pe care o consider necesarã pentru supraviețuirea aplicației, este posibilitatea creãrii conturilor de student în cadrul aplicației, direct de acasã, fãrã a fi
nevoie de prezentarea la sediul bibliotecii pentru validarea actelor de student.
O altă îmbunătățire la fel de necesară este introducerea unui algoritm de extragere a textului din imagini. Consider acest lucru foarte important deoarece majoritatea
cărților vechi nu există în format electronic, dar există o posibilitate de scanare e lor, pentru a putea fi introduse în sistem.
La nivel de indexare cu Solr, o îmbunãtãțire ce va fi necesarã adusã în momentul în care cantitatea de date indexate va fi destul de mare, este introducerea unor dicționare
ce vor conține: cuvinte frecvente din limba românã și alte limbi în care sunt scrise cãrțile ce urmeazã a fi indexate , sinonime și un dictionar cu sugestii ce se pot afișa în paginã.
La nivel de persistențã cu MongoDB se poate apela la scalare orizontalã în situația în care cantitatea de informație este atât de mare încat timpul de rãspuns nu mai este
favorabil.
Adãugarea unui nivel de securitate superior pentru a evita atacurile.
Adãugarea unui nivel de cache pentru a putea obține rapid rezultatele cãutãrilor cele mai frecvente.
Afișarea unor sugestii în pagina utilizatorului în funcție de cãutãrile efectuate anterior.
69
Lucrare de licențã
2013
6.ANEXE
Anexa1
6.1 INSTALAREA ȘI RULAREA SERVERULUI DE MONGODB CA SERVICIU SUB MICROSOFT WINDOWS
Instalarea și rularea serverului de MongoDB ca serviciu sub platforma Microsoft Windows presupune instalarea acestui server (“mongod.exe”) ca proces ce poate fi controlat de sistemul de operare, astfel încat serverul va porni la fiecare pornire a sistemului și se va opri la închiderea lui.
6.1.1 DESCÃRCAREA MO NGODB PENTRU WIDOWS
Descarcã ultima versiune apãrutã a serverului de MongoDB de pe pagina de descãrcare MongoDB.
Existã 3 versiuni ce pot fi descãrcate pentru Windows:
6.1.1.1 MongoDB pentru Windows Server 2008 ediția R2 , ce poate rula doar pe Windows Server 2008 R2, Windows 7 pe 64 de biți și versiunile mai noi de aceasta ale Windows-ului. Aceastã versiune are avantajul unei îmbunãtãțiri recente a platformei Windows și nu poate coopera cu versiuni mai vechi de Windows.
6.1.1.2 MongoDB pentru Windows pe 64 de biți, ce poate rula pe orice versiune de Windows pe 64 de biți, mai nouã decât Windows XP, include de asemenea , posibilitatea de instalare pe Windows Server 2008 R2 și
Windows 7 pe 64 de biti.
6.1.1.3 MongoDB pentru Windows pe 32 de biți, ce poate rula pe orice versiune de Windows pe 32 de biți, mai nouã decât Windows XP. Versiunile pe 32 de biți sunt destinate pentru sistemele vechi și pentru sistemele de testare și dezvoltare.
De reținut faptul cã trebuie descãrcatã varianta compatibilã cu sistemul de operare, deoarece versiunea pe 64 de biți nu va funcționa pe Windows pe 32 de biți.
70
Lucrare de licențã
2013
Pentru a afla arhitectura versiunii de platformã Windows folositã, se poate introduce în Command Prompt urmãtoarea comandã :
wmic os get osarchitecture
Dupã descãrcare, cautã în Windows Explorer fișierul și extrage arhiva în
C:\ . Numele folderului va fi de forma : C:\mongodb-win32-i386-[version] sau C:\mongodb-win32-x86_64-[version], unde [version] este versiunea de MongoDB descãrcatã.
6.1.2 INSTALAREA CA SERVICIU SUB WINDOWS
Instalând MongoDB ca serviciu sub Windows face ca serverul sã porneascã automat la fiecare repornire a sistemului de operare, având astfel acces la baza de date fãrã alte configurãri sau ferestre deschise în care sã rulãm serverul.
Pentru a rula MongoDB ca serviciu Windows trebuie specificate urmatoarele douã opțiuni:
6.1.2.1 Crearea unui director specific pentru log-urile MongoDB. Acest
lucru se face cu comanda :
md C:\mongodb\log
6.1.2.2 Crearea unui fișier de configurare pentru opțiunea de logpath, prin intermediul comenzii:
echo logpath=C:\mongodb\log\mongo.log > C:\mongodb\mongod.cfg
Cu aceste doua opțiuni se creeazã o locație specificã pentru salvarea fișierelor log.
Pentru a instala MongoDB ca serviciu, porniți Command Prompt cu
“Administrative Privileges” și introduceți :
71
Lucrare de licențã
2013
C:\mongodb\bin\mongod.exe –config C:\mongodb\mongod.cfg –install
Modificați mongo.cfg cu calea potrivitã cãtre acesta. Pentru ca operația – install sa reușeascã, trebuie specificat un logpath , setând –logpath ca opțiune la run-time.
Pentru a rula serviciul MongoDB folosiți urmãtoarea comandã:
net start MongoDB
6.1.3 OPRIREA SAU ȘTERGER EA SERVICIULUI MONGODB
Pentru a opri serviciul MongoDB, se folosește urmãtoarea comandã:
net stop MongoDB
Pentru a șterge serviciul MongoDB, se folosește urmãtoarea comandã:
C:\mongodb\bin\mongod.exe – remove
72
Lucrare de licențã
2013
7. BIBLIOGRAFIE
Kyle Banker –MongoDB in action , Manning, Shelter Island, 2011
David Smiley , Eric Pugh – Apache Solr 3 Enterprise Search Server
Gary Mak – Spring Recipes A Problem-Solution Approach
Baze de date NoSQL [online] :
http://martinfowler.com/nosql.html
Spring framework [online] : http://static.springsource.org/spring/docs/current/spring-framework-reference/html/
Apache Solr [online] :
http://wiki.apache.org/solr/
MongoDB [online ] : http://docs.mongodb.org/manual/
Spring Data –MongoDB [online] :
http://www.springsource.org/spring-data/mongodb
Apache Tika [online] : http://wiki.apache.org/tika/
73
BIBLIOGRAFIE
Kyle Banker –MongoDB in action , Manning, Shelter Island, 2011
David Smiley , Eric Pugh – Apache Solr 3 Enterprise Search Server
Gary Mak – Spring Recipes A Problem-Solution Approach
Baze de date NoSQL [online] :
http://martinfowler.com/nosql.html
Spring framework [online] : http://static.springsource.org/spring/docs/current/spring-framework-reference/html/
Apache Solr [online] :
http://wiki.apache.org/solr/
MongoDB [online ] : http://docs.mongodb.org/manual/
Spring Data –MongoDB [online] :
http://www.springsource.org/spring-data/mongodb
Apache Tika [online] : http://wiki.apache.org/tika/
Copyright Notice
© Licențiada.org respectă drepturile de proprietate intelectuală și așteaptă ca toți utilizatorii să facă același lucru. Dacă consideri că un conținut de pe site încalcă drepturile tale de autor, te rugăm să trimiți o notificare DMCA.
Acest articol: Sala de Lectura Online (ID: 146444)
Dacă considerați că acest conținut vă încalcă drepturile de autor, vă rugăm să depuneți o cerere pe pagina noastră Copyright Takedown.
