Solutii Actuale In Vederea Culegerii Si Agregarii Automate A Datelor

SOLUȚII ACTUALE ÎN VEDEREA CULEGERII ȘI AGREGĂRII AUTOMATE A DATELOR

Introducere

Internetul a avut un impact puternic asupra vieții noastre încă din 1990. Având în vedere creșterea rapidă și succesul la sursele de date publice, World Wide Web, este tot mai atractiv pentru a extrage informații din aceste surse și a le face disponibile pentru prelucrarea automată ulterioară de către aplicații. Datele culese de pe site-urile Web se pot utiliza pentru o varietate de funcționalități, precum procesarea analitică online (business intelligence), crearea unor statistici, monitorizarea evenimentelor și comerț electronic. Extragerea datelor structurate din site-uri Web nu este o sarcină ușoară. Majoritatea informațiilor de pe Internet sunt sub formă de documente HTML (Hypertext Markup Language) care sunt vizualizate cu ajutorul unui browser și sunt scrise de mână sau cu ajutorul unor programe specifice. Având în vedere că formatul de documente HTML este conceput pentru scopuri de prezentare, cea mai mare parte a conținutului HTML este scrisă într-un mod nestructurat, culegerea datelor din aceste documente putând fi comparată cu extragerea informațiilor din datele nestructurate.

În această lucrare sunt prezentate soluții pentru culegerea automată a informațiilor, descrierea procesului de extragere a datelor, agregarea acestora și evidențierea acestui proces printr-o aplicație Web bazată pe framework-ul Spring, în particular pentru site-urile cu anunțuri de mașini. Ideea principală constă în procesul de extragere și de prelucrare al informațiilor dorite cu ajutorul unui parser Web asupra unor site-uri specificate, verificarea și adăgarea acestora în baza de date pentru realizarea unor statistici despre piața actuală. Datele privind indicarea site-urilor și a informațiilor sunt într-un format semistructurat, fiind conținutul unor documente XML (Extensible Markup Language).

În primul capitol, sunt prezentate conceptele framework-ului Spring și tehnologiile utilizate pentru construirea aplicației Web. Acest capitol oferă de asemenea o descriere a noțiunilor de bază ale limbajului Java și avantajele folosirii platformei Java. Sunt explicate concepte precum programarea asincronă, modelul arhitectural Model-View-Controller și injecția de dependențe folosită de framework-ul Spring.

În al doilea capitol, sunt definite datele semistructurate, precum XML și HTML, urmate de descrierea unor procese diferite pentru culegerea informațiilor.

Lucrarea se termină firesc cu un capitol dedicat aplicației care fructifică în mod practic toate aspectele teoretice și conceptele prezentate în capitolele anterioare și oferă un ghid de utilizare al funcționalităților, urmat de concluzii, bibliografie și anexa cităriilor.

Spring

Aspecte avansate ale limbajului de programare Java

Java este cu siguranță unul dintre cele mai bune și mai populare limbaje de programare, în special pentru aplicațiile web. Java nu este doar un limbaj, ci și o platformă de lucru lansată pe piață de către corporația Sun Microsystems (care a fost preluată de Oracle Corporation în 2010) în anul 1995. Platforma Java include o bibiotecă standard care conține o colecție foarte amplă de componente reutilizabile și un mediu de execuție care oferă servicii cum ar fi securitatea și portabilitatea peste sistemele de operare. [6]

Avantajele limbajului de programare Java

Limbajul de programare de nivel înalt, Java, a fost descris în „White Paper” prin următoarele caracteristici:

Simplu – Conceptele fundamentale ale tehnologiei Java pot fi înțelese rapid și fără pregătiri ample de către programatori;

Orientat pe obiect – Metodologia orientata pe obiect este o modalitate de a vedea componentele software si relațiile lor. Aceasta se bazează pe trei caracteristici: încapsulare , polimorfism și moștenire;

Distribuit – Java este distribuit deoarece permite utilizatorilor rularea unui program pe două sau mai multe computere într-o rețea. Aplicațiile Java pot deschide și accesa obiecte de pe internet prin intermediul adreselor URL cu aceeași ușurință precum accesarea unui sistem de fișiere local;

Robust – Limbajul Java este proiectat pentru a crea un software extrem de fiabil; Acesta pune accept pe tratarea excepțiilor și verificarea erorilor, oferind doua nivele de verificare: verificarea la compilare, urmată de verificarea la rulare. Din punctul de vedere al administrării de memorie este foarte simplu, obiectele fiind create prin operatorul new. Colectarea reziduurilor este automată, iar programatorul nu este nevoit să declare pointeri, astfel încât se elimină posibilitatea suprascrierii memoriei;

Sigur – Java este proiectat pentru a putea fi folosit în mediile distribuite, prin urmare securitatea este foarte importantă. Aplicațiile scrise în limbajul Java sunt protejate prin diferite mecanisme de coduri malițioase care încearcă să obțină accesul în fișierele de sistem;

Neutru arhitectural – Acest format a fost conceput pentru a transporta cod în mod eficient către mai multe platforme hardware și software. Astfel, tehnologia Java rulează pe orice sistem ce are implementată Java Virtual Machine, rezolvând problema distribuției binare;

Portabil – Neutralitatea arhitecturii este doar o parte a unui sistem portabil. Java precizează dimensiunile tipurilor de date primitive și comportamentul operatorilor aritmetici, eliminând, astfel, dependența de implementare;

Interpretat – Interpretorul Java poate executa cod mașină translatat direct pe orice sistem care are o mașină virtuală Java;

Performant – Platforma Java atinge performanțe superioare prin adoptarea unui sistem prin care interpretorul poate rula la viteză maximă. Colectarea automată de obiecte si date neutilizate asigură disponibilitatea memoriei atunci când aceasta este necesară, astfel aplicațiile Java devin mai performante;

Concurent – Java este un limbaj de programare concurent (multithreaded) ceea ce înseamnă că putem dezvolta programe concurente folosind Java. Un program concurent conține două sau mai multe părți care pot rula simultan și fiecare parte se poate ocupa de diferite sarcini în același timp , optimizând utilizarea pentru resursele disponibile;

Dinamic – Java poate fi adaptat la un mediu în schimbare. Acesta este dinamic în etapa de editare a legăturilor, clasele fiind încărcate doar când sunt necesare, chiar și în cadrul unei rețele. [11]

Programarea orientată pe obiecte

Limbajele de programare orientate pe obiecte sunt definite printr-o colecție mică de proprietăți: încapsularea, abstractizarea, moștenirea și polimorfismul. Dacă aceste principii nu pot fi implementate, atunci platforma folosită nu este orientată pe obiecte. Un obiect este o entitate independentă care poate să fie tratată izolat față de celelalte obiecte. Acesta poate să fie trimis și returnat din diferite proceduri, poate să fie atribuit variabilelor și stocat în structuri de date precum liste, mulțimi și dicționare. Fiecare obiect are o identitate care este diferită de toate celelalte și poate să conțină alte obiecte care la rândul lor sunt compuse din atribute și metode ce caracterizează o anumită categorie de obiecte. Utilizatorul are întotdeauna posibilitatea de a determina dacă două obiecte sunt identice sau diferite.

Încapsularea

Principiul încalpsulării se definește prin ascunderea datelor. Încapsularea se referă la ascunderea datelor și a implementării unui obiect într-o clasă, astfel încât doar interfața obiectului încapsulat este vizibilă, detaliile interne fiind invizibile și nu pot fi accesate. Astfel, o clasă își poate schimba tipul unui atribut, iar utilizatorii clasei nu sunt nevoiți să schimbe nimic în restul codului. Obiectele din limbajele de programare orientate pe obiecte conțin date asociate cu ele care le definesc, și pot avea control absolut asupra datelor respective. [17]

public class Utilizator{

private String nume;//se încapsulează și se ascunde numele utilizatorului

public String getNume(){

return nume;

}

public void setNume(String numeNou){

nume = numeNou;

}

}

Abstractizarea

Abstractizarea surprinde numai detaliile despre un obiect care sunt relevante pentru perspectiva respectivă. În programarea orientată pe obiecte, abstractizarea este administrată de obiectele bine definite și de clasificarea lor ierarhică, unde clasele părinte sunt mai simple sau mai generale și au o implementare abstractă, iar subclase sunt definite și implementate mai detaliat precum ilustrează figura 1.1.1. Programatorii utilizează abstractizarea pentru a descompune sistemele complexe în componente mai mici și mai simple folosind principiul încapsularii.

Moștenirea

Ideea principiului de moștenire este că se pot crea clase noi pornind de la definiții de obiecte deja existente. Când se moștenește o clasă existentă, metodele și atributele clasei existente se pot reutiliza și se pot adăuga noi proprietăți pentru a adapta noua clasă. Această tehnică este fundamentală în limbajul de programare Java. [6]

Figura 1.1.1 Diagrama moștenirii pentru clasa Utilizator și subclasele sale

Conform unei interpretări a conceptului programării orientate pe obiecte, obiectele sunt definite prin descrieri, iar o descriere poate să fie folosită de mai multe ori pentru a crea obiecte individuale. Descrierea este exprimată în termeni de proprietăți ale obiectelor. Modul în care funcționează principiul moștenirii pentru limbajul Java, este prin crearea descrierilor pornind de la alte descrieri. Când o descriere nouă este creată din definiția unei descrieri vechi, , atunci proprietățile definite în devin accesibile în mod automat pentru . În acest caz, putem spune că este moștenită de către . Astfel, orice obiect creat prin moștenirea descrierii , va avea proprietățile definite în . [17]

public class Administrator extends Utilizator{

private String adresa;

public void setAdresa(String adresaNouă){

adresa = adresaNouă;

}

}

Polimorfismul

Polimorfismul este un concept important esențial în programarea orientată pe obiecte utilizat pe scară largă în limbajul Java, dar și în alte limbaje de programare și constă în abilitatea unui obiect de a lua mai multe forme. Cea mai utilizată formă a polimorfismului în programarea orientată pe obiecte se realizează când referința unei clase părinte este folosită pentru a referi o subclasă a acesteia.

Pentru a demonstra catacteristicile polimorfismului se extinde clasa Animal cu următoarele două clase: Câine, respectiv Pisică și se suprascrie metoda toString(). După cum se poate observa în exemplul de mai jos, aceeași metodă poate executa acțiuni diferite.

public class Animal {

public void toString()

{

System.out.println("Clasa părinte");

}

}

class Câine extends Animal{

public void toString()

{

System.out.println("Latră");

}

}

class Pisică extends Animal{

public void toString()

{

System.out.println("Miaună");

}

}

public class TestPolimorfism

{

    public static void main(String[] args) {

        Animal pisică = new Pisică();

        pisică.toString(); //Afișează Miaună

        Animal câine = new Câine();

        câine. toString (); //Afișează Latră

    }

}

Programarea concurentă

Un program concurent conține două sau mai multe fire de execuție (thread-uri) care se execută simultan și lucrează împreună pentru a efectua mai multe secvențe de cod optimizând utilizarea pentru resursele disponibile, mai ales atunci când calculatorul are mai multe procesoare. Java oferă o clasă java.lang.Thread, prin urmare programele concurente Java sunt orientate pe obiecte. Când un program este executat, sistemul de operare creează un proces care conține codul și datele programului și gestionează procesul până când se termină programul. [25]

Prin definiție, multitasking este atunci când mai multe procese partajează resurse de procesare comune, cum ar fi un procesor. Programarea concurentă extinde ideea de multitasking prin apariția unor System.out.println("Latră");

}

}

class Pisică extends Animal{

public void toString()

{

System.out.println("Miaună");

}

}

public class TestPolimorfism

{

    public static void main(String[] args) {

        Animal pisică = new Pisică();

        pisică.toString(); //Afișează Miaună

        Animal câine = new Câine();

        câine. toString (); //Afișează Latră

    }

}

Programarea concurentă

Un program concurent conține două sau mai multe fire de execuție (thread-uri) care se execută simultan și lucrează împreună pentru a efectua mai multe secvențe de cod optimizând utilizarea pentru resursele disponibile, mai ales atunci când calculatorul are mai multe procesoare. Java oferă o clasă java.lang.Thread, prin urmare programele concurente Java sunt orientate pe obiecte. Când un program este executat, sistemul de operare creează un proces care conține codul și datele programului și gestionează procesul până când se termină programul. [25]

Prin definiție, multitasking este atunci când mai multe procese partajează resurse de procesare comune, cum ar fi un procesor. Programarea concurentă extinde ideea de multitasking prin apariția unor aplicații individuale care vor rula mai multe task-uri în același timp. Fiecare task este de obicei numit fir de execuție (thread), care este prescurtarea de la fir de execuție de control (thread of control). Programul care rulează mai multe fire de execuție se numește program concurent. Diferența dintre procese și fire de execuție este foarte importantă și este că în timp ce fiecare proces are un set complet de variabile proprii și rulează independent și izolat de alte procese, firele de execuție pot accesa datele partajate având propria lor stiva de apel. [7]

Firul de execuție

Un fir de execuție este o unitate de control într-un proces. Când un fir de execuție rulează, execută o funcție în program. Un fir de execuție trece prin mai multe etape în ciclul său de viață, iar acestea sunt ilustrate în figura 1.1.2. Procesele asociate unui program care rulează, încep cu un fir de execuție, numit firul de execuție principal (main thread), care execută funcția principală a programului. Într-un program concurent, firul de execuție principal creează alte fire de execuție, care, la rândul lor, execută alte funcții și pot crea alte fire de execuție. O variantă de a defini un fir de execuție este prin moștenirea clasei java.lang.Thread. Metoda run() conține codul ce va fi executat. A doua variantă de definire este prin implementarea interfeței Runnable, ceea ce înseamnă că va trebui implementată metoda run(). Folosirea unui obiect Runnable în definirea metodei run() este mai avantajoasă decât moștenirea clasei Thread. Din moment ce o clasă Java nu poate moșteni mai mult de o clasă, iar implementarea interfeței Runnable este suficientă și nu este nevoie de a extinde clasa Thread, înseamnă că se poate moșteni o altă clasă.

Firele de execuție Java pot fi asignate după prioritate, ceea ce afectează selectarea acestora pentru execuție, iar executarea metodei sleep() forțează o schimbare de context, oferindu-i unui alt fir de execuție șansa de a fi executat.

Figura 1.1.2 Etapele ciclului de viață al unui fir de execuție

Fiecare fir de execuție are propria stivă de apel și propria memorie cache, inclusiv indicatorul stivă. Într-un proces concurent, firele de execuție își partajează datele, codul, resursele și spațiul de adresă al procesului. [25]

Avantajele programării concurente

Programarea concurentă face ca interfața grafică să fie mai receptivă. Firul de execuție care se ocupă de evenimentele GUI, cum ar fi click-urile pe un buton, poate crea fire de execuție suplimentare pentru a efectua task-uri de lungă funcționare, ca răspuns la evenimentele respective. Framework-ul servleturilor este proiectat să se ocupe de toată infrastructura implementării unei aplicațiilor web și de prelucrarea cererilor clienților HTTP de la distanță. Fiecare servlet reprezintă o componentă de logică a aplicației, și în aplicații web mari, mai mulți clienți pot solicita serviciile aceluiași servlet în același moment. Specificațiile servletului solicită ca un servlet să fie pregătit să fie apelat simultat de mai multe fire de execuție. [5]

Programarea concurentă își poate mări performanța prin programarea paralelă. Un program care folosește două procesoare va rula de două ori mai repede. Programarea concurentă are câteva avantaje în comparație cu procesele multiple, precum faptul că firele de execuție se administrează mai ușor , iar comunicarea prin intraprocese cu fire de execeție este mai ieftină decat cea cu procese.

Principalul dezavantaj al programelor concurente este că sunt dificile de dezvoltat. Acestea conțin adesea erori care sunt greu de găsit și de reparat. Dar când sunt utilizate corespunzător, firele de execuție pot reduce cantitatea de cod și costurile mentenanței și îmbunătățesc performanța aplicațiilor complexe. [25]

Introducere în Spring Framework

Spring Framework este o platformă gratuită și importantă de dezvoltare a aplicațiilor Java Enterprise, care face dezvoltarea pe platforma Java/J2EE mai ușoară și mai productivă. Deși a fost creat pentru a aborda complexitatea cererii aplicațiilor Enterprise, Spring oferă servicii ce pot fi utilizate în orice aplicație bazată pe limbajul Java, precum accesul de la distanță folosind RMI (apelarea metodelor la distanță) sau servicii web, mesageria, posibilitatea de a folosi administrarea de tranzacții, diferite opțiuni în persistența datelor, securitatea și multe altele. Partea ușoară a dezvoltării nu se referă neapărat la numărul de clase sau mărimea distribuției care poate să fie un singur fișier de aproximativ 1 MB, ci mai degrabă, definește principiul framework-ului Spring în ansamblu, care este, un impact minim. Spring este ușor, în sensul că trebuie să se facă puține modificări în codul aplicației pentru a putea beneficia de avantajele oferite. Spring oferă un Framework specializat în crearea aplicațiilor web orientat pe principiul cerere/răspuns, numit Spring MVC (Model-View-Controller), modalități transparente de a integra AOP (programare orientată pe aspecte) și o ierarhie bine structurată ce include maparea automată. [26]

Containerul Spring

Containerul Spring oferă o locație centrală pentru accesarea, configurarea și administrarea componentelor, numită Contextul aplicației (Application Context). Într-o aplicație pot exista mai multe locații de acest tip, care pot fi configurate prin folosirea adnotărilor Java sau prin fișiere XML ce conțin obiectele Spring administrate, descrise printr-o sintaxă XML unică.

Inversia Controlului

Containerul IoC (Inversia controlului), numit, de asemenea, containerul de bază, este responsabil pentru configurarea și crearea de obiecte în Spring și pentru rezolvarea dependențelor dintre bean-uri. În cele mai multe cazuri, atunci când un obiect are nevoie de o dependență, face o căutare sau recuperare de la un depozit de date extern. Elementele administrate de IoC sunt, de obicei, obiecte standard ale limbajului Java (POJO). Acestea sunt clase Java simple care nu implementează interfețe speciale sau extind alte clase de bază și nu știu containerul în care sunt rulate deoarece sunt configurate folosind principiul IoC. Acest lucru înseamnă că obiectele sunt create, scrise și administrate de container, și nu de programatori prin cod Java, ceea ce ușurează scrierea de cod, reutilizarea și testarea codului. [8]

Injecția de Dependențe

Spring Framework utilizeaza Injecția de dependențe (Dependency Injection – DI) pentru a realiza obiectivele containerului IoC. Obiectele Spring bean sau POJO își declară atributele cu metodele de setare (set) și obținere (get) sau prin constructori, care au grijă să primească dependențele necesare. Injecția de dependențe este realizată în momentul în care Spring creează contextul și se folosește de adnotări sau fisiere XML pentru a determina ce obiecte trebuie instanțiate sau injectate, adică ce obiecte trebuie create și ce metode trebuie apelate. În aceste fișiere sau adnotări trebuie să existe toate definițiile obiectelor folosite în contextul aplicației. Când un obiect referă un alt obiect prin definirea lui ca și un bean, descrierea acestuia din adnotări sau din fișierul XML are o referință către obiectul utilizat. Când contextul aplicației este inițializat, Spring găsește această descriere, instanțiază obiectul și îi setează atributele. Astfel, programatorului îi este permis să intervină și să modifice bean-ul, fără a fi nevoie să se recompileze aplicația prin schimbarea obiectului în fișierul XML, atât timp cât obiectul dependent implementează aceeași interfață. De exemplu, obiectul de acces la date, DAO, folosește baza de date relațională PostgreSQL și se dorește schimbarea acesteia cu Oracle. Prin utilizarea injecției de dependențe se poate reconfigura foarte ușor dependența obiectului business pentru a folosi implementarea Oracle.

Avantajele Injecției de Dependențe

Posibilitatea de a schimba dependențele unui bean fără a modifica codul existent, oferită de Spring Framework, facilitează testarea componentelor folosind teste pe unitate. Considerăm un obiect business ce efectuează prelucrări de date complexe prin utilizarea unui obiect DAO. În abordarea tradițională, unde obiectul business este responsabil pentru obținerea instanței obiectului de acces la date, tranzacția este dificil de testat datorită faptului că nu se poate schimba ușor implementarea obiectului DAO cu o implementare mock ce returnează seturile de date pentru test. În schimb, trebuie să ne asigurăm că datele din baza de date pentru testare sunt corecte și testele acoperă toate metodele din DAO. Prin utilizarea injecției de dependențe, se poate crea implementarea mock a obiectului de acces la baza de date ce îi returnează obiectului business seturile de date pentru testare. Acest mecanism poate fi extins pentru a testa orice nivel al aplicației și este foarte util în special în ceea ce privește testarea componentelor web unde se pot crea implementări mock ale interfețelor HttpServletRequest și HttpServletResponse. [26]

Unul dintre cele mai mari avantaje ale injecției de depentențe este abilitatea de a reduce codul pentru a integra toate componentele unei aplicații. Totuși, lucrurile devin mai complicate când avem nevoie să căutăm dependențele în JNDI (The Java Naming and Directory Interface) repository sau când dependețele nu pot fi apelate direct, cum ar fi resursele de la distanță. În aceste cazuri, injecția de dependențe simplifică integrarea fără a mai fi nevoie de alte setări. Spring oferă un proxy pentru obiectele la distanță, suport pentru RMI, JNDI, HTTPInvoker prin împachetarea obiectului inițial.[26]

Spring POA

Programarea orientată pe aspecte (POA) este o tehnologie importantă ce rezolvă o varietate de probleme întâlnite de programatori. În timp ce inversia de control face posibilă integrarea componentelor, programarea orientată pe aspecte permite utilizatorilor să implementeze funcționalitatea ce este utilizată în întreaga aplicație în componente reutilizabile. Framework-ul POA oferă servicii enterprise declarative ce completează utilitatea programării orientate pe obiecte. Pentru a păstra arhitectura Spring, caracteristicile POA sunt separate de containerul inversiei de control și prin urmare utilizatorii nu sunt obligați să folosească această tehnologie. Totuși, majoritatea utilizatorilor aleg să o folosească deoarece permite separarea nivelelor de servicii business și de tranzacții într-o manieră elegantă și transparentă prin adnotări.[27]

Spring oferă posibilitatea de a implementa programarea orientată pe aspecte în doua variante: prin framework-ul intern, Spring POA, ce include o implementare riguroasă în care obiectele sunt împachetate cu un proxy dinamic; și prin folosirea adnotărilor AspectJ din framework-ul POA. Întrucât adnotările AspectJ sunt suportate de un număr mare de cadre POA, aspectele AspectJ folosite au să rămână cel mai probabil nemodificate peste alte cadre POA ce suportă AspectJ. [13]

Concepte POA

Ca și în cele mai multe tehnologii, POA are propriul set specific de concepte și termeni. Aspectele sunt adesea descrise în termenii: advice, pointcuts, joinponts. Figura 1.2.1 ilustrează integrarea acestor concepte. Următoarea lista explică principalele concepte ale programării orientate pe aspecte:

Joinpoint-uri – Un joinpoint este un punct bine definit în timpul execuției aplicației. Apelarea unei metode, inițializarea unei clase, instanțiarea unui obiect sunt exemple tipice ale unui joinpoint. Joinpoint-ul este un concept principal și definește punctul în care se poate adăuga logica suplimentară folosing POA;

Figura 1.1.2.1 Funcționalitatea unui aspect

Advice (Înștiințare) – Codul care este executat într-un anumit joinpoint se numește advice. Sunt mai multe tipuri de advice, precum before, care se execută înaintea unui joinpoint, after, care se execută după un joinpoint și around, unde codul este executat înainte și după joinpoint-uri;

Pointcut-uri – Un pointcut este o colecție de joinpoint-uri folosită pentru a defini momentul în care un advice ar trebui executat. Prin crearea pointcut-urilor, crește controlul asupra aplicării advice-ului componentelor din aplicație. Așa cum este menționat mai sus, un joinpoint reprezentativ este invocarea unei metode. Un pointcut este format din toate invocările metodelor dintr-o anumită clasă;

Aspect – Un aspect este o combinație de advice-uri și pointcut-uri. Această combinație rezultă prin definirea logicii ce ar trebui să fie inclusă în aplicație și unde ar trebui să fie executată;

Weaving – Acesta este procesul în care se inserează aspectele în codul aplicației într-un anumit punct. Integrarea se poate face la compilare folosind Aspectj sau la execuție, unde se face distincția între obiectele aplicației și aspecte;

Target – Un obiect de tipul target este obiectul al cărui flux de execuție este modificat de un anumit proces POA. De multe ori acest obiect este denumit advised;

Introduction – Acesta este procesul în care se modifică structura unui obiect prin introducerea unor metode sau atribute adiționale. [26]

Suportul POA din interiorul framework-ului Spring

Suportul POA din interiorul framework-ului Spring are loc în patru moduri:

Proxy bazat pe POA din Spring;

Aspecte POJO;

Aspecte bazate pe adnotări @AspectJ;

Aspecte injectate AspectJ.

Primele trei moduri enumerate sunt variante ale implementării programării orientate pe aspecte oferite de Spring. Obiectele din POA Spring sunt împachetate cu un proxy dinamic, prin urmare metodele de interceptare sunt limitate.

Cu namespace-ul aop din Spring, obiectele de tipul POJO se pot transforma în aspecte, dar vor suporta doar metodele care sunt apelate în reacție la un pointcut. Această tehnică se configurează prin XML și este o modalitate ușoară ca orice obiect să fie transformat declartiv într-un aspect.

Spring împrumută aspectele AspectJ pentru a permite adnotările specifice POA. În spate, rămâne tot proxy-ul din Spring, dar modelul de programare este aproape identic cu aspectele adnotate din AspectJ. Avantajul acestei tehnici este că se poate realiza fără configurările XML.

Dacă într-o aplicație este necesară depășirea unei simple metode de interceptare, atunci va fi nevoie implementarea aspectelor în AspectJ. Astfel, se vor injecta valori în aspectele AspectJ.

Toate advice-urile create în Spring sunt scrise în clase Java standard. Prin urmare, se obține avantajul de a programa aspectele în același mediu de dezvoltare (IDE). Pointcut-urile definite unde un advice ar trebui să fie aplicat pot să fie configurate în fișiere XML sau să fie specificate prin adnotări.

În Spring, aspectele sunt integrate (woven) în bean-urile administrate de Spring la compilare, împachetate cu un proxy. Așa cum este ilustrat în figura 1.2.2, clasa proxy se prezintă ca un bean de tipul target, interceptează apelurile metodelor și le trimite mai departe către obiectul de tipul target. După ce proxy-ul interceptează apelurile respective și înainte de a invoca metoda bean-ului de tipul target, acesta efectuează logica aspectului. Spring nu creează obiecte proxy până în momentul în care aplicația are nevoie de ele. [10]

Spring MVC

Spring MVC este un framework ce ajută la integrarea arhitecturii web MVC. Este utilizat pentru a administrara starea, validarea și fluxul de lucru al aplicației. Integrarea Spring MVC cu Servlet API a făcut mai ușoară administrarea cererilor web. Nivelul Spring Web MVC este proiectat astfel încât sa ofere suport pentru cât mai multe tehnologii, precum paginile JavaServer (JSP), AngularJS, Velocity și multe altele. Un avantaj al utilizării framework-ului Spring MVC cu alte aplicații Spring ar fi faptul că se pot injecta alte bean-uri în obiectele de tipul controller din Spring MVC. [8]

Arhitectura MVC

Modelul arhitectural MVC (Model-View-Controller) are scopul de a separa diferite aspecte ale aplicației, mai exact izolarea logicii business față de considerentele interfeței cu utilizatorul, în trei tipuri de obiecte:

Model – Obiectele de tipul model încapsulează datele aplicației fiind, în general, obiecte POJO sau JavaBeans;

View – Acestea sunt responsabile pentru randarea modelelor și exprimarea ultimei forme a datelor: interfața grafică ce interacționează cu utilizatorul final;

Controller – Obiectele de tipul controller răspund acțiunilor luate de utilizatori, precum executarea unei forme sau faptul că a dat click pe un link. Acestea sunt responsabile pentru procesarea informațiilor reprezentate de modele sau alte obiecte și trimiterea acestora către view.[27]

Conceptele Spring MVC

Din momentul în care Spring primește o cerere (request) până când un răspuns este trimis la client, sunt implicate mai multe părți din framework-ul Spring MVC. Figura 1.2.3 prezintă ciclul de viață al unei cereri de la început până la sfârșit.

Procesul începe în momentul în care un client, mai exact un browser, trimite o cerere (1). Cererea conține cel puțin adresa URL cerută, dar mai poate include date adiționale, precum informațiile adăugate în formă de către utilizator. Prima componentă care primește această cerere este servletul DispatcherServlet. Spring MVC este construit in jurul servletului DispatcherServlet care manipulează cererile si răspunsurile HTTP.

Servletul DispatcherServlet are datoria să trimită mai departe cererea primită către un controller. Un controller este o componentă Spring care procesează cererea. Dar având în vedere că o aplicație poate avea mai multe obiecte de tipul controller, DispatcherServlet are nevoie de ajutor pentru a putea decide cărui controller să îi trimită cererea. Servletul consultă HandlerMapper (2) pentru a-și da seama care este controller-ul potrivit ce trebuie apelat și trimite cererea.

Controller-ul preia cererea (3) și apelează serviciile necesare unde se procesează informațiile. De cele mai multe ori, logica efectuată de servicii rezultă în informații ce trebuie trimise înapoi la utilizator și afișate in browser într-o manieră prietenoasă, de obicei în formatul HTML. Pentru această parte, informația trebuie să ajungă în view, care este de obicei o pagină JSP (JavaServer Page).

Controller-ul împachetează datele modelului, identifică denumirea view-ului unde ar trebui să fie afișată informația și apoi trimite cererea împreună cu modelul și cu numele view-ului înapoi la servletul DispatcherServlet (4). Denumirea view-ului nu specifică direct o pagină JSP și nu e necesar nici să sugereze că acel view e o pagină JSP, în schimb, conține o denumire logică ce va fi folosită pentru a căuta view-ul real ce va afișa răspunsul.

Servletul DispatcherServlet consultă un view resolver (5) pentru a mapa denumirea logică de implementarea view-ului, care este de obicei o pagină JSP, iar apoi transmite modelul către componenta view (6), care la rândul ei, randează modelul pentru browser (7). [10]

Concepte avansate ale framework-ului Spring

Spring Security

Securitatea aplicației are scopul de a controla accesul funcționalităților din aplicație. Conceptele generale ale securității sunt:

Autentificarea – Procesul de verificare al identității prezentate;

Autorizarea – Procesul identificării funcționalității permise pentru un utilizator autentificat.

Spring Security este un framework ce oferă securitate declarativă pentru aplicațiile Spring. Acesta oferă o soluție de securitate completă, manipulează autentificarea și autorizarea atât la nivelul cererii web cât și la nivelul invocării metodelor. Bazat pe framework-ul Spring, Spring Security preia toate avantajele injecției de dependențe (DI) și tehnicile orientate spre aspecte. [10]

Componentele Spring Security

Spring Security extinde conceptul Java standard de securitate al unui principal autentificat (java.security.Principal), care este folosit pentru a reprezenta o entitate unică. În cele mai multe cazuri, cu ajutorul lui Spring Security, un principal reprezintă un singur utilizator.

Framework-ul Spring Security este împărțit în mai multe componente:

SecurityContextHolder –este obiectul fundamental. Aici este locul unde se stochează detaliile contextului de securitate, care includ detaliile principalului (utilizatorului curent) al aplicației;

SecurityContext – este folosit pentru a reține obiectul Authentication și posibilele cereri despre detaliile securității;

Authentication – este folosit pentru a reprezenta obiectul Principal într-o manieră specifică Spring Security;

GrantedAuthority – este o autoritate ce se acordă obiectului Principal. Aceste autorități sunt de obicei roluri, precum ROLE_USER sau ROLE_ADMINISTRATOR. Obiectele GrantedAuthority sunt de obicei încărcate de către UserDetailsService;

UserDetails – oferă informațiile necesare pentru a crea un obiect Authentication din DAO-urile aplicației sau alte surse de date. Acesta este un obiect central al framework-ului Spring Security și reprezintă un Principal, dar într-un mod extins și specific al aplicației;

UserDetailsService – este folosit pentru a crea un obiect UserDetails în momentul când este obținut username-ul utilizatorului. [12]

Autentificare

Autentificarea în Spring Security este un proces ce se desfășoară în mai mulți pași:

Username-ul și parola sunt obținute și adăugate într-o instanță UsernamePasswordAuthenticationToken (o instanță a obiectului Authentication);

Obiectul este trimis mai departe pentru validare către o instanță a interfeței AuthenticationManager;

AuthenticationManager returnează instanța Authentication complet populată în momentul autentificarii cu succes;

Contextul securității este stabilit prin apelarea SecurityContextHolder.getContext() .setAuthentication(…) care este reținut în obiectul autentificat. [12]

Autorizare

Autorizarea implică două aspecte separate ce descriu accesibilitatea unui sistem securizat. Primul aspect este maparea unei autorități(sau mai multe) principalului autentificat. De exemplu, un utilizator simplu poate avea rolul USER_ROLE, iar administratorul poate avea autoritatea ADMINISTRATOR_ROLE. Al doilea aspect implică verificarea resurselor autorizate ale sistemului pe baza autorităților. De exemplu, partea de administrare a aplicației ar trebui să fie disponibilă doar utilizatorilor cu rolul de administrator.

Filtrul FilterSecurityInterceptor este responsabil pentru decizia dacă cererea primită este acceptată sau respinsă. În acest punct, obiectul Principal este autentificat, prin urmare sistemul știe dacă utilizatorul este valid. Obiectul Authentication specifică o metodă getAuthorities() ce returnează lista de autorități a obiectului Principal. Procesul de autorizare utilizează informația oferită de această metodă pentru a determina dacă o anumită cerere ar trebui respinsă sau nu.

Interfața responsabilă pentru deciziile de acces în Spring Security este AccessDecisionManager. Aceasta specifică două metode simple și logice care au un rol în procesarea deciziei unei cereri. Prima metodă este supports, ce cuprinde de fapt două metode care permit implementarea interfeței AccessDecisionManager pentru a raporta dacă cererea curentă este suportată sau nu. A doua metodă, decide, îi permite interfeței AccessDecisionManager să verifice dacă ar trebui să permită accesul și să accepte cererea. Această metodă nu returnează nimic, dar, în schimb, raportează refuzarea cererii prin aruncarea unei excepții ce indică faptul că cererea a fost respinsă. [23]

Log Out

Așa cum era de așteptat, funcționalitatea de logout este deja implementată prin filtrul LogoutFilter, care în mod implicit interceptează cererile la URL-ul „/j_spring_security_logout”, dar care poate să fie modificat.

<security:logout logout-success-url="/home" logout-url="/logout" invalidate-session="true"/>

Atributul logout-success-url indică URL-ul la care Spring Security ar trebui să redirecteze dacă cererea a fost rezolvată cu succes. Al doilea atribut, logout-url, indică URL-ul care ar trebui să fie interceptat de către filtrul LogoutFilter. Ultimul atribut indică dacă sesiunea HTTP să fie invalidată sau nu. Dacă aceasta este setată cu valoarea „false”, atunci doar org.springframework.security.core.context.SecurityContext devine invalid, iar sesiunea HTTP rămâne validă. [23]

Trimiterea unui E-Mail cu Spring

Trimiterea unui e-mail este o necesitate tipică pentru foarte multe tipuri de aplicație, iar Spring oferă un API (interfețe pentru programarea de aplicații) de nivel înalt simplificat pentru această funcționalitate.

Javamail și Spring

Librăria oferită de framework-ul Spring pentru trimiterea e-mailurilor are ca interfață centrală MailSender. Implementarea interfeței MailSender trimite un e-mail prin conectarea la un server de e-mail, așa cum este ilustrat și în figura 1.3.1. JavaMailSenderImpl este o implementare a interfeței MailSender, oferită de Spring, și utilizează API-ul JavaMail pentru a trimite e-mailurile precum ilustreaza figura 1.3.2. Pentru a putea trimite e-mailuri cu ajutorul aplicației Spring, clasa JavaMailSenderImpl trebuie declarată ca un bean în contextul aplicației.

Figura 1.3.1 Interfața MailSender este principala componentă pentru trimiterea e-mailurilor al framework-ului Spring. Aceasta trimite un e-mail serverului pentru a-l livra.

Clasa SimpleMailMessage este un obiect simplu ce încapsulează proprietățile unui simplu e-mail, precum expeditorul, destinatarul (sau mai mulți destinatari) și mesajul. Acest pachet conține de asemenea o ierarhie de excepții ce asigură un nivel înalt de abstractizare peste nivelul inferior al excepțiilor sistemului de e-mail ce are ca și excepție centrală excepția MailException. Interfața JavaMailSender adaugă caracteristici JavaMail specializate, precum suportul mesajelor MIME pentru interfața MailSender. [12]

Figura 1.3.2 Ierarhia Spring JavaMail

Pe scurt, trimiterea sau primirea unui e-mail necesită să interacționeze cu instanțe de tipul MimeMessage. La primirea mesajelor, interacționarea cu aceste obiecte este destul de simplă deoarece acestea oferă acces la toate proprietățile unui e-mail. În schimb, la trimiterea e-mailurilor, crearea și manipularea instanțelor MimeMessage necesită accesul la o resursă de nivel inferior, javax.mail.Session, care reprezintă conexiunea către serverul de e-mail.

Folosirea interfeței JavaMailSender are două consecințe. Prima consecință ar fi faptul că utilizatorii pot injecta un obiect JavaMailSender direct în Outbound Channel Adapter, ce poate acționa precum o configurare generală general pentru trimiterea de e-mailuri. Iar a doua consecință ar fi faptul că Outbound Channel Adapter acceptă mesajele de tipul MimeMessage (JavaMail), dar și cele de tipul MailMessage (Spring), ceea ce le permite dezvoltatorilor să formeze mesajele folosind utilitățile din interiorul framework-ului Spring și să le trimită prin Channel Adapter.[20]

Mesajului unui e-mail se formează prin concatenarea unui șir de cuvinte, ceea ce este suficient dacă mesajul nu este de dimensiuni mari. Construirea mesajului de dimensiuni mai mari al unui e-mail prin concatenarea unui șir de cuvinte nu este recomandată deoarece este dificil de a preconiza cum o să arate mesajul rezultant. În schimb, folosirea unui șablon proiectat de un designer grafic ar extrage aspectul mesajului și ar fi mult mai clar rezultatul. Mai exact, se extrage aspectul mesajului în ceva asemănător precum un fișier HTML, apoi șablonul respectiv se transformă într-un String. Există mai multe opțiuni pentru a alege un șablon pentru acest scop, inclusiv Apache Velocity și Thymeleaf.

Crearea E-Mailurilor cu ajutorul șablonului Velocity

Apache Velocity este un motor de șabloane bazat pe limbajul Java ce le permite designerilor web să lucreze în paralel cu programatorii Java pentru a dezvolta aplicații web conform modelului Model-View-Controller fiind o alternativă pentru paginile JSP. Velocity este de asemenea utilizat pentru construirea e-mailurilor de dimensiuni mari. Pentru această funcționalitate trebuie declarată clasa VelocityEngine, iar Spring oferă VelocityEngineFactoryBean ce produce un obiect VelocityEngine în contextul aplicației.

În pregatirea procesării șablonului, trebuie creat un Dicționar ce va conține informațiile necesare utilizate de șablon. Se apelează metoda mergeTemplateIntoString() pentru a transforma conținutul șablonului într-un String, iar apoi se setează textul rezultat în e-mail prin metoda setText(). [10]

Executarea și programarea unui task în Spring

Framework-ul Spring oferă suport pentru executarea asincronă și programarea task-urilor prin interfețele TaskExecutor, respectiv TakScheduler.

Executarea asincronă

Implementarile interfeței TaskExecutor sunt utilizate ca obiecte JavaBeans, iar configurarea proprietăților dorite se realizează prin namespace-uri XML în contextul aplicației.

<task:executor id="taskExecutor"

pool-size="5-25"

queue-capacity="100"/>

Aceasta este un exemplu de configurare ce are un numar ajustabil de operații poll ce pot fi executate în același timp, mai exact minim 5 operații, respectiv maxim 25, și o limită de 100 de task-uri. Ori de câte ori o componentă trebuie să execute un task asincron (un task poate să fie o metodă), acesta ajunge la taskExecutor care alocă un thread pentru executarea lui. Cea mai importantă caracteristică este faptul că mecanismul de alocare al thread-ului este complet izolat de aplicație. Ceea ce face defapt executorul este relativ simplu: o dată ce un task(Runnable) este primit, încearcă să găsească primul thread liber și de îndată ce thread-ul este eliberat, îl execută. [20]

Adnotarea @Async poate să fie declarată pentru o metodă pentru ca invocarea acelei metode să fie asincronă. În alte cuvinte, apelantul va reveni imediat după invocare și executarea efectivă a metodei va avea loc într-un task care a ajuns la taskExecutor. În cel mai simplu caz, adnotarea este declarată pentru o metodă de tipul void, dar se poate folosi și pentru metodele ce returnează valori. Deși acestea au nevoie să returneze obiecte de tipul „Future”, avantajele executării asincrone sunt în continuare valabile.

@Async

Future<String> returneazăString(int i) {

// această metodă va fi executată asincron

}

[12]

Planificatorul Spring

Aplicațiile enterprise au nevoie de multe ori să programeze unul sau mai multe task-uri, precum trimiterea unui e-mail pentru a notifica clienții, rularea unor teste, etc. Acestea trebuie să fie programate să ruleze în mod regulat, fie într-un interval fix (de exemplu în fiecare oră) sau dupa un anumit orar (de exemplu în fiecare seară la ora 20). În abstractizarea TaskScheduler, oferită de framework-ul Spring, sunt trei componente principale:

Interfața Trigger – asigură suportul pentru definirea mecanismului de declanșare. Spring oferă două implementări: clasa CronTrigger, respectiv clasa PeriodicTrigger;

Task – este componenta ce trebuie programată. În Spring, un task poate să fie o metodă specificată prin orice bean;

Interfața TaskScheduler – asigură suportul pentru planificarea unui task să ruleze. [9]

Clasa CronTrigger permite programarea task-urilor prin expresii cron. De exemplu, următorul task este programat să ruleze după 15 minute ale fiecărei ore din intervalul orelor business din zilele lucrătoare: scheduler.schedule(task, new CronTrigger("* 15 9-17 * * MON-FRI"));. Clasa PeriodicTrigger acceptă o perioadă fixată, o valoare opțională pentru o întârziere inițială și o valoare de tipul boolean ce indică dacă perioada dată ar trebui să fie interpretată ca fixed-rate sau ca fixed-delay, diferența dintre acestea putând fi observată în figura 1.3.3. Scenariul fixed-rate (1) garantează că operația va rula la intervalul stabilit, dar diferența de timp dintre terminarea, respectiv începutul operației poate varia. Scenariul fixed-delay (2) garantează că diferența de timp dintre terminarea, respectiv începutul operației va rămâne constantă, dar intervalul stabilit poate să sufere modificări în timp. [20] Această componentă are avantajul injecției de dependențe, prin urmare interfața Trigger poate să fie configurată și extern.

Figura 1.3.3 Diferența dintre fixed-rate (1) și fixed-delay (2).

TaskScheduler poate planifica rularea unui task într-un anumit moment din viitor prin diferite metode. Cea mai simplă metodă se numește schedule și are nevoie doar de interfețele Runnable și Date. Aceasta va rula o singură dată după timpul specificat. Toate celelalte metode sunt capabile să ruleze task-ul în mod repetat. Spring oferă două variante pentru a programa unul sau mai multe task-uri folosind abstractizarea TaskScheduler: prin adnotări sau prin configurarea în fișierele XML. [12]

Analizarea și extragerea datelor

O aplicație obișnuită utilizează un parser pentru a extrage informațiile dintr-un anumit document. Un parser este o aplicație care citește un document și îi înțelege convențiile de formatare, aplicând de obicei anumite reguli cu privire la conținut. De exemplu, clasa Properties din Java are un parser pentru formatul de fișiere standard properties. În funcție de complexitate, parsarea poate fi destul de dificilă, iar fiecare tip de parser se ocupă de acest proces în mod diferit. [21]

În continuare sunt definite diferite structuri de date și tehnologiile folosite pentru a extrage informațiile din acestea. Este importantă documentația acestor modele de date pentru facilitarea dezvoltării și testării serviciilor aplicației.

Limbaje de Markup

XML și HTML sunt numite limbaje de markup datorită modului în care este structurat textul din documente. Textul este împărțit în mai multe părți care sunt cuprinse de etichete ce indică structura sau definiția textului respectiv. În timp ce HTML are un set de etichete și o structură predefinită, XML oferă posibilitatea de a defini etichetele, regulile și definiția lor. Ambele limbaje, XML și HTML, sunt derivate din Standard Generalized Markup Language (SGML).

XML

XML, limbajul Extensible Markup, este adesea utilizat ca un format general pentru schimbarea datelor între servere și aplicații și stocarea datelor complexe datorită faptului că datele sunt structurate. XML a câștigat o acceptare vastă în toate industriile și limbajele de programare. În prezent, majoritatea limbajelor de programare oferă suport pentru procesarea datelor XML, iar limbajul Java nu este o excepție. Java are un suport excelent pentru procesarea documentelor XML, pentru crearea și citirea datelor XML. [28]

XML, este un limbaj meta-markup. Acesta permite crearea etichetelor care trebuie să fie organizate după anumite principii generale, dar care sunt destul de flexibile. De exemplu, pentru tematica „genealogia” ar trebui descrise atribute precum numele de familie, prenumele, data nașterii și așa mai departe, dar, în schimb, se pot crea etichete pentru fiecare dintre acestea. [14]

Valididatea unui document XML este opțională și se poate determina prin Document Type Definition (DTD) sau prin schema W3C XML Schema Language, sau chiar prin ambele. Un parser care citește un document XML poate să verifice sau nu dacă acesta este valid. Dacă verifică validitatea documentului, programul care primește datele de la parser poate să accepte unele erori de validare. În unele cazuri, cum ar fi adăugarea unui atribut care lipsește și este necesar al unei entități în baza de date, este o eroare de validare importantă și programul nu ar accepta validitatea documentului. Formatul corect al structurii unui document XML este necesar, dar nu și validitatea.

Elemente și atribute XML

Sunt câteva reguli generale în privința elementelor unui document XML. Un element este delimitat de eticheta de început și cea de sfârșit. De exemplu, elementul <element>text</element> are eticheta de început <element>. Tot ceea ce se află între etichetele elementului se numește conținut. Numele elementelor nu pot să conțină space și trebuie să înceapă cu o literă sau unul dintre caracterele underscore și două puncte.

Atributele conțin valori ce îi sunt asociate unui element și fac întotdeauna parte din eticheta de început al elementului: <element atribut=”valoare”></element>. Regulile de bază ale elementelor se aplică și atributelor, cu câteva adăugări. Numele atributului trebuie să fie imediat după numele elementului, urmat de caracterul egal, apoi de valoarea atributului inclusă între ghilimele sau apostroafe.

Nu există reguli despre când să se utilizeze elementele unui element și atributele. În general, se folosește orice se potrivește aplicației respective, dar este recomandat ca informațiile despre metadate, mai exact id-urile, URL-urile, referințele și alte informații nerelevante pentru utilizatori să fie stocate în atribute. Cu toate acestea, există multe motive pentru a nu stoca metadatele ca și atribute:

Atributele sunt neordonate, iar elementele sunt ordonate;

Elementele permit includerea informațiilor despre metadate;

Nu toată lumea este de acord despre ce este sau nu metadata;

Elementele sunt mai extensibile pentru posibilele schimbări;

Elementele pot avea substructuri, iar atributele nu. [14]

Validarea unui XML cu DTD

În timp ce XML este extrem de flexibil, nu toate programele care citesc anumite documente XML sunt atât de flexibile. Multe programe pot lucra doar cu câteva aplicații XML, prin urmare într-o aplicație XML, este de multe ori important să se asigure că un anumit document aderă la regulile aplicației XML. De exemplu, în XHTML, elementele „li” trebuie să apară doar după elementele „ul” sau „ol”, altfel este posibil ca browserele să nu știe ce să facă cu ele sau să acționeze în mod greșit. XML oferă o soluție la această problemă: o definiție de tip de document (DTD). DTD-urile sunt scrise într-o sintaxă formală care explică exact ce elemente pot să apară și unde în document și ce conținut și atribute pot și trebuie să conțină fiecare element. Un DTD poate să facă afirmații precum „Un element „ul” conține doar elemente „li”" sau „Fiecare element persoană trebuie să aibă un atribut cnp".

Un document valid include o declarare de tip de document care identifică DTD-ul ce satisface documentul. DTD-ul listează toate elementele, atributele și entitățile folosite de document și contextul în care pot să apară. Validitatea funcționează pe principiul că tot ce nu este permis, este interzis. Dacă documentul are o declarare de tip de document și documentul satisface DTD-ul pe care îl indică declararea de tip de document, atunci documentul XML este valid, altfel este invalid.

Un DTD pentru un document cu elemente persoană ar spune că un element persoană conține un element copil nume, urmat de zero sau mai multe elemente copil profesie. S-ar spune, în continuare, că fiecare element nume conține exact un element copil nume_familie, urmat de exact un element copil prenume și că toate elementele conțin text. Un element care conține numai text simplu este declarat folosind cuvântul cheie #PCDATA (Parsed Character Data) în paranteze.

<!ELEMENT persoană (nume, profesie*)>

<!ELEMENT nume (nume_familie, prenume)>

<!ELEMENT nume_familie (#PCDATA)>

<!ELEMENT prenume (#PCDATA)>

<!ELEMENT profesie (#PCDATA)>

Un document valabil include o referire la DTD-ul cu care ar trebui să fie comparat. Acest lucru este dat în declarația unică de tip de document al documentului XML. O declarație de tip de document arată astfel: <!DOCTYPE persoană SYSTEM "http://www.site.ro/dtds/ex.dtd">. Totuși, este recomandată menținerea unui DTD în același fișier cu elementele definite deoarece astfel, elementele se pot verifica și modifica mai ușor. În acest caz, declarația tipului de document se modifică, fiind inclusă între paranteze pătrare. Un exemplu final de document XML cu elementul persoană cu DTD-ul intern este prezentat în exemplul următor.

<?xml version="1.0"?>

<!DOCTYPE persoană [

<!ELEMENT persoană (nume, profesie*)>

<!ELEMENT nume (nume_familie, prenume)>

<!ELEMENT nume_familie (#PCDATA)>

<!ELEMENT prenume (#PCDATA)>

<!ELEMENT profesie (#PCDATA)>

]>

<persoană>

<nume>

<nume_familie>Pop</nume_familie>

<prenume>Ion</prenume>

</nume>

</persoană>

Sunt multe lucruri pe care un DTD nu le precizează:

Câte instanțe ale fiecărui element pot să apară în document;

Ce date sunt permise pentru contextul elementelor;

Sensul semantic al unui element, de exemplu, dacă conține data nașterii sau numele persoanei.

DTD-urile oferă posibilitatea de a face unele constângeri asupra unui document XML, dar limitele respective sunt destul de flexibile. Un DTD nu asigură un control fin asupra formatului și tipurilor de date ale elementor, altele decât diversele tipuri de atribute speciale (ID, IDREF, ENTITY, NMTOKEN, și așa mai departe) și nu precizează nimic despre lungime, structură, sens semantic, valori permise sau alte aspecte ale contextului unui element sau atribut. [15]

Validatea unui XML cu schema XSD

Schemele sunt documente ce definesc conținutul valid al unor anumite clase ale documentelor XML. Schema W3C XML Schema Language are un număr mare de caracteristici folositoare, precum abilitatea de a specifica tipul de date pentru conținutul unui text și valorile atributelor. De exemplu, schema poate preciza dacă elementul „preț” este de tipul double sau daca atributul „cantitate” conține un număr între 1 și 100. Schema mai are și alte caracteristici cum ar fi constrângerea numărului de apariție al unui element, conștientizarea namespace-ului și abilitatea de a valida structuri complexe construite din mai multe elemente diferite și de mai multe tipuri . [14]

Un document XML descris de o schemă se numește un document instanță . Dacă un document care îndeplinește toate constrângerile specificate de schemă , se consideră a fi valid. Documentul schemă este asociat cu un document instanță prin una dintre următoarele metode:

Un atribut xsi:schemaLocation pe un element ce conține o listă de namespace-uri folosite în cadrul acestui element și adresele URL ale schemelor cu care să valideze elementele și atributele în namespace-urile respective;

Un atribut xsi:noNamespaceSchemaLocation ce conține o adresă URL pentru schema folosită pentru a valida elementele care nu sunt în nici un namespace;

Un parser poate avea setat în mod exlicit o anumită schemă pentru a valida documentul dat, ignorând orice altă sursă din documentul respectiv.

Documentele XML sunt compuse în principal din elemente imbricate, și xs:element este una dintre declarațiile cel mai frecvent utilizate într-o schemă tipică. Declarația <xs:element name="nume" type="xs:string" minOccurs=”1” maxOccurs=”unbounded”/> include un singur element care spune că elementul nume trebuie să apară cel puțin o dată. Această declarație utilizează patru atribute pentru a descrie elementul în instanța documentului: name, type, minOccurs și maxOccurs. Schemele suportă două tipuri de conținut: simplu și complex. Conținutul simplu constă în text care nu conține elemente imbricate. Atributul type="xs:string" îi spune schemei că elementul nume poate avea doar conținut de tipul xs:string. Schema dispune și de alte tipuri simple precum anyURI, boolean, byte, dateTime, integer și multe altele. Deoarece valorile atributelor nu pot conține elemente, atributele trebuie să fie întotdeauna declarate cu tipuri simple. De asemenea, un element care este declarat având un tip simplu nu poate avea nici atribute.

Atributele sunt declarate folosind elementul xs:attribute. Atributele pot fi declarate la nivel global (care pot fi referite de oriunde în schema), sau la nivel local, ca o parte a unei definiții de tip complex care este asociată cu un anumit element. În DTD, entitățile parametru sunt folosite pentru a încapsula grupuri repetate de declarații de atribute, care sunt partajate între diferite tipuri de elemente. Schema oferă aceeași funcționalitate într-un mod mai formal folosind elementul xs:attributeGroup.

Abilitatea de a stabili în mod explicit numărul minim și maxim al aparițiilor unui anumit element într-un anumit punct într-un document, folosind atributele minOccurs și maxOccurs, este o caracteristică a schemelor care nu se regăsește și în DTD. Acest lucru este mult mai flexibil și mai ușor de utilizat decât utilizarea operatorilor „?”, „*” și „+”, care sunt disponibile în DTD. Valoarea implicită pentru ambele atribute, minOccurs si maxOccurs, este 1, în cazul în care nu sunt atribuite în mod explicit. De aceea, stabilind minOccurs la 0 înseamnă că elementul poate apărea o dată sau deloc (acest lucru este echivalent cu folosirea operatorului „?” într-o declarație DTD). O altă valoare posibilă pentru atributul maxOccurs este unbounded, care indică faptul că elementul în cauză poate să apară de un număr nelimitat de ori. Această valoare este folosită pentru a produce același efect ca și operatorii „*” și „+” într-o declarație DTD. Avantajul schemei este atunci când se folosesc alte valori decât 0, 1, sau unbounded, oferind posibilitatea de a specifica că un element trebuie să apară cel puțin o dată și cel mult de trei ori.[15]

HTML

HTML și XHTML definesc sintaxa si transmiterea direcțiilor speciale, integrate, care nu sunt afișate de browser, dar îi indică cum să afișeze conținutul documentului, inclusiv textul, imaginile și alte tipuri de medii. De asemenea, limbajele fac un document interactiv prin link-uri speciale hypertext, care conectează documentul cu altele de pe calculator sau de la alte resurse de pe internet.

Extensible HTML, XHTML, este o reformulare a documentului HTML în urma sintaxei mai stricte a documentului XML. În timp ce XML este extensibil, XHTML oferă un set finit de elemente predefinite, identice cu cele din HTML 4.01. Singurele diferențe reale între HTML 4.01 și XHTML 1.0 sunt de stilistică, XHTML având doar câteva reguli în plus.

Structura HTML

Documentele HTML și XHTML sunt compuse din text care definește conținutul documentului, și etichete (tag-uri), care definesc structura și aspectul documentului. Structura unui document HTML este simplă, constând dintr-o etichetă de început <html>, respectiv dintr-o etichetă de sfârșit a documentului </html>.

Majoritatea documentelor conțin etichetele <head> și <body>. Partea în care documentul primește un titlu și alte referințe care sunt utilizate pentru afișarea acestuia este poziționată după eticheta <head>. Ceea ce este pus în body este defapt conținutul real al documentului. Acesta include textul ce urmează a fi afișat și etichetele care indică cum să fie afișat. Etichetele pot, de asemenea, să conțină referințe către fișiere cu efecte speciale, inclusiv grafică și sunet, și să indice hyperlink-uri care leagă documentul de altele. Fiecare tag constă într-un nume de etichetă, urmat uneori de o listă opțională de atribute, toate plasate între caracterele de deschidere și închidere (< și >). Cea mai simplă etichetă nu este nimic mai mult decât un nume închis corespunzător între paranteze, cum ar fi <title> și <b>. Etichetele mai complicate conțin unul sau mai multe atribute, care precizează sau modifica comportamentul etichetei, precum ar fi <input type=”text” name=”exemplu” maxlength=”20”>. Această etichetă conține mai multe atribute cu valorile cuprinse între ghilimele, deși includerea ghilimelelor nu este necesară pentru HTML, doar pentru XHTML.

HTML și CSS

În cea mai mare parte, HTML-ul concentrează conținutul către stilizarea acestuia pentru a le oferi utilizatorilor un aspect de o calitate superioară. La cel mai simplu nivel, un stil nu este nimic mai mult decât o regulă pe care browser-ul o urmează pentru a randa un anumit. Fiecare etichetă are un număr de proprietăți de stil asociate cu ea, a cărei valori definește modul în care eticheta este randată de browser. O regulă definește o valoare specifică pentru una sau mai multe proprietăți ale unei etichete. Figura 2.1.1 ilustrează prelucrarea codului (HTML și CSS​) până în versiunea finală pe care o afișează browser-ul. [2]

Figura 2.1.1 Procesarea codului HTML și CSS de un browser

În primul rând, HTML devine parsat într-un DOM Tree. Acesta este unul dintre motivele pentru care un browser descarcă conținutul paginii HTML. Al doilea motiv se datorează faptului că un HTML conține toate referințele către resursele definite în pagină. Apoi, este creat Render Tree, prin combinarea regulilor stilului CSS și a elementului DOM Tree, iar elementele acestuia sunt afișate de browser. [18]

De asemenea, definițiile stilurilor se pot include într-un document separat (un fisier text cu extensia css) și apoi importate în document. Deoarece un stylesheet extern este un fișier separat și browser-ul îl încarcă în rețea, acesta se stoca oriunde și se poate refolosi pentru alte documente. De exemplu, fișierul stiluri.css conține următoarea regulă de stil: h1 {color: red; font-family:courier;}.

CSS3 permite definirea a mai multor stiluri diferite pentru același element prin denumirea unei clase prin atributul class pentru fiecare stil, la nivel de document sau într-un stylesheet extern. Clasa se poate defini și fără asocierea unei etichete particulare și se poate aplica selectiv pentru mai multe etichete. De exemplu, .red {color: red;}, creează o clasă generică numită red. Pentru a folosi acestă clasă, denumirea ei trebuie inclusă într-o etichetă prin atributul class: <h2 class=”red”>. Aproape toate etichetele HTML accepta atributul id, care îi atribuie un identificator unic unui element în document. Pentru a crea o clasă de stil pe care browser-ul o aplică numai pentru acele porțiuni ale documentului etichetate în mod explicit cu atributul id, se urmează aceeași sintaxă ca și pentru clasele de stil precedente, cu excepția schimbării caracterului „.” cu „#” înaintea denumirii clasei: #red {color: red;}. În document, se utilizează același nume de id pentru a aplica stilul, cum ar fi <h2 id=red> pentru a crea header-ul roșu. [2]

HTML5

HTML5 este pur și simplu următoarea iterație a limbajului HTML care oferă conținutului web structura necesară. După cum a fost prezentată structura HTML mai devreme în acest capitol, aceasta permite cititorilor, prin intermediul etichetelor, să diferențieze un titlu de un paragraf, sau un paragraf de o listă, sau o listă de un citat și așa mai departe. Conținutul fără o structură este un conținut fără sens.

Ultima versiune a limbajului HTML introduce o serie de elemente noi, semnificative, care au fost omise în HTML 4 si XHTML. În plus față de familiarele titluri (h1,h2..), paragrafe, tabele și liste, există elemente noi precum meniuri, articole, rezumate, calendare cu date și ore, figuri cu descrieri, și o mulțime de elemente noi de formulare interactive. Toate elementele utile din versiunile anterioare ale HTML-ului au fost păstrate, dar HTML5 elimină unele elemente vechi care nu mai sunt necesare. Pe deasupra, pentru a completa colecția de elemente noi, HTML5 a adăugat și elemente pentru integrarea conținutului media în documente. Utilizatorii au trebuit să se bazeze pe aplicații plug-in, precum Adobe Flash sau Apple QuickTime, pentru a reda audio sau video pe Web, dar HTML5 face posibilă redarea sunetului și video în browser, fără a avea nevoie de plug-in-uri. HTML5 aduce, de asemenea, elementul canvas, adică o porțiune într-un document în care script-urile și programele pot schița grafice. [22]

HTML5 introduce elementele structurale pentru secționarea unei pagini. Aceste elemente sunt înlocuitori pentru semantica ad-hoc comună ale unor părți ale paginii pe care s-au aplicat înainte atributele class și id, doar că acestea sunt standardizate:

<section> – Reprezintă o secțiune al unui document sau al unui grup de documente, având aproape întotdeauna un titlu. Este o parte de conținut relevant, ca o subsecțiune a unui articol lung (cum ar fi secțiunea de știri de pe o pagină);

<article> – Reprezintă o secțiune independentă al unui document sau al unui site. Un exemplu ar fi un articol de blog, o postare al unui forum sau un comentariu;

<header> – Reprezintă un titlu îmbunătățit care include un titlu standard (<h1>-<h6> sau grupul <hgroup>) și conținut suplimentar. Conținutul suplimentar poate conține un logo, elemente <nav>, un formular de căutare, dar nu și elementul <footer> sau un alt <header>;

<footer> – Este utilizat pentru afișarea informațiilor adiționale despre conținut, cum ar fi autorul, date despre autor, un link către începutul paginii, etc. și de obicei apare la finalul paginii. Precum la elementul <header>, nu poate să conțină elementele <footer> și <header>;

<hgroup> – Reprezintă o formă specializată de <header>, care poate conține numai elemente <h1>-<h6>. Este folosit pentru gruparea unui titlu cu mai multe subtitluri;

<nav> – Reprezintă o colecție de link-uri ale unei pagini. Aceste link-uri pot indica către subiecte din pagina curentă, sau către alte pagini ale site-ului;

<aside> – Reprezintă o bucată completă de text sau un grup de link-uri care este separată de restul conținutului paginii. De exemplu, un sidebar cu un conținut relevant despre articolul principal;

<figure> și <figcaption> – Ilustrează o figură și descrierea sa. Scopul acestor elemente este de a indica asocierea dintre imagine și descriere. [24]

HTML5 este bazat pe diverse principii de design, conform specificațiilor W3C, care cuprinde o nouă viziune de posibilitați și practicabilitate în câteva cuvinte: compatibilitate, utilitate, interoperabilitate și acces universal. HTML5 are o abordare în două direcții. În primul rând, se adaugă un număr foarte mare de elemente semantice, iar în al doilea rând, și mai important, HTML5 suportă un standard separat de microdate, care oferă utilizatorilor o modalitate extensibilă de a defini orice fel de informații doresc, iar apoi să o adauge în paginile lor. Microdata ajută la rezolvarea problemei de markup semantic, începând cu HTML5, și ajungând mai târziu să dețină propriul standard de dezvoltare. Aceasta este o meta-sintaxă nouă și ușoară, folosind perechi nume-valoare imbricate de date, în general bazate pe conținutului paginii. Acesta este un mod cu totul nou de a adăuga informații semantice suplimentare și extinderea limbajului HTML5. [22]

Prin utilizarea semanticii HTML (precum titlurile) într-un mod corespunzător și prin scrierea unui conținut de calitate, crește importanța cuvintelor cheie și prin urmare, se îmbunătățește indexul din topul motorului de căutare Google pentru aplicația Web respectivă. Markup-ul semantic este autodescriptiv și utilizează elementele HTML în mod corect. De exemplu, declararea <div id="heading" style="font-size:250%; padding: 10px;">Titlu</div> arată ca un titlu, dar nu ar funcționa ca un titlu în ceea ce privește sensul sau scopul acestuia. Prin urmare, ar avea un efect negativ asupra optimizarea motorului de căutare (cuvinte cheie în titluri au mai greutate), accesibilității, dezvoltării (este mult mai complicat de arăta elemente cu stiluri și scripturi atunci când nu se folosesc elementele semantice corespunzătoare), precum și altele. Exemplul corect ar fi așa: <header>Titlu</header>.

Odată cu noile elemente semantice, HTML5 introduce, de asemenea noi modalități simple de a găsi elemente în pagină. Cu noul API Selectors, există acum metode mai precise de a specifica ce elemente se doresc a fi preluate fără a recurge la iterarea prin document folosind parserul standard DOM. API-ul Selectors expune aceleași reguli de selectare prezente în CSS ca un mijloc de a găsi unul sau mai multe elemente pe pagină. De exemplu, querySelector() returnează primul element din pagina care corespunde regulilor specificate, iar querySelectorAll() returnează toate elementele care se potrivesc cu regula sau regulile specificate ( de exemplu document.querySelectorAll("#results td"); returnează toate elementele de tipul td cu id-ul results).[24]

Date semistructurate

Există o categorie mai mare de tipuri de date cu care se confruntă aplicațiile din ziua de azi:

Date structurate simple – aceste date pot fi organizate în tabele simple, care sunt structurate pe baza regulilor business;

Date structurate complexe – acest tip de date este potrivit pentru caracteristicile obiectelor relaționale al bazei de date, cum ar fi colecțiile, referințele, și tipurile definite de utilizator;

Date semistructurate – acest tip de date are o structură logică, care, de obicei, nu este interpretat de baza de date. De exemplu, un document XML care este procesat de o aplicație sau de un serviciu extern, poate fi încadrat în categoria datelor semistructurate;

Date nestructurate – acest tip de date nu este împarțit în structuri logice mai mici și nu este de obicei interpretat de baza de date sau de o anumită aplicație, și nu respectă nicio regulă. O fotografie stocată ca un fișier binar este un exemplu de date nestructurate. [11]

Modele de date semistructurate

Datele semistructurate, cum ar fi XML și HTML, atrag o atenție considerabilă. De asemenea, WWW poate să fie văzut precum o bază de date pentru datele semistructurate ale cărei instanțe sunt documentele HTML. Din moment ce datele semistructurate pot să fie modelate după denumirile ordonate ale nodurilor unui arbore, este important să se dezvolte diferite tipuri de tehnici de extragere a cunoștințelor din colecțiile de date semistructurate.

Multe modele de date semistructurate sunt bazate mai mult pe denumirile nodurilor unui graf, decât după ale unui arbore deoarece în multe cazuri există posibilitatea ca informațiile afișate să nu conțină restricții, și sunt utilizate pentru integrarea și schimbul de date între sursele de date eterogene, neutre. Adeseori, acestea sunt numite autodescriptive și fără schemă, iar informațiile sunt stocate în frunzele grafului precum ilustrează figura 2.2.1.

Figura 2.2.1 Model de date semistructurate descris într-un graf

Extragerea datelor din paginile Web semistructurate

În zilele noastre, există multe site-uri care oferă acces la datele structurate și care sunt conținute într-o bază de date. De obicei, aceste surse oferă un fel de formular HTML care permite emiterea unei interogări în baza de date, și care întorc rezultatele interogării încorporate în paginile HTML printr-un un anumit șablon. Aceste surse de date sunt de obicei numite surse web semistructurate. De exemplu, o pagină care conține o listă de înregistrări de date, fiecare înregistrare de date reprezentând informația despre un anunț al unei mașini într-un site de anunțuri de pe Internet. Permiterea programelor software pentru accesul la aceste date este utilă pentru o varietate mare de scopuri. De exemplu, permite aplicațiilor de integrare a datelor accesul la informațiile web într-un mod similar precum o bază de date și, de asemenea, permite stocarea informațiilor preluate. [19]

S-au descoperit mai multe tehnici pentru extragerea datelor web, precum trimiterea unui query către sursa de date și returnarea setului de date structurate rezultate prin apelul către aplicație. Deși aceste metode au fost folosite cu succes pentru multe extrageri de date, această abordare este limitată de faptul că sursele de date țintă trebuie să fie cunoscute în prealabil și aplicația să îți acorde dreptul de a interoga baza de date, iar acest lucru, de foarte multe ori nu este posibil. Din această cauză, s-au creat alte metode pentru extragerea datelor web, precum un parser. Un parser pentru o pagină Web, ar trebui să ia sursa HTML și să extragă atributele dorite din fiecare tree, dar există un grad mare de neregularități în structură din moment ce nu toate obiectele (anunțurile) sunt tratate în aceeași manieră (unele anunțuri pot conține mai puține informații, aceeași valoare poate să apară de mai multe ori, diferite valori care să reprezinte aceeași informație) și informația prezentată să nu fie acceptată. Prin urmare, parserul trebuie să fie scris astfel încât să accepte informația chiar dacă unele porțiuni lipsesc. [16]

Parsere pentru extragerea cunoștințelor din colecțiile de date

Un parser este o componentă software care preia datele de intrare, de obicei sunt formate din text, și construiește o structură de date, precum un arbore, oferind datelor o reprezentare structurală și verificarea sintaxei în acest proces. Parsarea poate să fie urmată de alți pași, sau acești pași să fie incluși într-o singură acțiune. Datele de intrare sunt de obicei text simplu, dar pot să fie și date mai puțin structurate, precum fișiere HTML sau XML, caz în care, în general, numai anumite părți ale datelor sunt extrase, fără a fi nevoie de construirea arborelui.

Parserul XML se ocupă de primirea datelor unui XML și verificarea documentului dacă este bine format, iar în cazul în care se face referire către un DTD sau o către o schemă, acesta se asigură că documentul este valid. Ceea ce rezultă dupa analizarea unui document XML este o structură de date care poate să fie utilizată de alte instrumente XML sau API-uri Java. [21]

O modalitate de a analiza un document XML, probabil cea mai tipică, este prin parserele SAX și DOM. World Wide Web Consortium (W3C) recomandă modelul de parsare DOM care are abrevirea de la Document Object Model. DOM este un parser care citește un document XML întreg și creează obiecte Node. Acesta se folosește atunci când este nevoie de toată reprezentarea documentului din care se pot scoate sau adăuga părți de date în orice moment. SAX, care este abrevierea de la Simple API pentru XML, nu reprezintă chiar un parser, ci mai mult este un API ce definește un mecanism de manipulare al unor evenimente și care poate fi utilizat pentru a analiza documentele XML. Prin folosirea parserului SAX, se asigură faptul că documentul XML nu este niciodată stocat sau reprezentat în memorie în totalitate. [28]

O altă modalitate prin care accesarea documentelor XML este mai ușoară, este JAXB, un API inclus în platforma Java, care automatizează maparea dintre documentele XML și obiectele Java, fără a fi nevoie de a utiliza un parser precum SAX.

DOM

DOM (Document Object Model) este singurul model de parsare al documentelor XML recomandat în mod oficial de către W3C pentru parsarea documentelor XML. Acesta poate să fie folosit pentru a crea documente XML, pentru a analiza structura DOM și pentru a adăuga, modifica sau șterge noduri DOM. Parsarea unui document cu DOM poate să fie mai lentă decât cu SAX deoarece DOM creează o reprezentare de a întregului document, indiferent cât de mare este acesta. Cu toate acestea, DOM poate să fie foarte folositor pentru extragerea tuturor informațiilor dintr-un document sau extragerea unei anumite părți de informații de mai multe ori. DOM rămâne în memorie atât timp cât codul care a creat reprezentarea DOM se execută. [4]

Versiunile succesive ale lui DOM sunt definite ca niveluri. Nivelul 1 a fost prima lansare a celor de la W3C, și s-a concentrat pe lucrul cu HTML și XML într-un context al browser-ului. A oferit suport pentru HTML și o bază pentru procesarea documentelor XML. Deoarece se aștepta ca documentul să fie existent într-un anumit conext, primul nivel a definit numai structura obiectului și cum să-l manipuleze, fără a reprezenta documentul într-o structură sau deserializa documentul din acea structură. Nivelul următor a adăugat această funcționalitate, și în plus, a inclus actualizări pentru modulele Core și HTML din primul nivel, precum și module noi pentru Views, Events, Style, Traversal, and Range. În nivelul 3 s-au introdus module noi pentru Abstract Schemas, Load, Save, XPath, și actualizări pentru modulele Core și Events. [15]

DOM este o reprezentare în structura de date „arbore” a datelor din XML, iar toate interfețele nucleului DOM sunt derivări ale interfeței org.w3c.dom.Node, care oferă un set generic de metode pentru accesarea structurii arborescente sau a unui fragment. Fiecare nod din arborele DOM reprezintă elementul original din documentul XML. Elementele, atributele și nodurile text sunt impricate pe mai multe niveluri care corespund elementelor imbricate de pe același nivel din documentul XML, de asemenea, și elementului rădăcină îi corespunde nodul rădăcină.

Cea mai folosită funcționalitate de la serializare, în DOM, este de a afișa denumirea, atributele, valoarea și copiii unui element. Toate acestea se pot realiza rapid cu metodele DOM. Pentru început se apelează metoda getNodeName() care returnează denumirea elementului XML, iar apoi se serializează elementele copil are elementului curent prin metoda serializeNode(). Elementele copil pot fi accesate prin metoda getChildNodes() ce returnează o instanță a obiectului NodeList din DOM. Clasa Node mai oferă funcționalități precum metoda getNodeValue() care returnează un String, getNodeName(), getParent(), createNode() care crează un element cu denumirea dată ca și parametru și multe alte metode care crează, modifică sau șterg un element. [3]

SAX

SAX (Simple API pentru XML) nu este un parser XML, ci un set de interfețe Java implementate de mai multe parsere XML. Acesta a fost dezvoltat ca un mod standardizat de a analiza și extrage informațiile dintr-un document XML, pentru a permite o analiză mai eficientă a documentelor de mari dimensiuni XML.

Parsarea cu ajutorul lui SAX este mai rapidă decât cu DOM, dar codul este mai complex, iar reprezentările documentelor XML nu urmează aceleași reguli și structuri precum cele definite de DOM. Pentru utilizarea API-ului SAX, este necesară dezvoltarea metodelor de tipul callback care sunt apelate de API-ul SAX când sunt întâlnite diverse elemente ale documentului XML. O implementare SAX scanează documentul XML de la început până la sfârșit și apelează metodele callback pentru evenimentele care au loc în cadrul documentului. Evenimentele includ lucruri cum ar fi începutul unui element, sfârșitul unui element, începutul unui atribut, sfârșitul unui atribut, și așa mai departe. Aceste metode aparțin clasei org.xml.sax.ContentHandler și sunt denumite startElement(), respectiv endElement(). Pentru a fi returnat textul conținutului unui element este apelată metoda characters(). [28] Interfața ContentHandler conține de asemenea și metodele apelate în răspuns la începutul unui document – startDocument(), respectiv sfârșitul unui document – endDocument(), dar și metode pentru manipularea mapării namespace-ului, în special instrucțiunilor XML, și spațiilor care pot fi ignorate. Ca și în multe interfețe Java, implementarea org.xml.sax.helpers.DefaultHandler permite suprascrierea doar metodelor dorite. Mecanismul ContentHandler pentru recepția evenimentelor SAX este simplu, dar ceea ce este mai complicat este utilizarea API-ului SAX pentru popularea unui obiect Java.

Fiecare aplicație SAX trece prin aceleași etape de bază pentru a procesa un document XML:

Obține referința obiectului care implementează interfața XMLReader. Interfața XMLReader reprezintă un parserXML ce declară metodele pentru a analiza un document și pentru a configura procesul de parsare, precum, opțiunea pentru verificarea validității documentului. Clasa XMLReaderFactory implementează interfața XMLReader și conține metoda statică createXMLReader() care crează o instanță XMLReader [21];

Se creează o instanță a unui obiect specific aplicației care implementează una sau mai multe dintre diferitele interfețe SAX Handler (DTDHandler, ContentHandler, ErrorHandler, și EntityResolver);

Acesta înregistrează instanța obiectului cu obiectul XMLReader pentru a primi notificările evenimentelor apărute la parsarea XML;

Se apelează metoda XMLReader.parse() pentru fiecare document XML care trebuie să fie procesat de aplicație. Instanța obiectului de la pasul 3 primește notificări pe măsură ce documentul este analizat.

Fiind bazat pe evenimente, SAX oferă mai multe beneficii de utilizare precum sunt următoarele:

SAX generează evenimentele în mod continuu pe toată durata procesului analizării unui document, iar analizarea documentului poate începe imediat, fără a fi nevoie să se aștepte terminarea procesării acestuia;

Aplicația nu trebuie să proceseze întregul document în cazul în care este interesată doar de o anumită parte;

Datorită faptului că analizează conținutul documentului pe măsură ce îl citește și generează imediat evenimentele, SAX nu are nevoie să stocheze datele în memorie, prin urmare procesarea documentelor mari este mult mai ușoară decât cu alte tehnici de parsare precum DOM, care are nevoie de a stoca tot documentul în memorie putând avea constrângeri severe asupra resurselor de sistem.

În același timp, SAX vine și cu anumite dezavantaje:

După citește o anumită parte a documentului, SAX nu se poate întoarce pentru a reciti datele pe care le-a prelucrat, doar dacă nu reîncepe procesarea;

Datorită faptului că SAX nu stochează datele procesate, acestea nu pot fi modificate și apoi adăugate în document;

Deoarece SAX nu crează o structură a unui document în memorie, nu se poate construi un document XML folosind API-ul SAX. [1]

JAXB

Arhitectura Java pentru maparea automată a documentelor XML cu obiectele Java, JAXB (Java Architecture for XML Binding), permite dezvoltatorilor Java să acceseze și să proceseze datele dintr-un document XML fără a fi nevoie de cunoașterea caracteristicilor XML sau procesul de prelucrare a acestora. Procesul marshalling de la JAXB generează un document XML dintr-un obiect Java care reprezinta un document XML, iar procesul de unmarshalling transformă un document XML într-un obiect Java. Deși parsarea unui document XML și procesul de unmarshalling al API-ului JAXB prezintă unele asemănări precum faptul că ambele procese randează obiecte care pot fi folosite de codul Java pentru a accesa diferite părți ale unui document XML, sau faptul că ambele procese oferă opționalitatea de a valida structura documentului XML prin utilizarea schemelor, JAXB poate folosi schema respectivă drept un set de instruțiuni pentru a converti obiectele Java într-un document XML sau invers. API-ul JAXB în comparație cu SAX și DOM, permite un acces mai ușor la obiectele Java și, de asemenea, permite validarea acestor obiecte care reprezintă obiectele dintr-un document XML înainte de a deveni obiecte ale documentului XML. JAXB oferă suport pentru procesele unmarshalling și marshalling și pentru API-ul SAX. [4]

Convertirea unui document XML într-o instanță a unui obiect Java este ideea de bază a procesului de asociere al datelor. JAXB folosește adnotări Java pentru creșterea corectitudinii a generării claselor cu informații adiționale care fac legătura dintre ceea ce este descris în schema sau documentul XML și cu informațiile disponibile (prin mecanisme de reflecție Java) dintr-un set de definiții al unei clase Java. Astfel, clasele Java adnotate, sunt pregătite pentru procesul de execuție al API-ului JAXB.

Procesul unmarshalling

Procesul unmarshalling pentru un document XML este constituit prin crearea unui arbore de obiecte care reprezintă conținutul și organizarea documentului. Acest arbore nu este un arbore DOM. De fapt, aceste structuri de date pot fi mai eficiente în privința utilizării memoriei decât cele produse de DOM. Nodurile arborelui corespund elementelor XML, ale căror atribute și conținut sunt instanțe ale variabilelor și se referă la elementele de tip copil prin referințele obiectului.

Pentru procesul unmarshalling al unui document XML, trebuie creat obiectul JAXBContent și aplearea metodei unmarshal. Obiectul JAXBContent oferă punctul de intrare către API-ul JAXB, și menține asocierea dintre documentul XML și obiectele Java. Din acest context se obține obiectul Unmarshaller care controlează întreg procesul de creare al setului de obiecte Java echivalent cu textul XML. Acesta oferă mai multe metode unmarshal, acceptând o gamă largă de tipuri de obiecte ca sursă de date pentru textul XML. Valoarea returnată de metoda unmarshal() reprezintă nodul rădăcină al documentului XML parsat într-o instanță al obiectului JAXBElement<T>. O caracteristică importantă a API-ului JAXB este că, în acest proces, datele sursă se pot valida cu ajutorul schemei asociate.

Procesul marshalling

Procesul marshalling este opusul procesului unmarshalling. Acesta creează un document XML pe baza conținutului unui arbore. Pentru procesul marshalling este nevoie de crearea obiectului JAXBContext și de a specifica calea contextului, adică pachetul care conține clasele și interfețele pentru asocierea schemei. În acest fel, se poate crea un document XML folosind diverse combinații de elemente XML care corespund unor scheme diferite. Controlarea procesului marshalling este realizată de obiectul Marshaller. Cu ajutorul metodei marshal se creează documentul XML, prin specificarea obiectului care conține rădăcina arborelui, și calea către documentul XML. [11]

Aplicația AutoLead

Acesta este capitolul dedicat lucrării aplicației practice care prezintă conceptele teoretice definite în capitolele anterioare. Aplicația AutoLead permite vizualizarea informațiilor extrase de pe site-urile Web într-o manieră semantică sau sub formă de rapoarte. Pentru a parcurge toate paginile unui anumit site căruia îi este precizat doar URL-ul rădăcină, s-a folosit interfața oferită de crawler-ul open source, crawler4j. Acesta oferă avantajul de a seta numărul de fire de execuție care se pot rula simultan, precum și ce URL-uri îi este permis, respectiv interzis, să viziteze. Extragerea informațiilor din paginile HTML se realizează cu ajutorul parserului JSOUP, o librărie Java bazată pe tehnologia DOM. Informațiile extrase se prelucrează și se validează, iar la finalul procesării tuturor paginilor unui anumit site, acestea se adaugă în baza de date.

AutoLead este o aplicație Web dezvoltată cu framework-ul Spring, care a fost prezentat în capitolul anterior, și care oferă utilizatorului posibilitatea de a vizualiza anunțurile de mașini din cadrul a trei site-uri, mai exact Auto, Autovit și BestAuto, cu posibilitatea de a adăuga și altele, și de a beneficia de statistici diferite pe baza rapoartelor create cărora le cresc șansele să fie cât mai reale datorită numărului foarte mare de anunțuri. Aceasta verifică dacă anunțurile se mai regăsesc în paginile site-urilor analizate, iar în caz negativ, anunțurile respective se șterg în mod logic din baza de date, urmând ca peste o perioadă de timp determinată să fie șterse definitiv. Perioada de timp este în așa fel aleasă încât să se poată forma rapoartele săptămânale, respectiv lunare care vor contribui mai târziu la crearea unor rapoarte pe o perioadă mai îndelungată. Astfel se evită supraîncărcarea bazei de date cu informații nefolositoare. Crearea rapoartelor se efectuează, de asemenea, în mod automat la data sau intervalul prestabilit de dezvoltator.

Analiza și proiectarea aplicației

Componentele aplicației

Arhitectura aplicației AutoLead este reprezentată pe trei nivele mari: date, servicii și interfața cu utilizatorul. Primul nivel, al datelor, se ocupă de accesul la date și manipularea acestora. Acesta este repository-ul aplicației, unde se prelucrează majoritatea datelor, fiind reprezentat de interfețele DAO și de implementările lor. Nivelul serviciilor reprezintă logica aplicației, fiind responsabil pentru crearea tranzacțiilor, iar nivelul de prezentare, interfeța cu utilizatorul, este format din paginile JSP, utilizând controller-ele din nivelul seviciilor pentru a manipula cererile utilizatorilor. Structura pachetelor aplicației este ilustrată în diagrama componentelor din figura 3.1.1.

Figura 3.1.1. Diagrama componentelor pentru aplicația AutoLead

Componentele din interfața cu utilizatorul utilizează în mod direct pachetul Controller, respectiv pachetul Model. Obiectele Controller ale aplicației manipulează cererile ce provin de la nivelul de prezentare, validează datele, dacă este cazul, și decid care serviciu se va ocupa de cerere.

Componenta ServiceImpl este formată din obiectele care implementează interfețele Service aferente, realizând operațiile mai complexe și crearea tranzacțiilor, iar apoi trimit informațiile mai departe către pachetul DAO. Inclus în pachetul Service este și ReportScheduler, obiectul responsabil de declanșarea funcționalității de creare a rapoartelor, dar și clasele care implementează mecanismul Spring Security de care am vorbit anterior.

Pachetul DAOImpl conține implementarea interfețelor DAO și este responsabil pentru trimiterea datelor către baza de date AutoLead prin maparea obiectelor Java, folosind Hibernate.

Pachetul Crawler conține componenta Scheduler. Aceasta este responsabilă pentru planificarea declanșării procesului de extragere a informațiilor de pe anumite site-uri Web, periodic, la o oră specificată. Periodicitatea depinde în mare măsură de frecvența de schimbare a datelor, dar, de asemenea, se ține cont și de alte cerințe. Din aceste motive, procesul de extragere a volumelor mari de date, este recomandat să fie rulat în timpul perioadelor de activitate de rețea mică, de exemplu pe timp de noapte.

Clasele din pachetul Crawler sunt folosite pentru a configura numărul firelor de execuție care se vor executa concurent pentru fiecare obiect moștenit de clasa abstractă Parser și apelarea interfețelor din pachetul Service după terminarea extragerilor informațiilor de pe Internet folosindu-se de componentele Parser aferente, pentru a le adăuga în baza de date relațională.

Componenta Parser este formată din obiecte care realizează două tipuri de extragere a datelor. În primul rând, se obțin datelor din fișierele XML pentru a preciza URL-urile site-urilor ale căror informații vor fi agregate și pentru a indica secțiunile paginilor HTML care trebuie să fie luate în vedere pentru fiecare site. Aceste secțiuni cuprind informațiile care trebuie să fie extrase de către al doilea tip de parser care se execută asincron cu ajutorul librăriei TaskExecutor de care dispune framework-ul Spring.

Figura 3.1.2 ilustrează diagrama de clase a aplicației AutoLead. Această diagramă descrie structura sistemului prin prezentarea claselor și a a relațiilor dintre ele. Pentru a păstra o anumită vizibilitate entitățile, atributele și operațiile, cu excepția celor private, respectiv protected, nu au fost incluse în diagramă.

Figura 3.1.2 Diagrama claselor pentru aplicația AutoLead

Structura bazei de date

Structura bazei de date pentru AutoLead nu este o structură complexă, fiind formată din opt tabele, precum se observă și în figura 3.1.3.

Figura 3.1.3 Structura bazei de date pentru aplicația AutoLead

Aceasta are ca și componentă principală tabela car_ads, care conține informațiile preluate de pe site-urile de specialitate, dar și datele adăugate de utilizatorii autentificați ai aplicației AutoLead. Tabela photos corespunde entității cu același nume și este folosită pentru a stoca fotografiile din anunțurile de mașini, având o relație de tipul many to one cu tabela car_ads.

Tabela users conține credențialele utilizatorilor și rolul acestora, de exemplu un administrator dispune de anumite funcționalități în plus față de un simplu utilizator autentificat. Aceasta este în strânsă legătură cu tabelele favorites, respectiv user_car_ads, care la rândul lor, au câte o cheie străină către tabela car_ads. Utilizatorii au posibilitatea de a-și salva anunțurile preferate, posibilitate care este datorată de stocarea cheilor primare ale tabelelor principale într-o singură locație, astfel apărând relația de tipul one to many precum este prezentată și în figura 3.2.1. user_car_ads resprezintă istoricul anunțurilor adăugate de un anumit utilizator și rămân în baza de date chiar dacă anunțul respectiv este șters, prin atribuirea unei valori specifice pentru status.

Tabela reports este folosită pentru a stoca rapoartele, iar reports_details detaliile acestora. Atributul frequency este de tipul ENUM și indică valorile posibile pe care le poate lua, un exemplu fiind valoarea „WEEKLY”. Pe baza acestor rapoarte săptămânale, se pot crea altele pentru o perioadă mai îndelungată fără a fi nevoie de informațiile din tabela car_ads.

În cele din urmă, tabela persistent_login, este necesară pentru funcționalitatea remember me al framework-ului Spring Security și înregistrează username-ul utilizatorului, în cazul de față fiind adresa de e-mail, și datele ultimelei autentificări ale acestuia.

Funcționalitățile aplicației

Pe lângă posibilitatea de a extrage și de prelucra informațiile de pe site-urile Web în mod automat, aplicația dispune de diverse funcționalități, de exemplu înregistrarea unui utilizator, autentificarea acestuia, vizualizarea și administrarea anunțurilor. Funcționalitățile aplicației AutoLead sunt prezentate în diagrama cazurilor de utilizare ilustrată în figura 3.1.4.

Figura 3.1.4 Diagrama cazurilor de utilizare pentru aplicația AutoLead

Securitatea aplicației AutoLead este oferită de Spring Security care oferă o soluție de securitate completă, manipulează autentificarea și autorizarea atât la nivelul cererii web cât și la nivelul invocării metodelor. Un utilizator autentificat poate avea roluri diferite. Rolurile definite de AutoLead sunt ROLE_ADMIN și ROLE_USER, care implică autorizarea unor funcționalități. Utilizatorul, o dată autentificat, poate să dispună de funcționalitățile autorizate, iar în cazul selectării opțiunii remember me, drepturile oferite nu îi expiră o dată cu terminarea sesiunii obișnuite, ci doar după perioada de timp specificată de către dezvoltatorul aplicației. În cazul de față, este vorba de două săptămâni, cu posibilitatea de modificare. Utilizatorul are dreptul la crearea unui singur cont prin adresa de e-mail, aceasta fiind unică, dar poate să își șteargă contul sau să își modifice profilul, cu excepția adresei de e-mail. Dacă procesul de înregistrare a fost terminat cu succes, clientul primește un e-mail care conține credențialele specificate. Acest proces este exemplificat în figura 3.1.5.

Figura 3.2.5 Diagrama de activități pentru înregistrarea unui utilizator

Afișarea anunțurilor este disponibilă pentru toți utilizatorii, indiferent dacă aceștia sunt autentificați sau nu. Anunțurile sunt afișate prin paginare cu posibilitatea de a fi filtrate și ordonate după anumite criterii. Căutarea rapidă implică o filtrare directă după marca și modelul autoturismelor din anunțuri, sistemul selectând din baza de date orice anunț ce conține în atributele marcă, model sau concatenarea celor două, cuvintele introduse de utilizator. În momentul selectării unui anunț, utilizatorul este redirectat către pagina în care sunt afișate toate informațiile anunțului respectiv cu posibilitatea de a-l adăga la favorite, dacă acesta este autentificat, pentru ca mai apoi să poată vizualiza lista personală de anunțuri preferate.

Un utilizator autentificat poate să adauge anunțuri noi, și de asemenea să își administreze lista personală de anunțuri prin vizualizarea sau ștergerea acestora. Un administrator poate să vizualizeze lista anunțurilor noi adăugate de utilizatorii aplicației și lista tuturor anunțurilor mai vechi de o anumită perioadă și ștergerea lor definitivă din baza de date. Acesta primește notificări cu numărul anunțurilor noi, respectiv numărul anunțurilor vechi, și decide dacă trebuie șterse sau nu.

Rapoartele afișate pot fi filtrate după tipul sau frecvența lor, de exemplu, statistici săptămânale sau lunare și nu țin cont de tipul utilizatorului. Acestea sunt create automat la intervale de timp specificate în configurația aplicației.

Procesul de extragere și prelucrare a informațiilor este, de asemenea, declanșat automat și este ilustrat în figura 3.1.6 prin diagrama de activitate.

Figura 3.1.6 Procesul de extragere a informațiilor prezentat în diagrama de activitate

Atributul ce conține data ștergerii al unui anunț marchează dacă anunțul respectiv a fost șters prin atribuirea datei ștergerii logice. Anunțurile cu data ștergerii mai veche decât aproximativ două luni, sunt considerate anunțuri șterse vechi și prin urmare sunt șterse din baza de date. Informațiile privind denumirea atributelor din paginile HTML sunt extrase din documentele XML prin maparea acestora în obiecte Attributes folosind JAXB și adnotările specifice pentru a configura crawler-ul și pentru indicarea părților ce trebuie extrase din conținutul HTML. Procesul crawling este executat pe mai multe fire de execuție, fiecare dintre ele verificând dacă URL-ul găsit în atributele „href” din etichetele (tag-urile) „a” sunt conforme cerințelor, de exemplu dacă încep cu URL-ul rădăcinii site-ului curent sau dacă nu încep cu URL-urile date în documentele XML. Dacă acestea sunt valide, se verifică dacă aparțin listei cu URL-urile anunțurilor aduse din baza de date în procesul de configurare. Cele care sunt incluse în lista respectivă sunt șterse din listă și se trece la următorul URL, altfel se trece la partea de extragere a informațiilor cu ajutorul parserului. Obiectele AutoParser, AutovitParser și BestAutoParser moștenesc clasa abstractă Parser și culeg informațiile din conținutul primit de crawler-ul configurat pentru clasa aferentă în mod asincron. La finalul prelucrării datelor, acestea verifică dacă informațiile corespund cerințelor, iar în caz afirmativ se adaugă în lista cu anunțuri noi ce vor fi adăugate la final. Lista finală cu URL-urile anunțurilor aduse din baza de date este considerată ca fiind lista anunțurilor expirate, urmând ca anunțurile respective să fie actualizate corespunzător.

Manual de utilizare

Cerințe hardware și software recomandate

Pentru crearea structurii proiectului și automatizarea dependențelor librăriilor aplicația AutoLead utilizează Apache Maven. Datorită flexibilității oferite, aplicația este configurată pentru a funcționa cu două servere, Apache Tomcat și Jetty, și cu posibilitatea de a fi extinsă foarte ușor. Atât Tomcat, cât și Jetty sunt gratuite (open-source) și oferă o performantă ridicată pentru aplicațiile Web, având suport pentru server-ul HTTP, clientul HTTP și javax.servlet container. Versiunile minime recomandate sunt 6.1.25 pentru Jetty, respectiv 7 pentru Apache Tomca. Rularea aplicației cu Jetty se efectuează prin instrucțiunea: mvn clean install jetty:run în linia de comandă, iar pentru Tomcat mvn clean install tomcat7:run sau prin configurarea acestuia și adăugarea war-ului aplicației în directorul webapps al locației configurate.

Pentru afișarea conținutului aplicației în mod corect, browser-ul trebuie să suporte jQuery și canvas.

Datorită faptului că aplicația prelucrează volume mari de date, cerințele recomandate privind partea hardware sunt următoarele:

CPU – Intel Core i3-3240T cu frecvența procesorului de 2.90GHz;

Memorie RAM – capacitate: 4GB cu tipul DDR3;

Hard Disk – capacitate: 400 GB.

Prezentarea aplicației

Aplicația AutoLead dispune de un meniu user-friendly fiind foarte ușor de utilizat iar unele funcționalități îi sunt disponibile și utilizatorului neautentificat. Acesta își poate crea un cont prin completarea următoarelor câmpuri ale formularului de înregistrare: adresă de e-mail și parolă care sunt obligatorii, nume, prenume, țară, județ, oraș și număr de telefon. Dacă datele introduse sunt valide, iar adresa de e-mail nu se regăsește în baza de date, utilizatorul primește un e-mail cu credențialele respective, altfel îi sunt afișate mesaje corespunzătoare de eroare. În cazul în care utilizatorul deține un cont, acesta se poate autentifica cu adresa de e-mai și parola, având posibilitatea de a selecta dacă dorește să rămână autentificat pe o perioadă mai îndelungată. Clientul își poate administra contul prin modificarea profilului. Toate conturile create prin intermediul aplicației au rolul unui utilizator simplu, cel de administrator putând fi oferit doar prin intermediul bazei de date.

Meniul din partea stângă include o căsuță destinată căutării rapide, adică o filtrare informațiilor după marca, modelul sau concatenarea celor două atribute ale anunțului. De exemplu: „audi a” va returna toate anunțurile cu autoturismele Audi și cu modele care încep cu „a”: A1,A2,A3 etc. Vizualizarea tuturor anunțurilor se obține prin selectarea simbolului unei mașini din cadul submeniului „Autorisme”. Tot din acest submeniu se poate selecta și o anumită marcă pentru care se va realiza o filtrare a datelor după marca respectivă. Pagina afișării listei de anunțuri conține un panou cu criterii de căutare și este ilustrată în figura 3.2.1. Utilzatorul poate selecta unul sau mai multe criterii precum marca, modelul, starea tehnică, combustibilul, cel mai vechi an de fabricație, prețul minim, respectiv prețul maxim, și de asemenea poate renunța la criteriile selectate prin apăsarea butonului cu detaliile căutate de la finalul panoului. Acesta dispune și de posibilitatea de a ordona rezultatele după vechimea anunțului sau prețul autoturismului, inițial fiind afișate în ordine descendentă după data adăugării. Acestea sunt afișate sub formă de paginare, câte douăzeci pe o pagină, iar fiecărui anunț îi sunt prezentate doar detaliile principale precum marca, modelul, prețul și valuta acestuia, anul fabricației, combustibilul, rulajul, starea tehnică și caroseria mașinii, respectiv țara și județul vânzătorului.

Figura 3.2.1 Afișarea anunțurilor cu autoturismele "BMW", neavariate și cu prețul minim de 5000 Euro pentru un administrator

Administratorul este notificat de anunțurile vechi, dar încă valabile și de anunțurile noi adăugate de utilizatorii aplicației prin numărul acestora, precum este ilustrat în figura 3.2.1. O dată cu creșterea numărului de astfel de anunțuri bara care indică gravitatea situației își schimbă culoarea. Prin selectarea unei notificări, se afișează sub formă de listă, detaliile corespunzătoare și un buton pentru ștergerea anunțului, respectiv pentru marcarea acestuia ca fiind vizionat, în cazul în care este un anunț nou.

Adăugarea unui anunț este o funcționalitate exclusiv doar pentru utilizatorii autentificați ai aplicației, și se realizează prin completarea câmpurilor formularului de adăugare ca de exemplu țara înmatriculării, kilometrajul și altele prezentate în figura 3.2.2.

Figura 3.2.2 Adăugarea unui anunț

Anunțurile adăugate de fiecare utilizator sunt afișate și administrate de aceștia, și de administrator.

Afișarea tuturor detaliilor unui anunț se realizează prin selectarea anunțului din lista corespunzătoare sau prin selectarea acestuia din lista utilizatorului de anunțuri adăugate sau de anunțuri favorite, în cazul în care utilizatorul este autentificat, caz în care poate adăuga (/șterge) anunțul în (/din) lista sa de anunțuri favorite cum este prezentat în figura 3.2.3.

Figura 3.2.3 Vizualizarea unui anunț de către un utilizator autentificat

Fiind o aplicație destinată extragerilor și prelucrărilor de date din diferite surse Web, afișarea diverselor rapoarte este o funcționalitate ce nu poate lipsi. Orice tip de utilizator are posibilitatea de a vizualiza rapoartele create în mod automat de AutoLead, un exemplu fiind ilustrat în figura 3.2.4.

Figura 3.2.4 Rapoarte vânzări totale pentru determinarea unui top al principalelor mărci de mașini

Utilizatorii pot opta pentru personalizarea rapoartelor în funcție de ceea ce îi interesează în particular, ca de exemplu care au fost cele mai vândute modele ale principalului producător de automobile, Dacia, în săptămâna precedentă, raport prezentat în figura 3.2.5.

Figura 3.2.5 Rapoarte vânzări pentru o anumită marcă selectată de utilizator

Activități și îmbunătățiri propuse

AutoLead este un exemplu de aplicație care are ca scop extragerea și prelucrarea informațiilor din diferite surse Web de anunțuri de automobile. Deși culegerea informațiilor este realizată cu succes, această funcționalitate poate să fie optimizată și să suporte și verificarea actualizării unui anunț din sursele respective.

Pentru extinderea aplicației, o funcționalitate propusă este reprezentată de studiul pieselor automobilelor. În prezent, mai multe mărci de automobile utilizează aceleași tipuri de piese pentru crearea vehiculelor. Prin adăugarea în baza de date a tuturor modelelor de autoturisme și a pieselor folosite, se poate verifica după extragerea informațiilor câte modele au fost înregistrate cu piesele respective. În acest fel, ar exista informații despre numărul de automobile vândute clasificate pe tipuri de piese, iar datorită acestei perspective, se pot crea statistici cu calcule probabilistice în vederea pieselor căutate în viitor care vor fi benefice pentru angajații service-urilor auto.

Deoarece în momentul de față, aplicația a fost axată pe culegea informațiilor doar despre autoturisme, aceasta poate să fie extinsă prin permiterea căutării crawler-ului și în sursele de date despre celelalte tipuri de vehicule.

O îmbunătățire propusă este dedicată interfeței, prin folosirea framework-ului relativ nou, AngularJS. Acesta îmbunătățește comunicarea cu utilizatorul și are posibilitatea de a extinde aplicația într-un mod impresionant inclusiv prin internaționalizare, fiind ușor de înțeles și de dezvoltat.

Printe alte adăugări sau îmbunătățiri ale aplicației AutoLead se numără și extinderea pe platformele sociale, ștergerea utilizatorilor de către un administrator, adăugarea utilizatorilor cu rolul de administator de către un alt administrator, adăugarea mai multor criterii de căutare ale autoturismelor și perfecționarea interfeței.

Concluzii

Având în vedere că majoritatea aplicațiilor Web au interfața construită prin seturi de șabloane HTML cu informațiile preluate dintr-o bază de date, o aplicație ideală pentru extragerea și prelucrarea datelor Web ar trebui să fie capabilă să culeagă informațiile din aceste șabloane și să creeze o copie identică a acestor baze de date.

În această lucrare a fost prezentată o metodă de a detecta în mod automat informații în format semistructurat din paginile Web, de a le extrage și de a le agrega. Pentru a realiza această performanță au fost folosite documente XML care cuprind principalele caracteristici ale paginilor Web pentru a obține setul de date corespunzător. Metoda descrisă în capitolele anterioare găsește nodurile rădăcină și principale ale paginii HTML, iar apoi începe procesul de parcurgere a etichetelor până la găsirea tuturor atributelor descrise în documentele XML. În momentul găsirii etichetelor corespunzătoare, începe procesul de prelucrare a informațiilor, urmând ca apoi să treacă la următorul atribut.

Acestea fiind spuse, aplicația AutoLead îndeplinește cerințele inițiale, deși are nevoie să fie optimizată și îmbunătățită cu multe alte funcționalități, precum calcularea probabilității creșterii vânzărilor pentru un anumit model de autoturism sau cele descrise în capitolul anterior.

Bibliografie

[1] Bill Evjen, Kent Sharkey, Thiru Thangarathinam, Michael Kay, Alessandro Vernet, Sam Ferguson. Professional XML, Wiley Publishing, Indianapolis, 2007

[2] Bill Kennedy, Chuck Musciano. HTML & XHTML the Definitive Guide 6th Ed., O'Reilly, Sebastopol, 2006

[3] Brett McLaughlin. Java and XML 2nd Ed., O'Reilly, Sebastopol, 2001

[4] Brian Benz, John R. Durant. XML Programming Bible, Wiley Publishing, New York, 2003

[5] Brian Goetz, Tim Peierls, Joshua Bloch, Joseph Bowbeer, David Holmes, Doug Lea. Java concurrency in practice, Addison Wesley Professional, Stoughton, 2006

[6] Cay S. Horstmann, Gary Cornell. Core Java Vol I – Fundamentals 8th Ed., Sun Microsystems, Birmingham, 2008

[7] Cay S. Horstmann, Gary Cornell. Core Java 2 Vol II – Advanced Features 7th Ed., Prentice Hall PTR, California, 2004

[8] Chris Giametta. Pro Flex on Spring, Appress, New York, 2009

[9] Clarence Ho, Rob Harrop. Pro Spring 3, Appress, New York, 2012

[10] Craig Walls. Spring in Action 4th Ed., Manning, Shelter Island, 2014

[11] Documentația oficială de la Oracle, http://www.oracle.com/technetwork/java/index.html

[12] Documentația oficială de la Spring, http://docs.spring.io/spring/docs/current/spring-framework-reference/html/

[13] Dr. Mark Lui, Mario Gray, Andy Chan, Josh Long. Pro Spring Integration, Appress, New York, 2011

[14] Elliotte Rusty Harold. XML 1.1 Bible 3rd Ed., Wiley Publishing, New York, 2004

[15] Elliotte Rusty Harold, W. Scott Means. HTML and XHTML the Definitive Guide 6th Ed., O'Reilly, Sebastopol, 2004

[16] Hisashi Kashima, Teruo Koyanagi. Kernels for Semi-Structured Data, Japonia, 16 pag

[17] Iain D. Craig. Object Oriented Programming Languages:Interpretation, Springer, London, 2007

[18] Jay Bryant, Mike Jones. Pro HTML5 Performance, Appress, New York, 2012

[19] Manuel A´ lvarez , Alberto Pan, Juan Raposo, Fernando Bellas, Fidel Cacheda. Extracting lists of data records from semi-structured web pages, Elsevier, 19 pag, 2007

[20] Mark Fisher, Jonas Partner, Marius Bogoevici, Iwein Fuld. Spring Integration in Action, Manning, Shelter Island, 2012

[21] Patrick Niemeyer and Jonathan Knudsen. Learning Java 3rd Ed., O'Reilly, Sebastopol, 2005

[22] Peter Lubbers, Brian Albers, Frank Salim. Pro HTML5 Programming 2nd Ed., Appress, New York, 2011

[23] Peter Mularien. Publishing Spring Security 3, Packt, Birmingham, 2010

[24] Richard Clark, Oli Studholme, Christopher Murphy, Divya Manian. Beginning HTML5 and CSS3, Appress, New York, 2012

[25] Richard H. Carver, Kuo-Chung Tai. Modern multithreading, Wiley Publishing, New Jersey, 2006

[26] Rob Harrop, Jan Machacek. Pro Spring, Appress, New York, 2005

[27] Rod Johnson, Juergen Hoeller, Alef Arendsen, Thomas Risberg, Colin Sampaleanu. Professional Java Development with the Spring Framework, Wiley Publishing, Indianapolis, 2005

[28] Timothy Fisher. Java phrasebook, Sams, U.S., 2007

Anexa citărilor

[1] – Subcap.2.3.2, Pag.45;

[2] – Subcap.2.1.2, Pag.35, 37;

[3] – Subcap.2.3.1, Pag.43;

[4] – Subcap.2.3.1, Pag.43; Subcap.2.3.3, Pag.46;

[5] – Subcap.1.1.3, Pag.11;

[6] – Subcap.1.1, Pag.6; Subcap.1.1.2, Pag.9;

[7] – Subcap.1.1.3, Pag.11;

[8] – Subcap.1.2.1, Pag.14; Subcap.1.2.3, Pag.19;

[9] – Subcap.1.3.3, Pag.27;

[10] – Subcap.1.2.2, Pag.18; Subcap.1.2.3, Pag.20; Subcap.1.3.1, Pag.21; Subcap.1.3.2, Pag.25;

[11] – Subcap.1.1.1, Pag.7; Subcap.2.3.3, Pag.47; Subcap 2.2, Pag.40;

[12] – Subcap.1.3.2, Pag.24; Subcap.1.3.3, Pag.26, 28; Subcap.1.3.1, Pag.21, 22;

[13] – Subcap.1.2.2, Pag.16;

[14] – Subcap.2.1.1, Pag.30, 31, 33;

[15] – Subcap.2.1.1, Pag.33, 34; Subcap.2.3.1, Pag.43;

[16] – Subcap.2.2.2, Pag.41;

[17] – Subcap.1.1.2, Pag.8, 9;

[18] – Subcap.2.1.2, Pag.36;

[19] – Subcap.2.2.2, Pag.41;

[20] – Subcap.1.3.2, Pag.25; Subcap.1.3.3, Pag.26, 27;

[21] – Cap.2, Pag.29; Subcap.2.3, Pag.42; Subcap.2.3.2, Pag.44;

[22] – Subcap.2.1.2, Pag.37, 38;

[23] – Subcap.1.3.1, Pag.23;

[24] – Subcap.2.1.2, Pag.38, 39;

[25] – Subcap.1.1.3, Pag.10, 12, 13;

[26] – Subcap.1.2, Pag.13; Subcap.1.2.1, Pag.15; Subcap.1.2.2, Pag.17;

[27] – Subcap.1.2.2, Pag.15; Subcap.1.2.3, Pag.19;

[28] – Subcap.2.1.1, Pag.29; Subcap.2.3, Pag.42; Subcap.2.3.2, Pag.44;

Bibliografie

[1] Bill Evjen, Kent Sharkey, Thiru Thangarathinam, Michael Kay, Alessandro Vernet, Sam Ferguson. Professional XML, Wiley Publishing, Indianapolis, 2007

[2] Bill Kennedy, Chuck Musciano. HTML & XHTML the Definitive Guide 6th Ed., O'Reilly, Sebastopol, 2006

[3] Brett McLaughlin. Java and XML 2nd Ed., O'Reilly, Sebastopol, 2001

[4] Brian Benz, John R. Durant. XML Programming Bible, Wiley Publishing, New York, 2003

[5] Brian Goetz, Tim Peierls, Joshua Bloch, Joseph Bowbeer, David Holmes, Doug Lea. Java concurrency in practice, Addison Wesley Professional, Stoughton, 2006

[6] Cay S. Horstmann, Gary Cornell. Core Java Vol I – Fundamentals 8th Ed., Sun Microsystems, Birmingham, 2008

[7] Cay S. Horstmann, Gary Cornell. Core Java 2 Vol II – Advanced Features 7th Ed., Prentice Hall PTR, California, 2004

[8] Chris Giametta. Pro Flex on Spring, Appress, New York, 2009

[9] Clarence Ho, Rob Harrop. Pro Spring 3, Appress, New York, 2012

[10] Craig Walls. Spring in Action 4th Ed., Manning, Shelter Island, 2014

[11] Documentația oficială de la Oracle, http://www.oracle.com/technetwork/java/index.html

[12] Documentația oficială de la Spring, http://docs.spring.io/spring/docs/current/spring-framework-reference/html/

[13] Dr. Mark Lui, Mario Gray, Andy Chan, Josh Long. Pro Spring Integration, Appress, New York, 2011

[14] Elliotte Rusty Harold. XML 1.1 Bible 3rd Ed., Wiley Publishing, New York, 2004

[15] Elliotte Rusty Harold, W. Scott Means. HTML and XHTML the Definitive Guide 6th Ed., O'Reilly, Sebastopol, 2004

[16] Hisashi Kashima, Teruo Koyanagi. Kernels for Semi-Structured Data, Japonia, 16 pag

[17] Iain D. Craig. Object Oriented Programming Languages:Interpretation, Springer, London, 2007

[18] Jay Bryant, Mike Jones. Pro HTML5 Performance, Appress, New York, 2012

[19] Manuel A´ lvarez , Alberto Pan, Juan Raposo, Fernando Bellas, Fidel Cacheda. Extracting lists of data records from semi-structured web pages, Elsevier, 19 pag, 2007

[20] Mark Fisher, Jonas Partner, Marius Bogoevici, Iwein Fuld. Spring Integration in Action, Manning, Shelter Island, 2012

[21] Patrick Niemeyer and Jonathan Knudsen. Learning Java 3rd Ed., O'Reilly, Sebastopol, 2005

[22] Peter Lubbers, Brian Albers, Frank Salim. Pro HTML5 Programming 2nd Ed., Appress, New York, 2011

[23] Peter Mularien. Publishing Spring Security 3, Packt, Birmingham, 2010

[24] Richard Clark, Oli Studholme, Christopher Murphy, Divya Manian. Beginning HTML5 and CSS3, Appress, New York, 2012

[25] Richard H. Carver, Kuo-Chung Tai. Modern multithreading, Wiley Publishing, New Jersey, 2006

[26] Rob Harrop, Jan Machacek. Pro Spring, Appress, New York, 2005

[27] Rod Johnson, Juergen Hoeller, Alef Arendsen, Thomas Risberg, Colin Sampaleanu. Professional Java Development with the Spring Framework, Wiley Publishing, Indianapolis, 2005

[28] Timothy Fisher. Java phrasebook, Sams, U.S., 2007

Anexa citărilor

[1] – Subcap.2.3.2, Pag.45;

[2] – Subcap.2.1.2, Pag.35, 37;

[3] – Subcap.2.3.1, Pag.43;

[4] – Subcap.2.3.1, Pag.43; Subcap.2.3.3, Pag.46;

[5] – Subcap.1.1.3, Pag.11;

[6] – Subcap.1.1, Pag.6; Subcap.1.1.2, Pag.9;

[7] – Subcap.1.1.3, Pag.11;

[8] – Subcap.1.2.1, Pag.14; Subcap.1.2.3, Pag.19;

[9] – Subcap.1.3.3, Pag.27;

[10] – Subcap.1.2.2, Pag.18; Subcap.1.2.3, Pag.20; Subcap.1.3.1, Pag.21; Subcap.1.3.2, Pag.25;

[11] – Subcap.1.1.1, Pag.7; Subcap.2.3.3, Pag.47; Subcap 2.2, Pag.40;

[12] – Subcap.1.3.2, Pag.24; Subcap.1.3.3, Pag.26, 28; Subcap.1.3.1, Pag.21, 22;

[13] – Subcap.1.2.2, Pag.16;

[14] – Subcap.2.1.1, Pag.30, 31, 33;

[15] – Subcap.2.1.1, Pag.33, 34; Subcap.2.3.1, Pag.43;

[16] – Subcap.2.2.2, Pag.41;

[17] – Subcap.1.1.2, Pag.8, 9;

[18] – Subcap.2.1.2, Pag.36;

[19] – Subcap.2.2.2, Pag.41;

[20] – Subcap.1.3.2, Pag.25; Subcap.1.3.3, Pag.26, 27;

[21] – Cap.2, Pag.29; Subcap.2.3, Pag.42; Subcap.2.3.2, Pag.44;

[22] – Subcap.2.1.2, Pag.37, 38;

[23] – Subcap.1.3.1, Pag.23;

[24] – Subcap.2.1.2, Pag.38, 39;

[25] – Subcap.1.1.3, Pag.10, 12, 13;

[26] – Subcap.1.2, Pag.13; Subcap.1.2.1, Pag.15; Subcap.1.2.2, Pag.17;

[27] – Subcap.1.2.2, Pag.15; Subcap.1.2.3, Pag.19;

[28] – Subcap.2.1.1, Pag.29; Subcap.2.3, Pag.42; Subcap.2.3.2, Pag.44;

Similar Posts