Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
laboratoare:laborator09 [2015/12/10 22:52]
Andrei Roșu-Cojocaru
laboratoare:laborator09 [2015/12/28 15:52] (current)
Andrei Roșu-Cojocaru
Line 1: Line 1:
 ====== Laborator 09 ====== ====== Laborator 09 ======
-====== ​Proiectarea de aplicații distribuite ​folosind ​framework-ul Hadoop ​======+====== ​Dezvoltarea interfețelor grafice cu utilizatorul ​folosind ​JavaFX ​======
  
 ===== Obiective ==== ===== Obiective ====
  
-  * înțelegerea modelului implementat ​de Hadoop ​pentru ​procesarea distribuită a unui volum mare de date, folosind clustere formate din mașini fără performanțe distribuite,​ larg disponibile ​în comerț (//eng.// commodity hardware); +  * familiarizarea cu facilitățile oferite ​de tehnologia JavaFX ​pentru ​dezvoltarea ​de interfețe cu utilizatorul ​în comparație cu alte soluții existente; 
-  * descrierea ​principalelor ​module integrate de framework-ul Hadoop; +  * identificarea ​principalelor ​componente din cadrul arhitecturii JavaFX; 
-  * cunoașterea produselor care funcționează împreună cu modulele Hadoop, funcționalitatea pe care o pun la dispoziție și oportunitatea folosirii lor; +  * descrierea structurii generale a unei aplicații JavaFX ​și a firelor de execuție din contextul cărora pot fi accesate obiectele corespunzătoare controalelor grafice, respectiv interacțiunii cu utilizatorul; 
-  * configurarea framework-ului Hadoop (HDFS, YARN) și a bazei de date distribuite HBase pe un cluster format dintr-o singură mașină; +  * implementarea unei interfețe cu utilizatorul folosind Scene Builder / FXML cu injectarea controalelor grafice / metodelor ​de tratare a evenimentelor în clasa controller din codul sursă; 
-  * utilizarea paradigmei ​de programare Map/Reduce pentru procesarea distribuită ​a unui volum mare de date; +  * înțelegerea mecanismului ​de tratare ​a evenimentelor legate ​de interacțiunea ​cu utilizatorul ​în JavaFX; dezvoltarea de filtre și metode de tratare pentru ​diferite ​acțiuni ​ale utilizatorului; 
-  * familiarizarea ​cu modul în care sunt gestionate sarcinile Map/​Reduce ​în diferite ​implementări ​ale framework-ului Hadoop (Map/Reduce "​clasic",​ respectiv YARN);+  * însușirea practicilor utilizate pentru dezvoltarea aplicațiilor JavaFX.
  
 ===== Cuvinte Cheie ==== ===== Cuvinte Cheie ====
  
-Hadoop, cluster, commodity hardware, Google File System, Hadoop Distributed File System, YARN, Map-Reduce, HBase, ZooKeeper, Oozie, Pig, Hive, HDFS federation, namenode, datanode, Job Tracker, Task Tracker, Resource Manager, Node Manager, Application Master+JavaFX, FXML, Scene Builder, Quantum Toolkit, Prism, Glass, Pulse, GStreamer, WebKitHTML, CSS, layout
  
 ===== Materiale Ajutătoare ====== ===== Materiale Ajutătoare ======
  
-===== Framework-ul Hadoop - aspecte generale =====+TODO
  
-Hadoop este un proiect open-source dezvoltat de Apache care îşi propune realizarea de procesări distribuite a unor seturi de date de dimensiuni mari, rulând pe mai multe clustere, folosind modele de programare simple. Proiectarea acestui framework a fost realizată astfel încât să fie scalabilă chiar şi în situaţia în care sarcinile sunt rulate pe mii de calculatoare,​ fiecare dintre acestea punând la dispoziţie o anumită capacitate de procesare şi de stocare.+===== JavaFX ​- aspecte generale =====
  
-<​note>​Un cluster ​este un set de mai multe maşini, legate prin intermediul unei reţele de calculatoare,​ care se găsesc în aceeaşi locaţie fizică. Nu este necesar ca performanţele pe care le oferă acestea să fie foarte ridicate, scalarea realizându-se nu prin adăugarea de resurse la o maşină (de vreme ce legea lui Moore oricum nu poate acoperi creşterea cantităţii de date), ci prin creşterea numărului de maşini în cadrul ​unui cluster, respectiv prin creşterea numărului de clustere, framework-ul Hadoop fiind proiectat ​pentru ​a gestiona astfel de modificări. Mai mult, spre diferenţă de modelul "​tradițional"​ de procesare distribuită,​ nu se face o separare între noduri de procesare ​şi noduri de stocare (întrucât pot apărea blocaje) ci un nod implementează ambele funcţionalităţi, fiind procesate datele stocate local.</​note>​+JavaFX ​este o tehnologie pusă la dispoziţie programatorilor Java pentru a implementa sisteme informatice ​ce implică interacțiune cu utilizatorul, având un comportament consistent pe mai multe platforme diferite. În cadrul ​JavaFX a fost dezvoltat un API extins ​pentru ​aplicaţii multimedia avansate ​şi motoare grafice care facilitează proiectarea și dezvoltarea unor aplicaţii pentru organizaţii bazate pe date. 
  
-<​note>​Spre diferenţă ​de sistemele Grid şi Cloud, Hadoop nu se bazează pe hardware-ul maşinilor care fac parte din cluster pentru a oferi un nivel de disponibilitate ridicat, ci are capabilitatea ​de a detecta (la nivel software) erorile care se produc, gestionând astfel de situaţii (în special prin replicarea datelor ​şi re-execuţia sarcinilor), garantând realizarea sarcinilor, inclusiv prin redirecţionarea lor pe alte maşini.</​note>​+Fiind implementat peste limbajul ​de programare Java, acesta va fi uşor de utilizat, optimizând costurile legate ​de investiţii şi complexitatea sistemelor, întrucât atât componenta server (nivelul de logică a aplicaţiei şi de acces la date) cât şi componenta client (nivelul de prezentare) vor fi dezvoltate utilizând acelaşi limbaj de programare.
  
-Un programator care proiectează aplicaţii distribuite folosind Hadoop nu trebuie să gestioneze evenimentele care se pot produce ​la nivelul unei maşini, concentrându-se ​pe dezvoltarea logicii ​aplicaţiei,​ în timp ce partiţionarea datelor ​şi distribuirea codului vor fi realizate ​în mod transparent ​prin intermediul ​framework-ului, ​interacţiunea dintre ​componente fiind definită în cadrul unor interfeţe standardizate.+Câteva dintre caracteristicile JavaFX 8 sunt următoarele: 
 +  * **integrare cu Java**. JavaFX ​ este o interfaţă de programare integrată în distribuţia limbajului de programare Java, instalarea sa făcându-se împreună cu acesta; prin urmare, din JavaFX ​pot fi accesate toate API-urile Java cu funcţionalităţile lor, acesta reprezentând o alternativă ​la celelalte limbaje de programare care folosesc Java Virtual Machine, precum JRuby sau Scala;  
 +  * **limbajul de adnotare FXML şi utilitarul SceneBuilder**. FXML este un limbaj declarativ de adnotare bazat pe XML prin intermediul căruia pot fi dezvoltate interfeţe grafice cu utilizatorul,​ fără a fi necesar ca aplicaţia să fie recompilată de fiecare dată când sunt modificate elemente din cadrul acesteia. În acest mod se realizează o separare între nivelul de prezentare și nivelul de logică a aplicației. SceneBuilder permite construirea interfeţei în mod vizual, generând automat şi documentul FXML asociat, acesta putând fi integrat apoi în orice mediu de dezvoltare. Astfel, nu mai este necesară decât implementarea mecanismelor de tratare a evenimentelor corespunzătoare diferitelor controale (elemente din cadrul interfeței grafice); 
 +  * **componente WebView**. Un modul ce foloseşte tehnologia WebKitHTML permite integrarea de pagini Internet în cadrul unei interfeţe grafice. De asemenea, codul JavaScript ce rulează în [[https://​docs.oracle.com/​javase/​8/​javafx/​api/​javafx/​scene/​web/​WebView.html|WebView]] poate accesa orice API-uri Java, la fel cum API-urile Java pot executa cod JavaScript care rulează în WebView. Există suport și pentru anumite funcționalități HTML5 (Web Sockets, Web Workers, Web Fonts) sau capabilități de tipărire;​ 
 +  * **interoperabilitate cu tehnologia Swing**. Aplicaţiile Swing existente pot fi extinse cu funcţionalităţi JavaFX, ca redarea de conţinuturi grafice sau a unor pagini Internet integrate. Clasa [[https://​docs.oracle.com/​javase/​8/​javafx/​api/​javafx/​embed/​swing/​SwingNode.html|SwingNode]] permite integrarea unui conținut dezvoltat folosind tehnologia Swing în cadrul aplicației JavaFX; 
 +  * **biblioteci de controale şi foi de stil**. JavaFX pune la dispoziţia programatorilor majoritatea controalelor necesare pentru dezvoltarea unei interfeţe cu utilizatorul complete (inclusiv [[https://​docs.oracle.com/​javase/​8/​javafx/​api/​javafx/​scene/​control/​DatePicker.html|DatePicker]] și [[https://​docs.oracle.com/​javase/​8/​javafx/​api/​javafx/​scene/​control/​TreeTableView.html|TreeTableView]]),​ aspectul acestora putând fi particularizat folosind tehnologii web standard ca foile de stil (//eng.// CSS – cascading style sheets), ​prin intermediul ​claselor ''​Styleable*'';​ 
 +  * **tema Modena** este folosită ca implicită pentru toate aplicațiile JavaFX (înlocuind tema Caspian, care poate fi utilizată prin apelul metodei ''​setUserAgentStylesheet(STYLESHEET_CASPIAN)''​ în metoda ''​start()''​ a clasei derivate din ''​Application'';​ 
 +  * **funcționalități de grafică 3D**. Biblioteca de grafică 3D a fost îmbogățită prin: 
 +    * implementarea claselor: 
 +      * ''​javafx.scene.shape.Shape3D''​ (cu subclasele ''​Box'',​ ''​Cylinder'',​ ''​MeshView'',​ ''​Sphere''​) 
 +      * ''​javafx.scene.SubScene''​ 
 +      * ''​javafx.scene.paint.Material''​ 
 +      * ''​iavafx.scene.input.PickResult''​ 
 +      * ''​javafx.scene.LightBase''​ (cu subclasele ''​AmbientLight''​ și ''​PointLight''​) 
 +      * ''​javafx.scene.SceneAntiAliasing''​ 
 +    * îmbunătățirea API-ului ''​Camera'';​ 
 +  * **API-ul Canvas** permite desenarea pe o suprafaţă dintr-o scenă JavaFX conţinând un element grafic (de tip nod); 
 +  * **API-ul pentru tipărire** este conținut în pachetul ''​javafx.print''​, oferind posibilitatea configurării modului în care vor fi tipărite scenele dintr-o interfață grafică sau diferite documente;​ 
 +  * **suport pentru text stilizat**. Controalele JavaFX pot reda informații de tip text în mai multe moduri: bidirecțional,​ multilinie, folosind mai multe stiluri grafice, incluzând seturi de caractere complexe; 
 +  * **suport pentru operaţii multi-touch**. JavaFX poate procesa mai multe operații de tip atingere a ecranului concomitente în cazul dispozitivelor care suportă astfel de comenzi; 
 +  * **suport pentru dispozitive de afișare cu rezoluție mare (HiDPI - //eng.// High Dots per Inch)**; 
 +  * **grafică accelerată hardware la nivel de bandă de asamblare**. JavaFX dispune de un motor pentru redarea conţinutului grafic denumit Prism care oferă performanţe deosebite atunci când este utilizat împreună cu anumite plăci grafice sau unităţi de procesare grafică (//eng.// GPU – Graphic Processing Unit). În cazul în care un sistem nu dispune de una dintre ​dispozitivele recomandate pentru a rula împreună cu JavaFX, Prism va folosi ​în mod implicit stiva de aplicaţii Java2D; 
 +  * **motor multimedia performant**,​ pentru redarea de conţinut multimedia folosind tehnologia GStreamer, caracterizată prin latenţă scăzută şi stabilitate;​ 
 +  * **model de dezvoltare al aplicaţiilor autonome**. Există pachete de aplicaţii independente care dispun de toate resursele necesare precum şi de copii ale mediilor de rulare Java şi JavaFX distribuite ca pachete native ce pot fi instalate oferind utilizatorilor aceeaşi experienţă ca şi celelalte aplicaţii native sistemului de operare respectiv. 
  
-Hadoop a fost creat de Doug Cutting, cel care realizase şi biblioteca pentru căutări în texte Apache Lucene. Ideea acestui proiect a plecat de la Apache Nutch, un motor de căutare web open-source,​ lansat în 2002, care nu era însă scalabil pentru miliardele de pagini ce ar fi trebuit indexate spre a oferi rezultate corecte. Pe baza unui articol din 2003 care descria sistemul de fişiere distribuite al celor de la Google (GFS), ​este lansat Nutch Distributed Filesystem (NDFS) ce rezolva atât problema spaţiului de stocare al fişierelor generate în urma proceselor de indexare a paginilor Internet cât şi sarcinile administrative de gestionare a nodurilor de stocare. Un model similar este urmat şi în cazul Map-Reduce: dacă în 2004 Google publica articolul prin care era prezentat acest concept, implementarea sa în Nutch devenea deja funcţională în 2005. În 2006, odată cu mutarea lui Doug Cutting la Yahoo!, apare noţiunea de Hadoop iar în 2008 acesta era deja folosit pentru ​motorul ​ de căutare web al Yahoo! folosind un cluster din 10.000 noduri. Apache acordă o importanţă deosebită proiectului,​ ce devine o prioritate a organizaţiei, după ce acesta devenise cel mai rapid sistem care sortase 1 TB de date (209 secunde, pe un cluster format din 910 noduri). În cadrul aceluiaşi an, recordul avea să fie depăşit ​de încă două ori: implementarea MapReduce de la Google sortase 1TB de date în 68 de secunde, în timp ce sistemul celor de la Yahoo! reuşise aceeaşi performanţă în numai 62 de secunde. Investiţiile ​în cercetare destinate acestui proiect devin din ce în ce mai mari, achiziţionându-se clustere ce depăşesc 1000 de noduri pe care sunt încărcate seturi de date ce atingeau ordinul sutelor de terrabytes. Începând ​cu anul 2010, Hadoop a fost adoptat pe scară largă de organizaţii atât în scopul de a stoca volume mari de date cât şi ca platformă ​de analiză a acestora. +JavaFX ​este folosit pentru ​aplicaţii care folosesc reţeaua de calculatoare, fiind capabile ​să ruleze pe mai multe tipuri ​de platforme, în care informaţiile ​pot fi vizualizate folosind o interfaţă cu utilizatorul performantă care foloseşte capabilităţi audio şi video (inclusiv tehnici ​de grafică avansată şi animaţii).
-În prezent, Hadoop este folosit de numeroase companii pentru care volumul de date generat zilnic depăşeşte capacităţile de procesare ​şi stocare specifice sistemelor convenţionale: Adobe, AOL, Amazon.com, EBay, Facebook, Google, LinkedIn, Twitter, Yahoo.+
  
-Framework-ul Hadoop include mai multe module: +Aplicaţiile JavaFX pot fi rulate: 
-  * **Hadoop Common**: utilitare de bază care oferă funcţionalităţile pentru celelalte module; +  * direct pe o anumită maşină, unde se află "​instalată"​ (accesând fişierul .jar care conţine programul în sine) - o astfel de opţiune este preferată în cazul în care aplicaţia nu are nevoie de acces Internet sau maşina pe care rulează nu dispune de o astfel de conexiune; 
-  * **Hadoop Distributed File System ​(HDFS)**: sistem ​de fişiere distribuite ce pune la dispoziţie un nivel de disponibilitate ridicat la datele utilizate de aplicaţii; +  * prin intermediul unui navigator ​(//eng.// browser), fiind integrată în cadrul unei pagini Internet, interacţiunea cu elementele paginii Internet putând fi realizată prin intermediul limbajului JavaScript;​ 
-  * **Hadoop YARN**: modul pentru planificarea sarcinilor ​şi gestiunea resurselor din cadrul unui cluster; +  ​* prin descărcare ​de la o anumită locaţie (dacă ​aplicația JavaFX este găzduită pe un server web), rulând apoi pe maşina respectivă (modul WebStart); 
-  * **Hadoop Map-Reduce**:​ sistem bazat pe YARN pentru procesarea paralelă a unor seturi mari de date.+  * ca program autonom, folosind copii private ale mediilor ​de rulare Java şi JavaFX.
  
-În plus, au fost dezvoltate mai multe produse care pot fi folosite împreună cu Hadoop / HDFS: +===== Arhitectura JavaFX =====
-  * **HBase**: bază de date distribuită,​ scalabilă care suportă stocarea informaţiilor structurate pentru tabele de dimensiuni mari; implementată sub forma unor perechi cheie-valoare,​ foloseşte de obicei sistemul de fişiere distribuit HDFS deşi poate fi folosit şi împreună cu sistemul de fişiere local; +
-  * **ZooKeeper**:​ serviciu de coordonare performant pentru aplicaţii distribuite;​ +
-  * **Oozie**: modulul pentru gestiunea şi planificarea fluxurilor, coordonând fluxurile Map-Reduce;​ +
-  * **Pig**: limbaj de nivel înalt pentru procesarea fluxurilor de date şi mediu de execuţie pentru prelucrări paralele; +
-  * **Hive**: depozit de date cu interfaţă SQL care oferă sumarizarea datelor şi interogări ad-hoc.+
  
-Există mai mulţi producători care pun la dispoziţie distribuţii Hadoop, al căror scop este oferirea unei configuraţii care rezolvă incompatibilităţile dintre diferite produse, prin rularea unor teste de integrare între acestea.+Platforma JavaFX dispune de o arhitectură bazată pe o stivă de componente (transparentă pentru programator),​ constituind motorul ce rulează codul propriu-zis (Quantum Toolkit). Acesta cuprinde un motor grafic performant (Prism), un eficient sistem ​de ferestre, de dimensiuni mici (Glass), un motor pentru redarea conţinutului multimedia şi un motor pentru integrarea conţinutului Internet.
  
-Produsele Hadoop integrate în cele mai multe dintre distribuţii sunt HDFS, MapReduce, HBase, Hive, Mahout, Oozie, Pig, Sqoop, Whirr, ZooKeeper, Flume. De asemenea, proiectul BigTop (dezvoltat de Apache) are rolul de a rula teste de interoperabilitate între componentele Hadoop oferind pachete Linux (RPM şi pachete Debian) pentru o instalare mai facilă.+{{ :​laboratoare:​laborator09:​01javafxarchitecture.png?nolink }}
  
-Distribuţiile sunt realizate în mai multe formate, suportă un set de sisteme de operare şi pot include scripturi suplimentare pentru rularea mediului de lucru. ​+==== Setul de API-uri Java pentru funcționalități JavaFX ====
  
-<​note>​De regulă, este vorba despre sisteme ​de operare Linux (RedHat Enterprise, CentOS, Oracle Linux, Ubuntu, SUSE Linux Enterprise Server).</​note>​+Platforma JavaFX permite accesul la setul de API-uri Java pentru a dezvolta aplicaţii ce implică interacțiunea cu utilizatorul într-un mod flexibil, exploatând capabilităţi ale acestui limbaj ​de programare de nivel înalt, precum: 
 +  * utilizarea unor funcționalități Java, cum ar fi: clase generice, adnotări, lucrul cu mai multe fire de execuție, expresii Lambda; 
 +  * accesul la JavaFX pentru dezvoltatorii de aplicații Internet din cadrul altor limbaje dinamice bazate pe mașina virtuală Java (Groovy, JavaScript);​ 
 +  * accesul la alte limbaje dinamice bazate pe mașina virtuală Java pentru implementarea de aplicații JavaFX complexe; 
 +  * folosirea unei biblioteci de asocieri ce include suport pentru rezolvarea leneșă a referințelor, legarea expresiilor și secvențelor de expresii, reevaluarea parțială a asocierilor (aceasta putând fi utilizată și din alte limbaje dinamice bazate pe mașina virtuală Java, printr-o sintaxă similară); 
 +  * extinderea bibliotecilor de colecții Java cu liste sau asocieri observabile,​ care permit aplicațiilor să realizeze conexiuni între interfețe și modelele de date, permițând actualizarea interfeței grafice conform cu modificările detectate în cadrul modelelor de date.
  
-Între distribuţiile ​mai cunoscute se numără Cloudera Distribution for Hadoop (CDH), MapR Distribution,​ Hortonworks Data Platform (HDP), Apache BigTop Distribution,​ Greenplum HD Data Computing Appliance. Acestea dispun şi de propriile documentaţii (inclusiv wiki) şi oferă utilizatorilor maşini virtuale pe care sunt instalate distribuţiile în cauză.+API-urile JavaFX au fost portate direct în Java, bazându-se ​mai mult pe standarde Internet, cum ar fi CSS pentru stilizarea controalelor sau ARIA pentru specificări referitoare la accesibilitate.
  
-Versiunile Hadoop întreţinute în prezent sunt 1.2.x, 2.6.x şi 0.23.x (similară cu 2.x, fără nivelul ​de disponibilitate ridicat pentru nodurile de nume). Îmbunătăţirile aduse în cadrul versiunii 2.6.x sunt: +==== Graful ​de Scene ====
-  * implementarea **federaţiilor HDFS**, ce utilizează mai multe noduri (spaţii) de nume independente (care nu necesită coordonare între ele); nodurile de date sunt utilizate ca spaţii de stocare pentru blocuri de către toate nodurile de nume. Pentru implementarea unei astfel de funcţionalităţi,​ este necesar ca fiecare nod de date să fie înregistrat de toate nodurile de nume din cluster. Acestea vor transmite rapoarte periodice cu privire la blocurile pe care le stochează, gestionând comenzile care provin de la nodurile de nume.\\ \\ {{ :​laboratoare:​laborator10:​figura01_federatii_HDFS.png?​nolink }} \\ \\ Din acest motiv, nodurile de date stochează blocuri aparţinând tuturor federaţiilor de blocuri (//eng.// block pool) din cadrul cluster-ului,​ fiecare dintre ele fiind gestionate separat de alte astfel de obiecte. O federaţie de blocuri este reprezentată de un set de blocuri ce aparţine unui singur spaţiu de nume. În acest mod, un spaţiu de nume poate genera identificatori pentru blocuri fără a fi necesară coordonarea cu alte spaţii de nume şi în acelaşi timp, erorile produse la nivelul unui nod de nume nu împiedică nodul de date de a lucra cu alte noduri de nume din cluster. Un spaţiu de nume împreună cu federaţia sa de blocuri poartă denumirea de volum al spaţiului de nume, acesta fiind o unitate de gestiune autonomă. Atunci când un nod (spaţiu) de nume este şters, şi federaţia sa de blocuri de la nivelul nodurilor de date este ştearsă. Actualizările de la nivelul volumului unui spaţiu de nume se realizează unitar, atunci când se produce actualizarea unui cluster. Toate nodurile din cadrul unui cluster partajează un identificator al clusterului,​ generat în mod automat la formatarea unui nod de nume. Un astfel de identificator ar trebui să fie folosit şi pentru formatarea altor noduri de nume în cadrul cluster-ului respectiv.\\ \\ Beneficiile acestei îmbunătăţiri includ **scalabilitatea spaţiului de nume** (spaţiul de stocare al clusterului HDFS este caracterizat prin scalabilitate,​ astfel încât proiectele de dimensiuni mari sau cele care utilizează numeroase fişiere de dimensiuni mai mici pot beneficia de scalabilitatea spaţiului de nume prin adăugarea mai multor noduri de nume la cluster), **performanţa** (îmbunătăţirea ratei de transfer pentru operaţiile de citire / scriere în cadrul sistemului de fişiere prin adăugarea mai multor noduri de nume în cadrul clusterului) şi **izolarea** (categorii diferite de aplicaţii şi utilizatori pot fi izolate în cadrul unor spaţii de nume diferite). Într-o arhitectură care foloseşte un singur spaţiu de nume, într-un mediu concurent, o aplicaţie poate suprasolicita spaţiu de nume astfel încât performanţele celorlalte aplicaţii ce utilizează acelaşi spaţiu de nume vor fi afectate.+
  
-  * **implementarea MapReduce NextGen** (**YARN, MRv2**) prin care se împart funcţionalităţile modulului ​de monitorizare a sarcinilor ​(//​eng.// ​Job Tracker) – gestiunea resurselor şi planificarea sarcinilor în procese separate; în acest mod, se creează **un modul global de gestiune al resurselor** (Resource Manager) şi **un modul de bază al aplicaţiei** (Application Master) pentru fiecare aplicaţie în parte. O aplicaţie este formată fie dintr-o singură sarcină (din punctul ​de vedere al sarcinilor de tip MapReduce) sau conţine ​un graf aciclic de sarcini. Modulul de gestiune al resurselor împreună cu **modulul de gestiune al nodurilor** (Node Manager) formează cadrul de calcul al sarcinilor. Modulul de gestiune al resurselor este autoritatea care arbitrează modul de distribuire al resurselor pentru aplicaţiile din sistem. Modulul de gestiune pentru aplicaţii este de fapt o bibliotecă ce negociază resursele primite de la modulul de gestiune al resurselor colaborând ​cu modulele de gestiune a nodurilor pentru a executa şi pentru a monitoriza sarcinile.\\ \\ {{ :​laboratoare:​laborator10:​figura02_arhitectura_yarn.png?​nolink }} \\ \\ Modulul pentru gestiunea resurselor cuprinde două componente de bază: **modulul de planificare** şi **modulul de gestiune al aplicaţiilor**.\\ \\  Modulul de planificare este responsabil pentru alocarea resurselor către diferite aplicaţii, caracterizate prin constrângeri referitoare la capacitate, cozi. Acesta nu oferă însă nici o garanţie în privinţa repornirii sarcinilor eşuate datorită erorilor produse la nivel hardware sau software şi nici nu se ocupă cu monitorizarea stării aplicaţiilor. Planificarea se realizează în funcţie de cerinţele pentru resurse ale aplicaţiilor,​ specificate de noţiunea abstractă container ​care cuprinde elemente ca memorie, procesor, disc, reţea. În versiunile anterioare ale Hadoop, singurul criteriu luat în considerare de planificator era reprezentat de memorie. Modulul de planificare suportă extensii programabile (precum CapacityScheduler sau FairScheduler) responsabile cu partiţionarea clusterului între ​diferite ​aplicaţii. Extensia programabilă CapacityScheduler suportă cozi ierarhice pentru a permite partajarea resurselor clusterului în funcţie ​de previziuni.\\ \\ Modulul de gestiune al aplicaţiilor se ocupă cu acceptarea sarcinilor transmise, negociind container-ul pentru executarea modulului de bază al aplicaţiei,​ oferind servicii pentru repornirea container-ului acestuia în situaţia în care s-au produs erori.\\ \\ Modulul de gestiune al nodurilor este un cadru implementat pe fiecare maşină în parte, responsabil pentru containere, monitorizându-le utilizarea resurselor (procesor, memorie, disc, reţea) ​şi raportând aceste valori la modulul de gestiune al resurselor şi la modulul de planificare.\\ \\ Modulul de bază al aplicaţiei are rolul de a negocia containerele de resurse corespunzătoare de la modulul de planificare,​ monitorizându-le starea.+Implementarea unei aplicații JavaFX implică proiectarea și dezvoltarea unui graf de scene (//​eng.// ​Scene Graph), structură ierarhică de noduri ce conţine ​elementele vizuale ale interfeţei grafice ​cu utilizatorul, care poate trata diferite ​evenimente legate ​de acestea ​şi care poate fi redată. 
  
-<​note>​MapReduce v2 menţine compatibilitatea ​cu versiunile anterioare, astfel ​încât acestea ​pot rula şi în noul cadru de execuţie după ce sunt recompilate.</​note>​+Un element din graful de scene (= un nod) este identificat în mod unic, fiind caracterizat printr-o clasă de stil şi un volum care îl delimitează. Fiecare nod are un părinte (cu excepția nodului rădăcină), putând avea nici unul, unul sau mai mulţi copii. De asemenea, pentru un astfel ​de element ​pot fi definite efecte (estompări sau umbre), opacitate, transformări,​ mecanisme de tratare a diferitelor evenimente (care vizează interacţiunea cu utilizatorul) precum ​şi starea aplicaţiei. 
  
-Funcţionalităţile implementate ​de diferitele versiuni Hadoop, cu privire la HDFS şi MapReduce pot fi sintetizate astfel:+Spre diferenţă de Swing sau AWT (Abstract Window Toolkit), JavaFX conţine pe lângă mecanisme ​de dispunere a conţinutului, controale, imagini sau obiecte multimedia ​şi primitive pentru elemente grafice (ca fi texte sau figuri geometice cu care se pot crea animaţii, folosind metodele puse la dispoziţie de API-urile ''​javafx.animation''​).
  
-<​html>​ +API-ul ''​javafx.scene''​ permite construirea următoarelor conţinuturi:​ 
-<​center>​ +  * **noduri**: forme 2D şi 3D, imagini, conţinut multimedia şi conţinut Internet, text, controale pentru interacţiunea cu utilizatorul,​ grafice, containere; 
-</​html>​+  * **stări**: transformări (poziţionări şi orientări ale nodurilor), efecte vizuale; 
 +  * **efecte**: obiecte care modifică aspectul nodurilor (mecanisme de estompare, umbre, reglarea culorilor).
  
-^  Funcţionalitate ​ ^  1.2.x  ^  0.23.x ​ ^  2.6.x  ^ +=== Mecanisme ​de Dispunere a Conţinutului ===
-| autentificare sigură | da | nu | da | +
-| nume de configurare vechi | da | învechite | învechite | +
-| nume de configurare noi | nu | da | da | +
-| API MapReduce vechi | da | da | da | +
-| API MapReduce nou | da (biblioteci lipsă) | da | da | +
-| cadru de rulare MapReduce 1 (clasic) | da | da | nu | +
-| cadru de rulare MapReduce 2 (YARN) | nu | nu | da | +
-| federaţii HDFS | nu | nu | da | +
-| nivel de disponibilitate HDFS ridicat | nu | nu | da |+
  
-<html> +Controalele din graful de scene pot fi grupate în containere sau panouri în mod flexibil, folosind mai multe mecanisme de dispunere a conținutului (//eng.// layout).  
-</center> + 
-</html>+API-ul JavaFX defineşte mai multe clase de tip container pentru dispunerea elementelor,​ în pachetul ''​javafx.scene.layout'':​ 
 +  * ''​BorderPane''​ dispune nodurile conţinute în regiunile de sus, jos, dreapta, stânga sau centru; 
 +  * ''​HBox''​ îşi aranjează conţinutul orizontal pe un singur rând; 
 +  * ''​VBox''​ îşi aranjează conţinutul vertical pe o singură coloană; 
 +  * ''​StackPane''​ utilizează o stivă de noduri afişând elementele unele peste altele, din spate către față; 
 +  * ''​GridPane''​ permite utilizatorului să îşi definească un tabel (format din rânduri şi coloane) în care să poată fi încadrate elementele conţinute;​ 
 +  * ''​FlowPane''​ dispune elementele fie orizontal, fie vertical, în funcţie de limitele specificate de programator (lungime pentru dispunere orizontală,​ respectiv înălţime pentru dispunere verticală);​ 
 +  * ''​TilePane''​ plasează nodurile conţinute în celule de dimensiuni uniforme; 
 +  * ''​AnchorPane''​ oferă programatorilor posibilitatea de a defini noduri ancoră (referinţă) în funcţie de colţurile de jos / sus, din stânga / dreapta sau raportat la centrul containerului sau panoului. 
 + 
 +Diferitele moduri de dispunere pot fi imbricate în cadrul unei aplicaţii JavaFX pentru a se obţine funcţionalitatea dorită. 
 + 
 +=== Tipuri de Controale Grafice === 
 + 
 +Controalele pentru interfaţa cu utilizatorul disponibile prin API-ul JavaFX sunt implementate ca noduri din graful de scene. Ele pot fi particularizate folosind foile de stil. 
 + 
 +Biblioteca ''​javafx.scene.control''​ definește cele mai frecvent utilizate controale din cadrul aplicațiilor ce conțin interfețe grafice cu utiliatorul. 
 + 
 +=== Utilizarea Foilor de Stil === 
 + 
 +JavaFX permite stilizarea interfeţei cu utilizatorul folosind foi de stil (//eng.// CSS – Cascading Style Sheets), deci fără a modifica codul sursă al aplicaţiei. Acestea pot fi aplicate ​ asupra oricărui obiect de tip ''​Node''​ din graful de scene, fiind aplicate asincron în momentul rulării (astfel încât pot fi modificate și dinamic). 
 + 
 +Specificația JavaFX CSS se bazează pe versiunea 2.1 a W3C CSS, cu unele actualizări din versiunea 3. Astfel, fişierele conţinând foi de stil pot fi parsate de orice utilitar specializat,​ chiar dacă acesta nu este integrat cu JavaFX. În acest fel, stilurile CSS pentru JavaFX și pentru alte scopuri (pagini HTML) pot fi incluse într-o unică foaie de stil.  
 + 
 +Toate proprietăţile JavaFX sunt prefixate cu şirul ''​-fx-''​ chiar şi pentru cele compatibile CSS HTML, datorită faptului că semantica acestora poate fi diferită pentru valorile corespunzătoare unor atribute. 
 + 
 +=== Operații asupra Elementelor Grafice === 
 + 
 +== Transformări 2D/3D == 
 + 
 +Fiecare nod din graful de scene JavaFX poate suferi transformări (2D/3D) în sistemul de coordonate Oxyz folosind metodele puse la dispoziţie de pachetul ''​javafx.scene.transform'':​ 
 +  * ''​translate''​ – mută un nod dintr-un loc în altul de-a lungul planurilor x, y, z relativ la poziţia sa iniţială;​ 
 +  * ''​scale''​ – redimensionează un nod pentru a apărea fie mai mare, fie mai mic în planurile x, y, z (în funcţie de factorul de scalare); 
 +  * ''​shear''​ – roteşte o axă astfel încât axele x sau y să nu mai fie perpendiculare coordonatele nodului fiind modificate conform specificaţiilor;​ 
 +  * ''​rotate''​ – roteşte un nod în jurul unui punct, denumit pivot al scenei; 
 +  * ''​affine'' ​ – realizează o mapare (liniară) dintr-un sistem de coordonate 2D/3D în alt sistem de coordonate 2D/3D păstrând caracteristici ale dreptelor precum paralelismul sau ortogonalitatea - această clasă ar trebui să fie utilizată împreună cu clasele ''​Translate'',​ ''​Scale'',​ ''​Rotate''​ sau ''​Shear''​ în loc de a fi utilizată direct. 
 + 
 +== Efecte Vizuale == 
 + 
 +Îmbogăţirea aplicaţiilor JavaFX (în special a celor de timp real) se face prin efecte vizuale care operează la nivel de pixel al imaginii, toate nodurile din graful de scene fiind randate ca atare. 
 + 
 +Efectele implementate în cadrul pachetului ''​javafx.scene.effect''​ sunt: 
 +  * ''​Bloom''​ (face ca zona cea mai luminoasă a unei imagini să pară strălucitoare);​ 
 +  * ''​Blur''​ (adaugă un efect de neclaritate asupra obiectului, putând fi de tipul ''​BoxBlur'',​ ''​MotionBlur''​ sau ''​GaussianBlur''​);​ 
 +  * ''​DropShadow''​ / ''​InnerShadow''​ (adaugă o umbră în spatele / în interiorul conţinutului respectiv);​ 
 +  * ''​Reflection''​ (creează o versiune reflectată a conţinutului respectiv, dispunând-o sub acesta); 
 +  * ''​Lighting''​ (simulează o sursă de lumină care operează asupra unui continut, dând un aspect mai realistic, 3D, asupra unui obiect plat) 
 +  * ''​Perspective''​ (mapează un dreptunghi peste un alt dreptunghi, menţinând netezimea liniilor dar nu neapărat şi paralelismul acestora). 
 + 
 +==== Sistemul Grafic ==== 
 + 
 +În **sistemul grafic** din JavaFX pot fi implementate grafuri de scene 2D şi 3D care sunt randate software atunci când hardware-ul nu dispune de accelerare grafică sau aceasta este insuficientă. 
 + 
 +Platforma JavaFX implementează două benzi de asamblare pentru accelerare grafică: 
 +  * **Prism** este folosit pentru operaţii de redare / rasterizare hardware / software a conţinutului (scene JavaFX, 2D sau 3D) folosind DirectX 9 (Windows XP / Vista), DirectX 11 (Windows 7), OpenGL (Mac, Linux, sisteme încorporate);​ 
 + 
 +<note>​Atunci când nu poate fi folosită accelerarea grafică la nivel hardware, se recurge la accelerarea grafică la nivel software folosind Java2D datorită răspândirii ei la nivelul JRE, mai ales când scena conţine obiecte 3D. Totuşi, trebuie să se țină cont de faptul că, în acest caz, performanţele sunt mai reduse.</​note> 
 + 
 +  * **Quantum Toolkit** reprezintă un element de interfaţă între Prism şi sistemul de ferestre Glass pe care le face disponibile nivelului JavaFX, ocupându-se şi de prioritatea firelor de execuţie ce tratează redarea faţă de tratarea evenimentelor ce țin de interacțiunea cu utilizatorul. 
 + 
 +La baza stivei de componente a sistemului grafic JavaFX se află **Glass – un sistem de ferestre**, o interfaţă între API şi sistemul de operare responsabil cu gestiunea ferestrelor,​ mecanismelor de cronometrare,​ suprafeţelor,​ cozii ce conține evenimentele de intrare / ieşire. 
 + 
 +<note>​Spre diferenţă de alte biblioteci grafice care folosesc de regulă o coadă de evenimente de intrare/ieşire proprie, JavaFX utilizează coada de evenimente a sistemului de operare gazdă pentru a gestiona modul de alocare al acestora la firele de execuţie. O altă caracteristică proprie este rularea sistemului de ferestre Glass pe acelaşi fir de execuţie ca şi aplicaţia JavaFX (alte sisteme grafice implementează un fir de execuţie specific bibliotecii şi un fir de execuţie specific Java, ceea ce putea genera o serie de probleme).</​note> 
 + 
 +Platforma JavaFX rulează pe mai multe fire de execuţie la un moment dat (minim 2): 
 +  * firul de execuţie JavaFX utilizat pentru a gestiona scenele care fac parte din ferestrele care sunt afişate; un graf de scene poate fi creat într-un fir de execuţie separat, însă atunci când nodul său rădăcină este legat de un obiect care este afișat în mod curent, acesta va fi tratat de firul de execuţie JavaFX; astfel, se permite ca utilizatorii să creeze în fundal scene complexe, menţinându-se constantă viteza de redare a scenei curente; totodată, firul de execuţie al aplicaţiei JavaFX este direrit de firul de execuţie asociat evenimentelor Swing sau AWT (//eng.// EDT - Event Dispatch Thread), astfel încât atunci când se integrează astfel de cod în aplicaţiile JavaFX, gestiunea obiectelor create în fire de execuţie diferite trebuie să se realizeze cu grijă; 
 +  * firul de execuţie Prism folosit pentru redare, separat de gestiunea evenimentelor de interacțiune cu utilizatorul – permiţându-se ca un cadru să fie afişat în timp ce alt cadru este procesat în fundal; de asemenea, poate asocia alte fire de execuţie folosite pentru rasterizare,​ eliminând încărcarea diun procesul de randare propriu-zis;​ procesarea concurentă poate fi exploatată în special în contextul mașinilor care dispun de mai multe procesoare, în care fiecare fir de execuție este asociat unui alt procesor; 
 +  * un fir de execuţie pentru conţinut multimedia, ce rulează în fundal, utilizat pentru sincronizarea celor mai recente cadre din graful de scene utilizând firul de execuţie JavaFX. 
 + 
 +Sincronizarea se face prin intermediul **mecanismului Pulse**. Un puls este un eveniment care indică grafului de scene JavaFX faptul că trebuie sincronizată starea elementelor pe care le conţine conform valorilor din firul de execuție Prism. El se declanşează la cel mult 60 de cadre pe secundă sau oricând sunt redate diferite animaţii / starea unui control din graful de scene trebuie modificată. Se permite astfel ca evenimentele să fie tratate asincron, în funcţie de puls. 
 + 
 +<note tip>​Actualizarea dispunerii conţinutului sau a stilului sunt legate de asemenea de puls. Dacă aceste modificări sunt numeroase (în cazul modificărilor din graful de scene), există riscul ca performanţa să fie redusă semnificativ,​ motiv pentru care ele sunt parcurse doar o singură dată în cadrul unui puls. Programatorii pot forţa parcurgerea cozii de modificări (dispunere conţinut ​/ stil) pentru a deveni vizibile înaintea unui puls.</​note> 
 + 
 +Evenimentele din cadrul unui puls sunt executate de sistemul de ferestre Glass prin intermediul unui sistem de cronometrare (de rezoluţie înaltă) nativ. 
 + 
 +==== Sistemul Multimedia ==== 
 + 
 +JavaFX oferă suport pentru multimedia prin API-urile ''​javafx.scene.media''​ care implementează atât conţinut auditiv (formatele ''​.mp3'',​ ''​.aiff'',​ ''​.wav''​) cât şi vizual (formatul ''​.flv''​).  
 + 
 +Sunt implementate trei componente:  
 +  * obiectul ''​Media''​ reprezintă fişierul multimedia, auditiv sau vizual; 
 +  * obiectul ''​MediaPlayer''​ redă conţinutul;​ 
 +  * obiectul ''​MediaView''​ reprezintă nodul din graful de scene ce afişează utilizatorilor informații despre conținutul redat, oferindu-le posibilitatea de a interacționa cu acesta prin diferite operații.  
 + 
 +Motorul multimedia a fost proiectat pentru a oferi stabilitate,​ performanţă şi comportament consistent pentru toate platformele. 
 + 
 +==== Sistemul pentru Redarea de Pagini Internet ==== 
 + 
 +JavaFX include şi un navigator care permite redarea conţinutului Internet prin intermediul API-ului său.  
 + 
 +Componenta Web Engine se bazează pe WebKit, un navigator open-source care suportă HTML5, CSS, JavaScript, DOM şi SVG, oferind o funcţionalitate asemănătoare cu cele mai multe produse de acelaşi tip (redare conţinut HTML local şi aflat într-o locaţie la distanţă, implementare istoric cu navigare înainte şi înapoi în cadrul acestuia, reîncărcarea conţinutului,​ aplicarea unor efecte, editarea conţinutului HTML, execuţia de comenzi JavaScript şi tratarea evenimentelor).  
 + 
 +La nivelul componentei care integrează navigatorul sunt definite două clase:  
 +  * ''​WebEngine''​ care oferă funcţionalităţi de bază caracteristice unui navigator  
 +  * ''​WebView''​ (derivat din ''​Node''​) care conține un obiect ''​WebEngine'',​ încorporând conţinut HTML în scena aplicaţiei,​ oferind atribute şi metode pentru aplicarea de efecte şi transformări.  
 + 
 +De asemenea, apelurile Java pot fi controlate prin intermediul JavaScript şi invers, astfel încât utilizatorii pot beneficia de avantajele ambelor medii de programare. 
 + 
 +===== Structura Generală a unei Aplicații JavaFX ===== 
 + 
 +O aplicaţie JavaFX trebuie să aibă o clasă principală,​ derivată din ''​javafx.application.Application''​. 
 + 
 +Metoda ''​start()''​ a acesteia trebuie să fie suprascrisă,​ primind ca unic parametru un obiect de tip ''​javafx.stage.Stage'',​ fereastra principală a aplicației,​ pentru care se indică titlul, scena și vizibilitatea. Acestă metodă este apelată în mod automat la execuţia clasei principale.  
 + 
 +Containerul interfeţei cu utilizatorul se exprimă prin clase de tip: 
 +  * ''​javafx.stage.Stage''​ - fereastra principală;​ 
 +  * ''​javafx.scene.Scene''​ - are asociat graful de noduri menţinând un model intern al elementelor grafice din cadrul aplicaţiei;​ la fiecare moment de timp, acesta ştie ce obiecte să afişeze, care zone ale ecranului trebuie actualizate şi cum să realizeze acest proces într-un mod eficient; metodele de desenare nu sunt apelate manual de utilizator, ci automat de sistemul de randare, conform informaţiilor reţinute în graful de noduri. 
 + 
 +{{ :​laboratoare:​laborator09:​02applicationstructure.png?​nolink&​500 }} 
 + 
 +Fiecare element din cadrul unei scene este exprimat sub forma unui nod dintr-un graf (arbore) în care elementul rădăcină este reprezentat de containerul din care acestea fac parte. 
 + 
 +Pachetul ''​javafx.scene''​ defineşte clase aferente celor trei tipuri de noduri care pot apărea în graful (arborele) de scene: 
 +  * ''​Scene'':​ containerul de bază pentru întregul conţinut (nod rădăcină);​ 
 +  * ''​Parent'':​ clasă abstractă pentru nodurile ce pot avea copii (nod ramură); implementări ale acestei clase sunt ''​Control'',​ ''​Group'',​ ''​Region''​ şi ''​WebView'';​ 
 +  * ''​Node'':​ clasă abstractă pentru toate elementele grafice, folosită în special pentru nodurile care nu pot avea copii (nod frunză); clasele ce pot fi folosite în acest scop sunt definite mai cu seamă în pachetele ''​javafx.scene.shape''​ şi ''​javafx.scene.text''​. 
 + 
 +{{ :​laboratoare:​laborator09:​03scenegraph.png?​nolink&​500 }} 
 + 
 +Aceste clase de bază definesc funcţionalităţi importante care vor fi moştenite de subclasele lor, inclusiv ordinea de desenare, vizibilitatea,​ compunerea transformărilor sau suportul pentru stiluri CSS. 
 + 
 +==== Exemplu ==== 
 + 
 +Se implementează o aplicaţie JavaFX denumită ''​BookStore''​ ce extinde clasa ''​javafx.application.Application''​.  
 + 
 +Metoda ''​start()''​ primeşte un argument de tip ''​javafx.stage.Stage''​ ce reprezintă container-ul de nivel înalt (fereastra vizibilă a aplicației). Această metodă este apelată în mod automat în momentul în care se creează o instanță a clasei. 
 + 
 +<file java BookStore.java>​ 
 +import javafx.application.Application;​ 
 +import javafx.stage.Stage;​ 
 +import ro.pub.cs.aipi.lab09.controller.Authentication;​ 
 + 
 +public class BookStore extends Application { 
 +     
 +    @Override 
 +    public void start(Stage mainStage) throws Exception { 
 +    new Authentication().start();​  
 +    }  
 +  
 +    public static void main(String[] args) { 
 +    launch(args);​ 
 +    } 
 +} 
 +</​file>​ 
 + 
 +La rândul său, aceasta creează o instanță a clasei ''​Authentication'',​ pentru care apelează metoda ''​start()''​.  
 + 
 +Acesta obține un obiect ''​Scene''​ pe baza încărcării conținutului unui fișier ''​.fxml''​ pe care îl afișează în cadrul unui obiect ''​Stage''​ (printr-un apel al metodei ''​show()''​),​ după ce a indicat alte proprietăți ale acestuia (titlu, pictogramă). Specificarea unei scene ca parte a unei ferestre se face printr-un apel al metodei ''​setScene()''​. 
 + 
 +<file java Authentication.java>​ 
 +import javafx.fxml.FXML;​ 
 +import javafx.fxml.FXMLLoader;​ 
 +import javafx.scene.Node;​ 
 +import javafx.scene.Parent;​ 
 +import javafx.stage.Stage;​ 
 +import javafx.scene.Scene;​ 
 +import ro.pub.cs.aipi.lab09.general.Constants;​ 
 + 
 +public class Authentication { 
 + 
 +    private Stage                   ​applicationStage;​ 
 +    private Scene                   ​applicationScene; ​    
 + 
 +    // ...
    
-Decizia de a utiliza Hadoop împreună cu HDFS şi MapReduce trebuie să se bazeze pe adecvarea unei anumite probleme la acest framework. Astfel, aplicaţiile dezvoltate folosind această tehnologie implică procesarea unui volum foarte mare de date care poate fi realizată în paralel, ceea ce presupune independenţa acestora unele de altele. Situaţia în care datele sunt dependente unele de altele poate fi rezolvată prin iterare ​(rularea mai multor sarcini MapReduce, în care datele de ieşire ale unora reprezintă datele de intrare pentru celelalte) sau prin partajare ​(folosind o bază de date distribuită şi nu variabile distribuite întrucât acestea există doar în contextul unei singure maşini virtuale, neputând fi accesate şi din contextul altor noduri sau clustere).+    public void start() {  
 +        try { 
 +            applicationScene = new Scene((Parent)FXMLLoader.load(getClass().getResource(Constants.AUTHENTICATION_FXML))); 
 +        } catch (Exception exception) { 
 +     System.out.println ("An exception has occured: "​+exception.getMessage());​ 
 +     if (Constants.DEBUG) 
 +         exception.printStackTrace();​ 
 + }
  
-===== Configurarea Mediului de Lucru =====+ applicationStage ​= new Stage(); 
 + applicationStage.setTitle(Constants.APPLICATION_NAME);​ 
 + applicationStage.getIcons().add(new Image(getClass().getResource(Constants.ICON_FILE_NAME).toExternalForm()));​ 
 + applicationStage.setScene(applicationScene);​ 
 + applicationStage.show();​ 
 +    } 
 +     
 +    // ... 
 +     
 +} 
 +</​file>​
  
-[[:​utile:​instalare_hadoop_hbase|Configurarea Mediului de Lucru]]+===== =====
  
-===== Paradigma de Programare Map Reduce =====+Metoda ''​main()''​ nu este necesară atunci când fişierul ''​.jar''​ corespunzător aplicaţiei JavaFX este creat folosind utilitarul JavaFX Packager, care include şi un mecanism pentru lansarea aplicaţiei în cadrul acesteia (JavaFX launcher). Totuşi, metoda ''​main()''​ va trebui implementată atunci când nu se utilizează acest utilitar (IDE-uri care nu sunt integrate complet cu JavaFX). În această situaţie, din metoda ''​main()''​ va trebui apelată metoda ''​Application.launch()''​.
  
-MapReduce reprezintă un model de progamare destinat procesării de date pe un număr foarte mare de noduri, reprezentate de maşini disponibile în comerţ, fără performanţe deosebite (//eng.// commodity hardware). Este inspirat din programarea funcţională de unde sunt preluate funcţiile map şi reduce, putând fi implementat în limbaje de programare ca Java, C++, Python sau Ruby. Un astfel de model este util mai ales pentru prelucrarea unor seturi de date (semistructurate şi orientate pe înregistrări) de dimensiuni foarte mari, în care procesarea paralelă este singura soluţie pentru obţinerea unor rezultate într-un interval de timp acceptabil.+===== Componente ale Interfeței cu Utilizatorul =====
  
-MapReduce se bazează pe împărţirea procesării în 2 etape: **map** şi **reduce**, fiecare primind ca date de intrare o pereche cheie-valoare (al căror tipuri poate fi stabilită de programator) şi întorcând ca rezultat tot o pereche cheie-valoare. ​+==== Controale Grafice ====
  
-<note tip>​Alternativ, se mai poate defini ​şi o funcţie de combinare ​(fiind de fapt o implementare a funcţiei de reducere), cu excepţia faptului că tipurile de intrare sunt aceleaşi ca ale funcţiei de reducere iar tipurile de ieşire ​sunt aceleaşi ca ale funcţiei de mapare.+Controalele care gestionează interfaţa cu utilizatorul în JavaFX sunt noduri în graful de scene, putând fi particularizate fie folosind foi de stil CSS, fie utilizând clasa ''​Skin''​. Totodată, ele pot fi integrate cu uşurinţă cu alte aplicaţii grafice Java (integrarea cu o aplicaţie Swing se face creând un obiect ''​Scene''​ la care se adaugă toate nodurile - având un mod de dispunere asociat -, acesta fiind ulterior adăugat la containerul corespunzător din aplicaţia Swing respectivă; chiar şi în acest caz, elementele JavaFX ​sunt randate cu Prism). 
  
-''​combine: ​(K<​sub>​2</​sub>,​ list(V<​sub>​2</​sub>​)) → list(K<​sub>​2</​sub>,​ V<​sub>​2</​sub>​)''​+Clasele care implementează controale din JavaFX se găsesc în pachetul ​''​javafx.scene.control''​. Fiecare control dispune de atribute şi metode ​(suplimentare faţă de cele din clasa ''​Control''​) pentru a oferi suport complet în interacţiunea cu utilizatorul. Clasa ''​Control'' ​poate fi extinsă definindu-se un obiect care corespunde nevoilor utilizatorilor.
  
-De cele mai multe ori, funcţiile de combinare şi reducere se confundă. +{{ :​laboratoare:​laborator09:​04javafxgraphicelements.png?​nolink&​700 }}
-</​note>​+
  
-Valorile care sunt procesate de programul MapReduce sunt partiţionate ​în funcţie de cheile care le caracterizează ​şi distribuite nodurilor care aplică funcţia de mapare, în urma căreia se generează o listă (intermediară) de valori, fiecare dintre ele având asociată şi o cheie. Acestea sunt sortate şi grupate în funcţie de cheie (toate valorile care au aceeaşi cheie sunt concatenate într-o singură listă), astfel încât funcţia de reducere primeşte mai puţine perechi cheie-valoare (pentru fiecare cheie unică există o listă de valori generate anterior) obţinându-se o listă de rezultate compusă din perechi chei-valoare.+Pe lângă controalele clasice (existente ​în AWT şi Swing) au fost dezvoltate ​şi alte componente, precum ''​Accordion'',​ ''​ColorPicker'',​ ''​Chart'',​ ''​DatePicker'',​ ''​Pagination'',​ ''​TitledPane'',​ ''​TreeTableView''​. 
  
-''​map:    (K<​sub>​1</​sub>,​ V<​sub>​1</​sub>​) ​      → list(K<​sub>​2</​sub>,​ V<​sub>​2</​sub>​)''​+Fiind derivate din clasa ''​Node''​, controalele pentru interfaţa cu utilizatorul pot fi integrate în diferite animaţii, efecte, transformări sau tranziţii în cadrul procesului de randare a scenei.
  
-''​reduce:​ (K<​sub>​2</​sub>,​ list(V<​sub>​2</​sub>​)) → list(K<​sub>​3</​sub>,​ V<​sub>​3</​sub>​)''​+=== Label ===
  
-{{ :laboratoare:​laborator10:​figura00_paradigma_map_reduce.png?​nolink&​700 }}+Un obiect ''​Label''​ reprezintă o etichetă (non-editabilă) ce poate conține în cadrul său un text (obiect de tip ''​String''​) și / sau o imagine (obiect de tip ''​ImageView''​). Acestea pot fi specificate ca parametri fie în cadrul constructorului,​ fie în cadrul metodelor de tip setter specifice: 
 +  * <code java> 
 +public void setText(String text) 
 +</​code>​ 
 +  * <code java> 
 +public void setGraphic(Node graphic) 
 +</​code>​
  
-===== Gestiunea Sarcinilor Map/​Reduce ​în Implementări ale Framework-ului Hadoop =====+Alinierea textului ​în cadrul etichetei utilizează metoda ''​setTextAlignment()'',​ iar definirea unei poziţii a elementului grafic faţă de text se face prin metoda ''​setContentDisplay()''​ care poate primi ca argument una din constantele clasei ''​ContentDisplay''​ şi anume: ''​LEFT'',​ ''​RIGHT'',​ ''​CENTER'',​ ''​TOP'',​ ''​BOTTOM''​. În situaţia în care textul trebuie împărţit între mai multe rânduri, metoda ''​setWrapText()''​ va primi ca argument valoarea ''​true''​. Totodată, în cazul în care textul asociat nu poate fi vizualizat datorită dimensiunilor etichetei respective, se foloseşte metoda ''​setTextOverrun()''​ care primeşte ca argument unul dintre tipurile clasei ''​OverrunStyle''​ ce defineşte modul în care va fi procesat textul care nu a putut fi vizualizat corespunzător. Textul poate fi redat folosind un anumit set de caractere, indicat ca parametru al metodei ''​setFont()''​ și o anumită culoare, specificată ca parametru al metodei ''​setTextFill()''​.
  
-Framework-ul Hadoop plasează sarcinile (în urma partiţionării) pe nodurile care găzduiesc segmentele de date care trebuie să fie procesate de acea sarcină specifică ​(codul este mutat acolo unde se găsesc datele).+Dacă se foloseşte atât text cât şi imagine pentru o etichetă, distanţarea dintre ele se poate face folosind metoda ''​setGraphicTextGap()''​.
  
-Fluxurile ​de intrare şi ieşire sunt coordonate ​de framework-ul Hadoop, acesta realizând ​şi sincronizarea ​(prin intermediul unei bariere) înainte ​de procesul de sortare ​şi grupare prin care datele intermediare sunt distribuite către alte maşini.+Efectele care pot fi aplicate asupra obiectelor ​de tip ''​Labeled'',​ ca de altfel asupra tuturor controalelor din JavaFX sunt rotirea (''​setRotate()''​), translaţia (''​setTranslate()''​) ​şi mărirea/​micşorarea (''​setScale()''​),​ numele metodelor putând fi sufixate ​de axa ce serverşte drept referinţă a operaţiei respective.
  
-Erorile sunt considerate un eveniment probabil să se întâmple, astfel că sarcinile care se găsesc într-o astfel de situaţie vor fi executate din nou, însă pe alte maşini.+=== Button ===
  
-Execuţia ​unei sarcini MapReduce ​se realizează ​prin apelul ​metodei ''​submit()'' ​pe un obiect de tip ''​Job''​ care abstractizează procesarea ce se doreşte a fi realizată. +Un obiect ''​Button''​ are funcția de a produce o acţiune în momentul în care este apăsat. ​Execuţia ​acestei operaţii ​se face prin transmiterea unui obiect ''​EventHandler<​ActionEvent>''​ ca parametru al metodei ''​setOnAction()''​. Acesta trebuie să implementeze metoda ​''​handle()''​ care realizează procesările asociate acţiunii de apăsare a unui buton. Cel mai frecvent, tipul de eveniment asociat este ''​ActionEvent'':​
  
-<note tip>Alternativ, poate fi apelată metoda ''​waitForJobCompetion()''​ care transmite sarcina dacă aceasta nu a fost transmisă deja, aşteptând să fie terminată.</note>+<code java> 
 +button.setOnAction((ActionEvent event) -> { 
 +        // ... 
 +    } 
 +); 
 +</code>
  
-Implementarea aplicaţiei utilizând această paradigmă ​de programare depinde de parametrii de configurare specificaţi: ​''​mapred.job.tracker''​ este folosit pentru versiunile Hadoop mai vechi, folosind un mecanism MapReduce "​clasic",​ în timp ce ''​mapreduce.framework.name'' ​reprezintă proprietatea utilizată pentru versiunile Hadoop mai noi, care implementează YARN.+Obiectul ​de tip ''​Button''​ este derivat din clasa ''​Labeled''​, astfel încât conținutul său poate fi atât text cât și imagine, acestea putând fi transmise în constructor sau în metodele setter respective.
  
-<​note ​tip>​Valorile posibile pentru proprietatea ​''​mapreduce.framework.name'' ​sunt: +Asupra unui obiect de tip ''​Button'' ​pot fi aplicate efecte (din pachetul ​''​javafx.scene.effect''​) ​prin metoda ​''​setEffect()'' ​asociate de regulă evenimentelor legate de mouse, cum ar fi ''​MouseEvent.MOUSE_ENTERED''​ şi ''​MouseEvent.MOUSE_EXITED''​. Tratarea unor astfel de evenimente se face prin specificarea unei metode specifice, apelată automat în momentul producerii acestuia, asociată prin metoda ​''​addEventHandler()''​. Aceasta primește ca parametri tipul de eveniment, precum și obiectul ​(de tip ''​EventHandler''​) care gestionează operațiile realizate în momentul producerii sale.
-  * ''​local'' ​(în caz că se doreşte ca sarcina să fie rulată local, în cadrul unei singure maşini virtuale Java); +
-  * ''​classic'' ​(pentru implementarea MapReduce "​clasică", folosind procesele ​''​JobTracker''​ şi ''​TaskTrackers''​);  +
-  * ''​yarn''​ (pentru implmentarea ce utilizează YARN). +
-</​note>​+
  
-În cazul **implementării MapReduce "​clasice"​** sunt implicate mai multe entităţi:  +Stilizarea unui buton se face apelând metoda ''​setStyleClass()''​ ce primeşte drept argument un fişier ​de tip ''​.css''​ sau prin metoda ''​setStyle()''​ în care elementele specifice de stil sunt precizate manual.
-  * clientul, care transmite sarcina ​de tip MapReduce;​ +
-  * un proces pentru monitorizarea sarcinii (//eng.// Job Tracker) care coordonează rularea acesteia;+
  
-<​note>​Procesul de monitorizare a sarcinii este o aplicaţie Java a cărei clasă principală este ''​JobTracker''​.</​note>​+=== RadioButton ===
  
-  * mai multe procese pentru monitorizarea părţilor ​în care a fost împărţită sarcina ​(//eng.// Task Tracker);+Un obiect ''​RadioButton''​ este un tip de buton care are proprietatea că poate fi la un moment dat de timp fie selectat, fie deselectat. De regulă, ​mai multe astfel de obiecte sunt grupate împreună în cadrul unui obiect de tip ''​ToggleGroup'', ​care asigură selecția exclusivă între acestea (un singur control poate fi selectat din grup poate fi selectat). Apartenența unui buton radio la un grup este precizată prin metoda ''​setToggleGroup()''​ care primeşte ca argument elementul din care va face parte. Selecţia unui anumit buton din grup trebuie realizată atât prin metoda ''​setSelected(true)''​ cât şi prin metoda ''​requestFocus()''​. Verificarea faptului că butonul a fost selectat se face prin metoda ''​isSelected()''​.
  
-<​note>​Procesul de monitorizare a unei părţi a sarcinii este tot o aplicaţie Java a cărei clasă principală este ''​TaskTracker''​.</note>+Identificarea butonului selectat în cadrul interacţiunii cu utilizatorul implică definirea, pentru grupul de butoane (de tip ''​ToggleGroup''​), a unui obiect ascultător de tip ''​ChangeListener<Toggle>''​ pentru care trebuie implementată metoda ''​changed()'':​
  
-  * sistemul distribuit de fişiere ​(de obicei HDFS), utilizat pentru partajarea fişierelor între aceste entităţi.+<code java> 
 +final ToggleGroup toggleGroup = new ToggleGroup(); 
 +toggleGroup.selectedToggleProperty().addListener( 
 +    (ObservableValue<?​ extends Toggle> observableValue, Toggle oldToggle, Toggle newToggle) -> { 
 +        if (toggleGroup.getSelectedToggle() != null) { 
 +            Toggle selectedToggle = toggleGroup.getSelectedToggle();​ 
 +            // ... 
 +        } 
 +    } 
 +); 
 +</​code>​
  
-{{ :​laboratoare:​laborator10:​figura03_sistemul_map_reduce_clasic.png?​nolink }}+=== ToggleButton ===
  
-Etapele urmate ​la crearea unei sarcini ​de tip MapReduce sunt următoarele:+Un obiect ''​ToggleButton''​ este de asemenea un tip de buton care are proprietatea că poate fi la un moment dat de timp fie selectat, fie deselectat, mai multe elemente de acest fel putând fi grupate împreună. Totuși, într-un grup (obiect ''​ToggleGroup''​) format din mai multe astfel de controale, există posibilitatea ca nici un element să nu fie selectat la un moment dat de timp, păstrându-se totuși constrângerea ​de tip selecție exclusivă.
  
-**1.** metoda ''​submit()''​ apelată pe obiectul de tip ''​Job''​ creează o instanţă a unui obiect de tip ''​JobSummiter''​ pentru care apelează metoda ''​submitJobInternal()'';​ ulterior, metoda ''​waitForJobCompletion()''​ verifică progresul sarcinii o dată pe secundă, raportând starea acesteia (în situaţia în care s-a modificat de la ultimul raport); când sarcina este încheiată cu succes se afişează statisticile sarcinii, altfel este afişată eroarea care a determinat eşecul sarcinii.+=== CheckBox ===
  
-**2.** procesul de transmitere al sarcinii (reprezentat de obiectul instanţă al clasei ​''​JobSummitter''​) solicită procesului ​de urmărire al sarcinii (''​JobTracker''​) ​un nou identificator pentru sarcina respectivă (prin apelul metodei ​''​getNewJobId()''​); ulterior, sunt verificate specificaţiile privind datele de ieşire şi datele de intrare ​pentru ​sarcina în cauză; dacă directorul unde trebuie plasate datele de ieşire nu a fost specificat sau există deja, respectiv nu pot fi determinate partiţiile pentru datele de intrare (datorită faptului că acestea nu au fost specificate sau nu există) sarcina nu este transmisă, generându-se în schimb o eroare; dacă specificaţiile privind operaţiile de intrare/​ieşire sunt corecte, sunt determinate partiţiile care vor fi prelucrate de fiecare parte a sarcinii;+Un obiect ​''​CheckBox'' ​are proprietatea ​de a fi la un moment dat de timp selectat sau deselectat, însă mai multe elemente de acest tip nu pot fi grupate în obiecte ​''​ToggleGroup'', ​tocmai ​pentru a permite selecția simultană.
  
 +Un obiect ''​CheckBox''​ poate fi definit (situaţie în care acesta poate fi selectat sau deselectat) sau nedefinit, caz în care starea sa nu poate fi modificată ca urmare a interacţiunii cu utilizatorul. Definirea obiectului presupune specificarea proprietăţilor sale prin metodele ''​setSelected()''​ respectiv ''​setIndeterminate()'':​
 +  * în cazul în care proprietatea ''​INDETERMINATE''​ are valoarea ''​false'',​ starea unui obiect ''​CheckBox''​ poate fi selectat sau deselectat;
 +  * în cazul în care proprietatea ''​INDETERMINATE''​ are valoarea ''​true'',​ starea unui obiect ''​CheckBox''​ poate fi selectat, deselectat sau nedefinit; dacă se doreşte ca obiectul ''​CheckBox''​ să cicleze între trei valori: selectat, neselectat şi nedefinit, se precizează proprietatea ''​allowIndeterminate''​.
  
-**3.** procesul ​de transmitere ​al sarcinii copiază din sistemul distribuit ​de fişiere resursele necesare ​pentru ​rularea sarcinii ​(inclusiv ​fişierul .jar care conţine ​codul corespunzător sarcinii, fişierul ​de configurare ​şi partiţiile datelor ​de intrare) în sistemul ​de fişiere al procesului ​de urmărire al sarcinii, într-un director având numele dat de identificatorul sarcinii;+^ ^  ''​INDETERMINATE=false'' ​ ^  ''​INDETERMINATE=true'' ​ ^  
 +| **''​SELECTED=false''​** | {{ :​laboratoare:​laborator09:​05checkbox-state1.png?nolink }} | {{ :​laboratoare:​laborator09:​05checkbox-state2.png?​nolink }} |  
 +| **''​SELECTED=true''​** | {{ :​laboratoare:​laborator09:​05checkbox-state3.png?​nolink }} | ::: | 
 + 
 +=== ChoiceBox === 
 + 
 +Un obiect ''​ChoiceBox''​ se oferă posibilitatea selecţiei între un număr relativ mic de opţiuni. Elementele din cadrul unui astfel de obiect (create prin metoda ''​FXCollections.observableArrayList()''​) pot fi specificate fie atunci când obiectul este construit, fie prin metoda ''​setItems()''​. Delimitarea dintre opţiuni se poate realiza utilizând obiecte de tip ''​Separator''​. Totodată, nodul poate fi însoţit de o explicaţie suplimentară,​ folosind metoda ''​setTooltip()''​ (care primeşte drept parametru un obiect de tipul ''​Tooltip''​). 
 + 
 +Identificarea indexului pe care îl deţine elementul selectat în cadrul interacţiunii cu utilizatorul se face prin intermediul unui obiect ascultător de tipul ''​ChangeListener<​Number>'',​ pentru care se implementează metoda ''​changed()'':​ 
 + 
 +<code java> 
 +choiceBox.getSelectionModel().selectedIndexProperty().addListener( ​                              
 +    (ObservableValue observableValue,​ Number oldValue, Number newValue) -> { 
 +        int selectedIndex = newValue.intValue();​ 
 +        // ... 
 +    } 
 +); 
 +</​code>​ 
 + 
 +Metoda ''​getSelectionModel()''​ întoarce elementul selectat din cadrul obiectului ''​choiceBox'',​ în timp ce metoda ''​selectedIndexProperty()''​ returnează proprietatea ''​SELECTED_INDEX''​ a acestuia. 
 + 
 +=== TextField / PasswordField === 
 + 
 +Clasele ''​TextField''​ şi ''​PasswordField'',​ derivate din clasa ''​TextInput'',​ oferă posibilitatea de a gestiona un text de la utilizator pe care îl pot afişa. 
 + 
 +<​note>​Diferenţa dintre clasele ''​TextField''​ şi ''​PasswordField''​ constă în faptul că în cazul ''​TextField''​ conţinutul este afişat în clar în timp ce pentru ''​PasswordField''​ fiecare caracter este înlocuit prin ●.</​note>​ 
 + 
 +<note tip>O practică frecventă pentru obiecte de tip ''​PasswordField''​ este ştergerea conţinutului său după ce a fost realizată procesarea sa.</​note>​ 
 + 
 +Crearea unui astfel de obiect se face cu sau fără argument. 
 + 
 +Dimensiunea câmpului text este precizată prin metoda ''​setPrefColumnCount()''​.  
 + 
 +Unui astfel de element i se poate asocia un text descriptiv indicând semnificaţia conţinutului,​ prin metoda ''​setPromptText()''​. O astfel de funcționalitate este utilă atunci când nu se utilizează etichete împreună cu câmpurile text pentru a specifica conținutul acestora. Totuși, doar valoarea specificată de utilizator poate fi obținută prin metoda ''​getText()''​ asociată acestui tip de control. 
 + 
 +Ştergerea textului conţinut de aceste obiecte se face apelând metoda ''​clear()''​. 
 + 
 +Metodele puse la dispoziţie de aceste clase sunt: 
 +  * ''​copy()''​ – transferă textul selectat într-o zonă de memorie, menţinându-l în obiectul curent; 
 +  * ''​cut()''​ – transferă textul selectat într-o zonă de memorie, nemenţinându-l în obiectul curent; 
 +  * ''​selectAll()''​ - selectează întregul conținut din cadrul obiectului curent; 
 +  * ''​paste()''​ – transferă conţinutul zonei de memorie în obiectul curent, înlocuind textul selectat. 
 + 
 +Procesarea valorii din cadrul unui câmp text poate fi realizată prin intermediul unui obiect ​de tipul ''​EventHandler<​ActionEvent>''​ specificat ca parametru ​al metodei ''​setOnAction()''​. 
 + 
 +=== ScrollBar === 
 + 
 +Un obiect ''​ScrollBar''​ permite crearea de panouri şi zone de vizualizare care pot fi derulate. Elementele sale sunt cursorul, bara culisantă precum şi butoanele stâng şi drept.  
 + 
 +Metodele ''​setMin()''​ şi ''​setMax()''​ sunt utilizate pentru a exprima limitele între care se mişcă cursorul și ''​setValue()''​ pentru a specifica poziţia curentă a cursorului. Implicit, cursorul este centrat pe orizontală (se găsește la valoarea (min + max) / 2).  
 + 
 +Metoda ''​setOrientation()''​ este folosită pentru a distinge între tipurile orizontal şi vertical.  
 + 
 +Mutarea cursorului (într-o anumită direcţie) cu o singură unitate (specificată prin proprietatea ''​UNIT_INCREMENT''​) se face accesând butoanele ​din stânga sau din dreapta (respectiv sus şi jos). Atributul ''​BLOCK_INCREMENT''​ indică deplasarea implicită în momentul în care utilizatorul apasă bara culisantă în loc de butoanele de la extremităţile acesteia. 
 + 
 +=== ScrollPane === 
 + 
 +Un obiect de tip ''​ScrollPane''​ permite vizualizarea elementelor grafice a căror dimensiune depășește suprafața de afișare prin controale care culisează.  
 + 
 +Conţinutul (un singur nod!!!) unui astfel de obiect este specificat prin intermediul metodei ''​setContent()''​. 
 + 
 +<note tip>​Dacă se doreşte includerea mai multor noduri, se vor folosi containere care gestionează dispunerea conţinutului sau obiecte din clasa ''​Group''​. Totodată, metoda ''​setPannable()''​ poate fi utilizată (cu argumentul ''​true''​) pentru ca obiectul conţinut să fie previzualizat odată cu mişcarea mouse-ului.</​note>​ 
 + 
 +Se pot specifica politici de afişare a elementelor derulante, atât pentru ​verticală cât şi pentru orizontală prin metodele ''​setHbarPolicy()''​ / ''​setVbarPolicy()''​. Parametrii pe care îi pot primi aceste metode sunt definite în clasa ''​ScrollBarPolicy'':​ ''​ALWAYS'',​ ''​NEVER'',​ ''​AS_NEEDED''​.  
 + 
 +Componentele din cadrul unui obiect ''​ScrollPane''​ pot fi redimensionate pentru a corespunde spaţiului existent (metodele ''​setFitToWidth()''​ / ''​setFitToHeight()''​). Implicit, proprietăţile ''​FIT_TO_WIDTH'' ​şi ''​FIT_TO_HEIGHT''​ au valoarea ''​false''​. De asemena, clasa ''​ScrollPane''​ oferă posibilitatea de a se afişa dimensiunea minimă, dimensiunea maximă precum şi dimensiunea curentă a componentelor pe care le conţine. 
 + 
 +Proprietăţile ''​HVALUE''​ şi ''​VVALUE''​ ale obiectului ''​ScrollPane''​ identifică poziţia pe care o are cursorul de derulare pe orizontală, respectiv ​ pe verticală. 
 + 
 +=== ListView === 
 + 
 +Obiectul ''​ListView''​ este utilizat pentru vizualizarea unei liste care conţine mai multe elemente, astfel încât pentru inspectarea acestora este necesară existenţa unei bare derulante.  
 + 
 +Componentele sale pot fi specificate fie atunci când obiectul este construit fie prin metodele ''​setItems()''​ (se foloseste constructorul ''​FXCollections.observableArrayList()''​),​ respectiv ''​setCellFactory()''​.  
 + 
 +Modificarea dimensiunilor implicite se face prin ''​setPrefHeight()'',​ respectiv ''​setPrefWidth()'',​ cu valorile exprimate în pixeli.  
 + 
 +Lista poate fi orientată pe verticală sau orizontală,​ în funcţie ​de parametrul pe care îl primeşte metoda ''​setOrientation()''​ (''​Orientation.HORIZONTAL''​ sau ''​Orientation.VERTICAL''​).  
 + 
 +<code java> 
 +ListView<​Object>​ listView = newListView<>​();​ 
 +ObservableList<​Object>​ entries = FXCollections.observableArrayList(...);​ 
 +listView.setItems(entries);​ 
 +listView.setPrefWidth(...);​ 
 +listView.setPrefHeight(...);​ 
 +listView.setOrientation(...);​ 
 +</​code>​ 
 + 
 +Clasele ''​SelectionModel'' ​şi ''​FocusModel''​ sunt folosite pentru a identifica selecţia şi focusul din cadrul listei (aceste proprietăţi pot fi obţinute, însă nu pot fi specificate pentru a determina valorile selectate, respectiv focusate în cadrul listei): 
 +  * ''​getSelectionModel().getSelectedIndex()''​ – întoarce indexul elementului selectat în mod curent; 
 +  * ''​getSelectionModel().getSelectedItem()''​ – întoarce elementul selectat; 
 +  * ''​getFocusModel().getFocusedIndex()''​ – întoarce indexul elementului care deţine focusul în mod curent; 
 +  * ''​getFocusModel().getFocusedItem()''​ – întoarce elementul focusat. 
 + 
 +Obiectele ''​ListView''​ sunt create ​în mod implicit având ca model de selecţie o implementare a clasei abstracte ''​MultipleSelectionModel'',​ cu proprietatea ''​selectionMode''​ având valoarea ''​SelectionMode.SINGLE''​. 
 + 
 +Pentru a permite selecţia multiplă se va folosi metoda ''​setSelectionMode()''​ având ca parametru ''​SelectionMode.MULTIPLE'',​ elementele selectate obţinându-se prin proprietăţile ''​selectedItems''​ / ''​selectedIndices''​.  
 + 
 +Dacă se doreşte ca datele din listă să poată ​fi modificate de utilizator (implicit o astfel de operație nu este permisă), se pot utiliza extensii ale clasei ''​ListCell''​ ca ''​CheckBoxListCell'',​ ''​ChoiceBoxListCell'',​ ''​ComboBoxListCell''​ sau ''​TextFieldListCell''​. Redefinirea implementării unei celule ​ a listei la aceste tiprui de obiecte se face prin metoda ''​setCellFactory()''​. 
 + 
 +=== TableView === 
 + 
 +JavaFX pune la dispoziţie programatorilor ​şi clase pentru a reprezenta datele într-o formă tabelară: ''​TableView'',​ ''​TableColumn''​ şi ''​TableCell''​. Popularea implică definirea unui model pentru tabel şi asocierea unei fabrici pentru celule. Modelul de date este o clasă ale cărei atribute au tipul ''​SimpleStringProperty''​ şi pentru care se definesc metode de tip getter şi setter. Pentru fiecare coloană existentă în cadrul tabelului se va specifica, pe lângă nume şi dimensiune şi fabrica pentru valorile pe care le va conţine: 
 + 
 +<code java> 
 +for (String attribute: attributes) { 
 +    TableColumn<​Model,​ String> column = new TableColumn<​Model,​ String>​(attribute);​ 
 +    column.setMinWidth(tableContentTableView.getPrefWidth() / attributes.size());​ 
 +    column.setCellValueFactory(new PropertyValueFactory<​Model,​ String>​(attribute));​ 
 +    tableContentTableView.getColumns().add(column);​ 
 +} 
 +populateTableView(null);​ 
 +</​code>​ 
 + 
 +<code java> 
 +public void populateTableView(String whereClause) { 
 +    try { 
 +        ArrayList<​ArrayList<​String>>​ values = DataBaseWrapperImplementation.getInstance().getTableContent(tableName,​  
 +            null,  
 +            (whereClause == null || whereClause.isEmpty()) ? null : whereClause,​  
 +            null,  
 +            null); 
 +        ObservableList<​Model>​ data = FXCollections.observableArrayList();​ 
 +        for (ArrayList<​String>​ record:​values) 
 +            data.add(getCurrentEntity(record));​ 
 +        tableContentTableView.setItems(data);​ 
 +    } catch (SQLException sqlException) { 
 +        System.out.println("​An exception had occured: " + sqlException.getMessage());​ 
 +        if (Constants.DEBUG) 
 +            sqlException.printStackTrace();​ 
 +    } 
 +} 
 +</​code>​ 
 + 
 +Metoda ''​setCellValueFactory()''​ specifică o fabrică de celule pentru fiecare coloană în parte. Aceasta este implementată folosind clasa ''​PropertyValueFactory''​ ce utilizează denumirile coloanelor tabelelor ca referinţe către metodele aferente ale clasei ''​Model''​.  
 + 
 +Tabelele JavaFX au capacitatea de a sorta datele. Sortarea obiectelor din cadrul unei coloane se face printr-un click al mouse-ului. În funcţie ​de numărul de click-uri ale mouse-ului, elementele vor fi sortate crescător (1), descrescător (2) sau deloc (3). Programatorul poate indica din cod preferinţele pentru sortarea conţinutului,​ folosind metoda ''​setSortType()'',​ care primeşte ca parametru o constantă din clasa ''​TableColumn.SortType''​ (având valorile ''​ASCENDING''​ / ''​DESCENDING''​). Coloanele care vor fi sortate pot fi indicate prin apăsarea tastei ''​Shift''​ înainte de selectarea lor, fie prin metoda ''​TableView.sortOrder()''​ având ca parametru lista observabilă a coloanelor. Posibilitatea de realizare a sortării informațiilor din cadrul tabelelor se face prin intermediul metodei ''​setSortable()''​. 
 + 
 +Tabelele JavaFX oferă posibilitatea de a redimensiona coloanele în funcţie de conţinut.  
 + 
 +În cazul în care se doreşte editarea conţinutului unor tabele, se va folosi metoda ''​setEditable(true)''​.  
 + 
 +Structura unui tabel presupune existenţa unor coloane (obiecte de tip ''​TableColumn''​) care se adaugă la obiectul de tip ''​TableView''​. Pentru un obiect de tip ''​TableColumn''​ se poate utiliza metoda ''​setVisible(false)''​ dacă nu se doreşte vizualizarea conţinutului său. 
 + 
 +De asemenea, se pot crea structuri mai complexe, cum ar fi de exemplu coloane imbricate, adăugând la coloana părinte coloanele copil: 
 + 
 +<code java> 
 +TableColumn parent = new TableColumn("​Parent"​);​ 
 +TableColumn child1 = new TableColumn("​Child1"​);​ 
 +TableColumn child2 = new TableColumn("​Child2"​);​ 
 +parent.getColumns().addAll(child1,​ child2); 
 +</​code>​ 
 + 
 +În situaţia în care tabelul nu conţine nici un fel de date, este afişat mesajul ''"​No content in table"''​. Dacă se doreşte afişarea altui text, acesta poate fi precizat prin metoda ''​setPlaceHolder()''​. 
 + 
 +=== TreeView === 
 + 
 +Un obiect ''​TreeView''​ permite vizualizarea de conţinuturi care respectă o structură ierarhică în care elementul cel mai de sus este numit rădăcină,​ iar elementele cele mai de jos sunt numite frunze.  
 + 
 +Construirea unui obiect ''​TreeView''​ implică definirea mai multor obiecte ''​TreeItem''​ între care se stabilesc relaţii de tip părinte-fiu. Obiectul ''​TreeItem''​ rădăcină este specificat fie ca parametru ​al constructorului obiectului ''​TreeVioew''​, fie ca parametru al metodei ''​setRoot()''​. Indicarea unui nod fiu se face prin transmiterea sa ca parametru al metodei ''​add()''​ apelată pentru lista observabilă a elementelor din nodul părinte (care se obține prin metoda ''​getChildren()''​). 
 + 
 +Obiectele ''​TreeItem''​ pot fi expandate (vizualizându-se conţinutul lor) sau nu, în funcţie de parametrul transmis metodei ''​setExpanded()''​. Implicit, conţinutul obiectelor ''​TreeItem''​ nu poate fi vizualizat. 
 + 
 +Clasa ''​TreeItem''​ este parametrizată (''​TreeItem<​T>​ (T value)''​) întrucât poate conţine elemente de orice tip (inclusiv alte controale). Pentru fiecare obiect de tip ''​TreeItem''​ poate fi asociat ​un element grafic ce poate fi precizat fie în constructor sau poate fi transmis ca parametru al metodei ''​setGraphic()''​. 
 + 
 +Întrucât clasa ''​TreeItem''​ nu este derivată din ''​Node'',​ supra obiectelor ​de acest tip nu pot fi aplicate efecte vizuale. De aceea, trebuie definit un mecanism de tip "​fabrică"​ pentru a genera obiecte de tip ''​TreeCell''​ al căror comportament poate fi modificat în funcţie de necesităţi. Această abordare este utilă mai ales când obiectul respectiv va conţine o cantitate mare de informaţii care este modificată în mod dinamic. De asemenea, acest mecanism poate fi folosit atunci când se doreşte redefinirea tipului de control conţinut, cu specificarea comportamentului aplicaţiei în cazul când utilizatorul interacţionează cu tipul de nod respectiv, putând fi folosite ''​CheckBoxTreeCell'',​ ''​ChoiceBoxTreeCell'',​ ''​ComboBoxTreeCell'',​ ''​TextFieldTreeCell''​.  
 + 
 +Verificarea relaţiilor dintre obiectele de tip ''​TreeItem''​ se face prin metodele ''​getParent()'',​ respectiv ''​isLeaf()''​. 
 + 
 +=== TreeTableView === 
 + 
 +Un obiect ''​TreeTableView''​ reprezintă o combinație a funcționalităților oferite de clasele ''​TableView''​ și ''​TreeView'',​ permițând vizualizarea unei ierarhii de date (nelimitate) organizate tabelar. 
 + 
 +Procesul de construire al unui obiect de tip ''​TreeTableView''​ implică mai multe etape: 
 +  - definirea nodurilor din cadrul arborelui (obiecte de tip ''​TreeItem''​) <code java> 
 +final TreeItem<​String>​ childNode1 = new TreeItem<>​(new Person("​FirstName1,​ LastName1"​));​ 
 +final TreeItem<​String>​ childNode2 = new TreeItem<>​(new Person("​FirstName2,​ LastName2"​));​ 
 +</​code>​ 
 +  - definirea nodului rădăcină (obiect de tip ''​TreeItem''​) <code java> 
 +final TreeItem<​String>​ rootNode = new TreeItem<>​("​Persons"​);​ 
 +rootNode.setExpanded(true);​  
 +</​code>​ 
 +  - stabilirea relațiilor de tip părinte-copil între nodurile din cadrul arborelui <code java> 
 +rootNode.getChildren().setAll(childNode1,​ childNode2);​ 
 +</​code>​ 
 +  - definirea atributelor (coloanelor) <code java> 
 +TreeTableColumn<​Person,​ String> firstNameColumn = new TreeTableColumn<>​("​First Name"​);​ 
 +TreeTableColumn<​Person,​ String> lastNameColumn = new TreeTableColumn<>​("​Last Name"​);​ 
 +</​code>​ 
 +  - specificarea conținutului atributelor (coloanelor),​ prin intermediul unor fabrici de celule, ce furnizează obiecte de tip ''​TreeItem'',​ pe baza proprietăților clasei ale căror obiecte sunt reprezentate <code java> 
 +firstNameColumn.setCellValueFactory((CellDataFeatures<​Person,​ String> parameter) ->  
 +    new ReadOnlyStringWrapper(parameter.getValue().getValue().getFirstName()));​ 
 +lastNameColumn.setCellValueFactory((CellDataFeatures<​Person,​ String> parameter) ->  
 +    new ReadOnlyStringWrapper(parameter.getValue().getValue().getLastName()));​ 
 +</​code>​ 
 +  - construirea unui obiect de tip ''​TreeTableView''​ <code java> 
 +final TreeTableView<​String>​ treeTableView = new TreeTableView<>​(rootNode);​ 
 +treeTableView.setShowRoot(true);​ 
 +</​code>​ 
 +  - asocierea atributelor (coloanelor) la obiectul de tip ''​TreeTableView''​ <code java> 
 +treeTableView.getColumns().addAll(firstNameColumn,​ lastNameColumn); 
 +</​code>​
  
-<​note>​Arhiva .jar conţinând codul corespunzător sarcinii este copiat folosind un factor de replicare foarte mare (indicat ​de proprietatea ​''​mapred.submit.replication'' ​a cărei valoare implicită este 10), astfel încât vor exista suficient de multe copii în cadrul clusterului ​ce vor putea fi accesate de procesele ce prelucrează porţiuni ale sarcinii atunci când se află în execuţie.</​note>​+Dacă se dorește ca utilizatorii să aibă acces la vizibilitatea coloanelor, se poate apela metoda ''​setTableMenuButtonVisible()'',​ care în funcție ​de valoarea parametrului furnizat, afișează (pentru ​''​true''​) sau nu (pentru ''​false''​) în antetul tabelului un buton (''​+''​) ​ce oferă o astfel de funcționalitate.
  
-**4.** procesul de transmitere al sarcinii informează procesul de urmărire a sarcinii de faptul că aceasta poate fi executată, prin apelul ​metodei ''​submitJob()'' ​pe obiectul instanţă a clasei ​''​JobTracker''​;+Vizibilitatea nodului rădăcină este controlată prin intermediul ​metodei ''​setShowRoot()'' ​care primește un parametru de tip ''​boolean''​.
  
-**5.** atunci când obiectul instanţă a clasei ​''​JobTracker''​ primeşte un apel al metodei ​''​submitJob()'', ​pune sarcina respectivă într-o coadă internă de unde îl va prelua planificatorul de sarcini ​pentru ​a-l iniţializa;​ procesul ​de iniţializare presupune crearea unui obiect reprezentând sarcina care va fi executată, conţinând partiţiile care vor fi rulate pe noduri diferite, precum şi informaţii referitoare la progresul acestora;+Ordonarea conținutului pentru fiecare atribut în parte se poate face: 
 +  ​* pentru fiecare coloană în parte, prin metoda ​''​setSortType()''​, ce primește ca parametru o constantă din clasa ''​TreeTableColumn.SortType''​ (''​ASCENDING'', ​''​DESCENDING''​);​ 
 +  * pentru ​întregul tabel, prin metoda ''​setSortMode()''​ 
 +    * ''​TreeSortMode.ALL_DESCENDANTS'' ​- regulile ​de ordonare se aplică la toți descendenții 
 +    * ''​TreeSortMode.ONLY_FIRST_LEVEL''​ - regulile de ordonare se aplică numai pentru descendenții de pe primul nivel
  
-**6.** ​ pentru a crea lista partiţiilor sarcinii, planificatorul de sarcini primeşte datele de intrare, defalcate pe secţiuni, aşa cum au fost împărţite de client în urma primirii acestora de la sistemul distribuit de fişiere; pentru fiecare secţiune este creată o partiţie a sarcinii (operaţie de tip ''​map''​), în timp ce numărul de operaţii de tip ''​reduce''​ este determinat din proprietatea ''​mapred.reduce.task'' ​a obiectului ''​Job''​ (fiind stabilit ​de metoda ​''​setNumReduceTasks()''​) creându-se un număr corespunzător de procese care le vor executa; fiecare partiţie ​a sarcinii (de tip map sau reduce) va putea fi urmărită printr-un identificator unic; în plus, vor mai fi create încă două procese, pentru configurarea ​(//eng.// setup), respectiv eliberarea resurselor ​(//eng.// cleanup) asociate partiţiei sarcinii, ele fiind rulate înainte, respectiv ​după ce codul asociat partiţiei sarcinii este executat; pentru fiecare sarcină există un obiect de tip ''​OutputCommitter'' ​ce determină codul corespunzător fiecărei sarcini în parte;+Un obiect ​''​TreeTableView'' ​implementează un model de selecție ​''​SelectionMode.SINGLE''​, definit ​de clasa abstractă ​''​MultipleSelectionModel''​. Pentru ​a permite selecția ​mai multor noduri ale arborelui / atribute ​(coloane), trebuie apelate succesiv metodele ''​setSelectionMode()''​, respectiv ''​setCellSelectionEnabled()''​.
  
-<​note>​În mod implicit, obiect ​''​OutputCommitter'' ​are tipul ''​FileOutputCommitter'';​ în cazul procesului de configurare,​ acesta va crea directorul în care vor fi plasate datele de ieşire precum şi directoarele de lucru (temporare), în timp ce pentru procesul de eliberare al resurselor, acesta va şterge directoarele de lucru (temporare),​ transmiţând în acelaşi timp rezultatul sarcinii, ceea ce pentru procesele care realizează operaţii pe fişiere se traduce în scrierea datelor de ieşire la locaţia corespunzătoare sarcinii respective (în cazul în care este activată execuţia speculativă, se asigură faptul că vor fi transmise numai rezultatele provenind de la sarcinile duplicate, celelalte fiind ignorate).</​note>​+^  **''​setSelectionMode()''​**  ^  **''​setCellSelectionEnabled()''​** ​ ^  **COMPORTAMENT** ​ ^ 
 +| ''​SelectionMode.SINGLE''​ | ''​false''​ | permite selecția unui singur rând din tabelă | 
 +| ''​SelectionMode.SINGLE''​ | ''​true''​ | permite selecția unei singure celule din tabelă | 
 +| ''​SelectionMode.MULTIPLE''​ | ''​false''​ | permite selecția mai multor rânduri din tabelă | 
 +| ''​SelectionMode.MULTIPLE''​ | ''​true''​ | permite selecția mai multor celule din tabelă |
  
-**7.** procesele de urmărire a partiţiilor în care este împărţită o sarcină rulează o buclă care transmite mesaje periodice (//eng.// heartbeat) procesului ce urmăreşte sarcina prin care acesta este anunţat asupra stării sale de funcţionare;​ informaţiile cuprinse în aceste mesaje sunt disponibilitatea de a rula o nouă partiţie a sarcinii, caz în care, ca răspuns la acest mesaj, procesul de urmărire a sarcinii îi va aloca una, după o selecţie corespunzătoare,​ potrivit algoritmului de planificare pe care îl implementează;​ iniţial este selectată sarcina de unde va fi aleasă o partiţie pentru a fi repartizată procesului de monitorizare corespunzător,​ algoritmul implicit bazându-se pe asocierea unor priorităţi pentru fiecare sarcină în parte, de unde vor fi alese apoi partiţiile;​ fiecare proces pentru monitorizarea partiţiei unei sarcini dispune de un număr fix de sarcini de tip map respectiv de tip reduce ​ pe care le pot rula simultan; în distribuirea sarcinilor de tip map se are în vedere localizarea (în reţea) nodului pe care rulează procesul ce urmează să realizeze procesarea, alegându-se unele pentru care setul de date se găseşte cât mai aproape; o astfel de constrângere nu este luată în calcul pentru sarcinile de tip reduce;+=== ComboBox ===
  
-<note tip>Poziţiile corespunzătoare sarcinilor de tip map vor fi completate înaintea poziţiilor aferente sarcinilor de tip reduce (cu alte cuvinte, pentru ​un proces de urmărire a partiţiilor unei sarcini, atâta timp cât există poziţii libere pentru sarcini de tip map, nu vor fi completate poziţiile alocate sarcinilor ​de tip reduce).</​note>​+Un obiect ''​ComboBox''​ este folosit atunci când este necesară selectarea unei opţiuni dintr-o listă care depăşeşte o anumită limită, pentru ​că oferă posibilitatea vizualizării folosind elemente derulante, spre deosebire ​de obiectele ''​ChoiceBox''​. 
  
-<​note>​Valoarea numărului ​de sarcini care pot fi rulate în paralel este dată de capacitatea de procesare a maşinii pe care rulează procesul respectiv cât şi de memoria respectivă.</​note>​+Elementele conţinute (obiect ​de tip listă observabilă) sunt specificate fie la construirea obiectului, fie apelând metoda ''​setItems()'',​ fie folosind metoda ''​addAll()''​ aplicată unui obiect obţinut din ''​getItems()''​. 
  
-<​note>​Ideal este ca datele să se găsească cât mai aproape de nodul care urmează să realizeze procesarea, pe acelaşi maşină sau pe acelaşi rastel. Nu întotdeauna o astfel de constrângere ​poate fi satisfăcută, într-o astfel de situaţie înregistrându-se o creştere a traficului utilizat în reţeaua de calculatoare.</​note>​+Selecţia poate fi specificată prin metoda ''​setValue()''​ (care modifică şi obiectul asociat din proprietatea ''​selectionModel'',​ chiar dacă valoarea indicată nu se regăsește printre valorile din cadrul controlului), și poate fi obţinută prin metoda ''​getValue()''​. 
  
-**8.** după ce procesului ​de monitorizare a partiţiei sarcinii i-a fost alocată sarcina pe care trebuie să o ruleze, acesta îşi va copia arhiva .jar conţinând codul care va fi executat din contextul sistemului distribuit de fişiere în sistemul de fişiere local precum şi alte fişiere necesare din zona de memorie tampon distribuită;​ ulterior, creează un director temporar pentru sarcină, dezarhivând conţinutul ​fişierului ​.jar, acesta fiind rulat în contextul unui obiect de tipul ''​TaskRunner'',​ instanţiat în acest scop; +Numărul de opţiuni vizibile din cadrul listei ​va fi modificat folosind metoda ''​setVisibleRowCount()''​, primind ca parametru numărul de elemente care vor fi afişate.
  
-**9.** obiectul ​de tipul ''​TaskRunner'' ​lansează o maşină virtuală Java nouă;+<note warning>​Deși clasa ''​ComboBox''​ este generică, este recomandat ca aceasta să nu fie parametrizată folosind obiecte ale clasei ''​Node''​ sau derivate din aceasta. Întrucât structura grafului ​de scene implică faptul că un singur nod se poate afla într-o anumită locație la un moment dat, în momentul accesării unui control din cadrul unui obiect ​''​ComboBox''​, el va fi eliminat din acesta, urmând să fie adăugat înapoi la modificarea selecției. În schimb, se vor folosi mecanisme de tip "​fabrică" de celule (printr-un apel al metodei ''​setCellFactory()''​ ce primește ca parametru un obiect de tip ''​Callback''​ pentru care trebuie implementată metoda ''​call()''​).</​note>​
  
-**10.** fiecare sarcină va fi rulată în contextul acestei maşini virtuale Java, astfel că orice erori sau funcţiile de tip map/reduce definite de utilizator nu vor afecta procesul de monitorizare a partiţiei sarcinii, implicând comportamente nedorite (încetarea funcţionării);​ fiecare partiţie a sarcinii comunică cu procesul părinte prin interfaţa ombilicală,​ informându-l de progresul său la fiecare câteva secunde până când aceasta este terminată.+=== Separator ===
  
-<note tip>​Există posibilitatea ca aceeași maşină virtuală Java să fie refolosită între mai multe partiţii ale sarcinii.</​note>​+Elementul ''​Separator''​ este utilizat doar pentru a distinge între elementele unui grup sau pentru a structura interfaţa grafică, fără a produce vreo acţiune.
  
-Întrucât sarcinile de tip MapReduce durează o perioadă mai mare de timp, este important ca utilizator să aibă informaţii cu privire la progresul acestora. Astfel, fiecare sarcină şi partiţiile sale sunt caracterizate printr-o stare (în execuţie, terminată cu succes, eşuată din cauza unei erori), progresul operaţiilor de tip map şi reduce, valorile contoarelor asociate sarcinii în cauză precum şi un mesaj (descriere) asociat stării respective. Progresul, adică proporţia din sarcină care a fost executată deja (dacă poate fi determinată),​ este comunicată periodic clientului.+Un obiect ''​Separator''​ poate fi orizontal sau vertical, orientarea sa modificându-se prin metoda ''​setOrientation()''​. 
  
-Un progres înregistrat ​de o partiţie a sarcinii este transmisă procesului care o monitorizează prin intermediul unui semafor ​(//eng.// flag). Acesta e verificat de un fir de execuţie dedicat la fiecare trei secunde şi în condiţiile în care valoarea ​sa o impune, procesul de monitorizare a partiţiei sarcinii este informat de progresul realizat. De asemenea, în mesajele transmise către procesul de monitorizare al sarcinii sunt transmise şi date cu privire la progresul înregistrat de toate partiţiile sarcinii monitorizate în mod curent. +Dimensiunea unui astfel ​de obiect poate fi precizată în cadrul metodei ''​setMaxWidth()'', ​în timp ce poziţia sa               (orizontală sau verticală) se face cu ''​setValignement()''​, respectiv ''​setHalignement()''​, altfel implicit acesta ocupă tot spaţiul care îi este alocat.
  
-<note tip>De regulă, astfel de mesaje de semnalizare sunt transmise o dată la fiecare cinci secunde, însă este posibil ca pentru clustere de dimensiuni mai mari, această perioadă să fie mai mare de vreme ce mesajele ocupă lăţime de bandă în cadrul reţelei de calculatoare care conectează nodurile.</​note>​+Fiind derivat din clasa ''​Node''​, el poate fi stilizat, i se pot adăuga efecte vizuale şi poate fi animat. 
  
-Valorile referitoare la progres sunt agregate de procesul de monitorizare al sarcinii, rezultând o viziune de ansamblu asupra tuturor sarcinilor rulate la un anumit moment de timp şi asupra partiţiilor constituente. Ulterior obiectul de tip ''​Job''​ primeşte cel mai recent statut interogând procesul de monitorizare al sarcinii în fiecare secundă.+=== Slider ===
  
-<note tip>​Clienţii pot folosi și metoda ​''​getStatus()'' ​a obiectului de tip ''​Job'',​ obţinând ​o instanţă a unui obiect de tip ''​JobStatus''​, care conţine toate informaţiile cu privire la starea sarcinii.</​note>​+Un control ​''​Slider'' ​conţine o pistă şi un cursor care poate fi poziţionat. Totodată, poate include marcaje ce pot avea etichete asociate, indicând diferite valori numerice din intervalul respectiv.
    
-Când procesul de monitorizare a sarcinii primeşte notificări provenind de la toate partiţiile sarcinii cu privire la încheierea acestora ​(inclusiv sarcina pentru eliberarea resurselor), va modifica statutul asociat acesteia ca fiind "​terminată cu succes"​, acesta fiind transmis şi obiectului de tip ''​Job'', ​care informează la rândul său utilizatorul cu privire la acest fapt, părăsind metoda ​''​waitForCompletion()''​. Toate statisticile şi contoarele cu privire la sarcină sunt afişate la consolă în acest moment. La final, procesul de monitorizare a sarcinii eliberează toate resursele utilizate temporar instruind şi procesele care gestionează partiţiile sarcinii să acţioneze în acelaşi sens.+Metodele pe care le pune la dispoziţie această clasă sunt: ''​setMin()''​, ''​setMax()''​, ''​setValue()'', ​''​setShowTickLabels()''​, ''​setShowTickMarks()'', ​''​setMajorTickUnit()'',​ ''​setMinorTickCount()'',​ ''​setBlockIncrement()''​.
  
-<​note>​Procesul de monitorizare a sarcinii poate să transmită o notificare cu privire la starea acesteia ​şi prin HTTP, în situaţia în care este configurată proprietatea ​''​job.end.notification.url'' ​de către clienţii ​care doresc ​să primească astfel de informaţii prin intermediul unor apeluri inverse (//eng.// callback).</​note>​+Metodele ''​setMin()'' ​şi ''​setMax()''​ definesc valorile extreme între care poate fi derulat obiectul de tip ''​Slider''​, în timp ce ''​setValue()'' ​indică valoarea curentă a cursorului (care trebuie ​să fie mai mare decât valoarea minimă şi mai mică decât valoarea maximă). 
  
-Întrucât pentru clustere ​de dimensiuni foarte mari (peste 4000 de noduri) sistemul MapReduce "​clasic"​ are probleme de scalabilitate,​ a fost implementat **mecanismul YARN** ​(Yet Another Resource Negociator / YARN Application Resource Negociator) care rezolvă astfel de inconveniente,​ separând responsabilităţile procesului de monitorizare a sarcinilor (planificarea sarcinii cât şi monitorizarea progresului realizat de partiţiile asociate acesteia) în două procese independente:​  +Modul de vizualizare al obiectului ''​Slider''​ este definit ​de metodele ''​setShowTickMarks()'' ​şi ''​setShowTickLabels()''​ care primesc ca argumente parametri ​de tip ''​boolean''​. 
-  * un proces pentru gestiunea resurselor în cadrul clusterului;​ +
-  * un proces pentru gestiunea aplicaţiilor pe parcursul ciclului lor de viaţă.+
  
-<note tip>​Pentru fiecare instanţă a unei aplicaţii există un proces de gestiune dedicat, ​care rulează atâta vreme cât aceasta ​se află în execuţie.</​note>​+Metoda ''​setBlockIncrement()''​ precizează distanţa cu care se mişcă cursorul atunci când utilizatorul apasă pe pista asociată. În cazul în care se doreşte alinierea cursorului cu marcajele din cadrul pistei, se poate folosi metoda ''​setSnapToTicks()''​.
  
-Aceste procese negociază căror noduri ​(containere) le vor fi alocate anumite programe, respectându-se constrângerile cu privire la capacitatea lor de procesare ​şi referitoare la memoria disponibilă. Verificarea acestor restricţii ​este realizată ​de procesul ​de gestiune al nodului, ce asigură faptul că nu sunt utilizate mai multe resurse decât au fost alocate.+Valoarea la care se găseşte cursorul poate fi obţinută prin metoda ''​getValue()'' ​şi este de obicei ​de tip ''​double''​.
  
-<​note>​Planificarea sarcinii se referă la asocierea partiţiilor asociate acestora unor anumite procese folosind nişte mecanisme de prioritate.<​/note>+=== ProgressBar ​/ ProgressIndicator ===
  
-<​note>​Monitorizarea progresului realizat de partiţiile asociate unei sarcini implică păstrarea evidenţei acestora, cu repornirea sarcinilor care nu au generat erori sau a celor care progresează într-un ritm necorespunzător ​şi determinarea statisticilor cu privire la progresul lor, atâta timp cât se află în execuţie.</​note>​+Prin clasele ''​ProgressBar''​ și ''​ProgressIndicator''​ se indică utilizatorului faptul că o sarcină este în curs de execuţie, precizându-se şi care este cantitatea din cadrul acesteia care a fost terminată deja.
  
-YARN este mai generic decât MapReduce, aceasta reprezentând doar un tip de aplicaţie ce poate fi rulată folosind acest mecanism, flexibilitatea sa constând în coexistenţa (în cadrul aceluiaşi cluster) al unor programe având tipuri diferite (de exemplu MPI sau un shell distribuit),​ ceea ce implică beneficii pentru gestiunea şi utilizarea resurselor respective. De asemenea, utilizatorii ​ pot rula diferite versiuni ale MapReduce, astfel că actualizarea de la o versiune la alta se poate realiza foarte uşor.+<​note ​tip>''​ProgressBar''​ reprezintă o subclasă a ''​ProgressIndicator''​.</​note>​
  
-Entităţile implicate la rularea ​unei aplicaţii de tip MapReduce folosind YARN sunt:  +Obiectele ''​ProgressBar''​ au forma unei bare.
-  * clientul, care transmite sarcina de tip MapReduce;​ +
-  * procesul pentru gestiunea resurselor (//eng.// Resource Manager) care coordonează alocarea resurselor de procesare pe cluster; +
-  * procesele pentru gestiunea nodurilor (//eng.// Node Manager) care lansează în execuţie şi monitorizează containerele în cadrul maşinilor din cluster; +
-  * procesul de gestiune a aplicaţiilor (//eng.// Application Master) care va coordona partiţiile sarcinilor;+
  
-<note tip>​Atât procesul ​de gestiune a aplicaţiilor cât şi partiţiile sarcinii MapReduce rulează în cadrul unor containere care sunt alocate de procesul de gestiune al resurselor, fiind monitorizate de procesele de gestiune a nodurilor.</​note>​+Obiectele ''​ProgressIndicator''​ sunt de forma unei diagrame circulare al cărui conţinut se umple pe măsură ce procentul este mai mare.
  
-  * sistemul distribuit de fişiere (de obicei HDFS), utilizat pentru partajarea fişierelor între aceste entităţi.+Constructorul acestor clase primeşte ca parametru procentul în care sarcina a fost completată (alternativ se poate folosi metoda ''​setProgress()''​).
  
-{{ :​laboratoare:​laborator10:​figura04_sistemul_map_reduce_yarn.png?nolink }}+<note tip>​Valoarea folosită ca parametru pentru constructorul claselor ''​ProgressBar''​ / ''​ProgressIndicator''​ sau pentru metoda ''​setProgress()''​ este subunitară.</​note>​
  
-Etapele urmate la crearea unei sarcini de tip MapReduce ​în cadrul YARN sunt următoarele:+<​note ​tip>Există posibilitatea ca obiectele să fie create fără parametru, ​în cazul în care nu se poate evalua dimensiunea sarcinii în cauză. Într-o astfel de situaţie, metodele pot primi ca parametru şi o valoare negativă. Metoda ''​isIndeterminate()''​ se utilizează pentru a verifica dacă progresul este într-o stare nedeterminată sau nu.</​note>​
  
-**1.** transmiterea sarcinii se realizează folosind acelaşi API ca în cazul mecanismului MapReduce clasic, deşi există şi o implementare a ''​ClientProtocol''​ care este activată atunci când proprietatea ''​mapreduce.framework.name''​ are valoarea ''​yarn''​ în care procesul de transmitere a sarcinii este destul de similar cu cel al mecanismului MapReduce clasic;+Clasele mai pun la dispoziţia programatorilor metoda ​''​progressProperty'' ​care întoarce valoarea progresului respectiv şi pe care este aplicat obiectul ascultător în cazul modificărilor acesteia.
  
-**2.** identificatorul sarcinii este transmis de la procesul de gestiune a resurselor (faţă de cazul mecanismului MapReduce clasic în care acesta era primit de la procesul de monitorizare a sarcinii);+=== Hyperlink ===
  
-<note tip>În terminologia mecanismului YARN, pentru o sarcină se foloseşte conceptul de aplicaţie.</​note>​+Clasa ''​Hyperlink''​, derivată din ''​Labeled''​ (din care moşteneşte metodele ''​setText()''​ şi ''​setGraphic()''​) este folosită spre a formata texte care au semnificaţia legăturilor Internet. 
  
-**3.** clientul verifică specificaţiile sarcinii în privinţa locaţiei unde urmează să fie plasate rezultatele ​şi calculează partiţiile datelor ​de intrare, copiind resursele specifice sarcinii ​(fişierul .jar care conţine codul corespunzător sarcinii, fişierul de configurare dar şi partiţiile datelor de intrare) în sistemul distribuit de fişiere HDFS;+Starea unei legături (vizitată / nevizitată) poate fi marcată prin metoda ''​setVisited()''​. Acţiunea asociată operaţiei de apăsare poate fi precizată prin metoda ''​setOnAction()''​ care primeşte un obiect ​de tip ''​EventHandler<​ActionEvent>'' ​(având definită metoda ''​handle()'' ​corespunzătoare). La aceesarea unui astfel de obiect, locaţia poate fi vizualizată printr-un obiect ''​WebEngine''​ (obţinut ca ''​new WebView().getEngine()''​) pentru care se apelează metoda ''​load()''​.
  
-<note tip>Opţiunea ''​yarn.app.mapreduce.am.compute-splits-in-cluster''​ face ca partiţiile datelor de intrare să fie calculate în cadrul clusterului,​ ceea ce este util mai ales în cazul sarcinilor care au un număr mare de partiţii ale datelor de intrare.</note>+<code java> 
 +Hyperlink hyperlink = new Hyperlink();​ 
 +String URL = "​http://​aipi2015.andreirosucojocaru.ro"; 
 +hyperlink.setText(URL);​ 
 +hiperlink.setOnAction((ActionEvent actionEvent) ​-> { 
 +        new WebView().getEngine().load(URL);​ 
 +    } 
 +); 
 +</code>
  
-**4.** sarcina este transmisă prin apelul metodei ''​submitApplication()''​ în contextul procesului de gestiune a resurelor;+=== HTMLEditor ===
  
-**5.** când procesul ​de gestiune al resurselor primeşte acest apel, transmite mai departe această cerere către procesul ​de planificare al sarcinilor care îi alocă un container astfel încât procesul specific aplicaţiei va fi lansat (de către procesul de gestiune al resurselor) în acest context, fiind supervizat de către procesul de gestiune a nodului respectiv;+Controlul ''​HTMLEditor''​ este un editor de texte cu numeroase funcţionalităţi pentru redactarea documentelor HTML5: 
 +  ​* formatare de text (bold, italic, underline, strike though); 
 +  ​* configurări referitoare la paragraf (formatare, tip și dimensiune caractere);​ 
 +  ​* culori de fundal; 
 +  ​* indentare ​de text; 
 +  * liste numerotate ​şi nenumerotate;​ 
 +  * aliniere ​de text; 
 +  * folosirea unei rigle orizontale;​ 
 +  * facilităţi copy/paste pentru fragmente ​de text.
  
-**6.** procesul specific al aplicaţiei pentru sarcini de tip ''​MapReduce'' ​este de fapt un program Java având clasa principală ''​MRAppMaster'';​ acesta iniţializează sarcina în cauză creând un număr de obiecte care vor monitoriza progresul sarcinii, primind rapoarte în acest sens de la partiţiile în care va fi împărţită sarcina;+În cadrul editorului ​este redat conţinutul unei pagini Internet asociat unui cod HTML. 
  
-**7.** procesul specific al aplicaţiei preia partiţiile datelor de intrare determinate de client din cadrul sistemului distribuit de fişiere, creând apoi o partiţie a sarcinii (aplicaţie de tip map) pentru fiecare dintre acestea dar şi un număr de procese de tip reduce (conform proprietăţii ​''​mapreduce.job.reduce''​); ulterior, procesul specific al aplicaţiei decide modul în care va rula partiţiile care constituie sarcina de tip MapReduce: dacă aceasta este de dimensiuni mici, partiţiile vor fi rulate în aceeaşi maşină virtuală Java ca şi el însuşi - o astfel de sarcină se spune că rulează ca o super-partiţie;​ o sarcină este considerată ca fiind de dimensiuni mici dacă poate fi partiţionată în mai puţin de 10 procese de tip map şi un singur proces de tip reduce, iar dimensiunea fişierului de intrare este mai mică decât un bloc HDFS; înainte ca orice partiţie a sarcinii să fie rulată, trebuie apelată metoda de configurare ​(o instanţă a obiectului de tip ''​OutputCommitter'' ​corespunzător sarcinii) pentru a se crea directorul în care vor fi plasate rezultatele acesteia;+Constructorul unui obiect ​''​HTMLEditor'' ​nu primeşte parametri, dimensiunea ​sa putând ​fi specificată prin metodele ''​setPrefWidth()'' ​/ ''​setPrefHeight()''​. ​
  
-<​note>​Decizia cu privire la rularea partițiilor sarcinii în aceeași mașină virtuală cu procesul specific al aplicației este luată ​ţinându-se cont de faptul că supraîncărcarea generată de alocarea şi rularea sarcinilor în alte containere depăşeşte beneficiul ​obţinut ​din rularea acestora în paralel ​(comparativ cu rularea lor secvenţială,​ în cadrul aceluiaşi nod). Un astfel de comportament este diferit de mecanismul MapReduce clasic, în care sarcinile de dimensiuni mici nu sunt rulate niciodată în contextul unui singur proces de monitorizare a partiţiilor sarcinii.</​note>​+Conţinutul (o pagină Internet dată prin codul HTML) va fi specificat prin metoda ''​setHtmlText()''​. Acesta poate fi obţinut ​folosind metoda "​pereche"​ ''​getHtmlText()''​.
  
-<note tip>​Posibilitatea de a rula o sarcină ca o super-partiție ​poate fi dezactivată prin proprietatea ​''​mapreduce.job.ubertask.enable'' ​care va avea valoarea ​''​false''​.</​note>​+Vizualizarea conţinutului acestui editor într-un navigator ​poate fi realizată tot prin metoda ​''​load()'' ​a unui obiect ''​WebEngine'',​ ca în cazul obiectul ​''​Hyperlink''​.
  
-<​note ​tip>Caracteristicile unei sarcini ​de dimensiuni mici pot fi specificate prin intermediul proprietăţilor:​ +<​note ​important>Conținutul corespunzător unui cod HTML afișat ​de un obiect ​''​HTMLEditor'' ​și de un navigator ​''​WebEngine'' ​pentru ​care se apelează metoda ​''​load()'' ​ar trebui să fie identic.</​note>​
-  * ''​mapreduce.job.ubertask.maxmaps''​, respectiv ​''​mapreduce.job.ubertask.maxreduces''​, care indică numărul de procese;  +
-  * ''​mapreduce.job.ubertask.maxbytes''​, care specifică dimensiunea unui bloc. +
-</​note>​+
  
-<​note>​Spre diferenţă ​de implementarea MapReduce clasică în care metoda de configurare este apelată într-un proces special rulat de procesul de monitorizare a partiţiilor sarcinilor, în cazul implementării YARN, aceasta este apelată direct de către procesul specific al aplicaţiei.</​note>​+Fiind derivat din clasa ''​Node'',​ acestui tip de obiect i se pot aplica stiluri, efecte vizuale sau transformări.
  
-**8.** în cazul în care sarcina nu întruneşte condiţiile pentru a rula ca super-partiţie,​ procesul specific al aplicaţiei solicită containere pentru toate procesele de tip map şi reduce din cadrul sarcinii de la modulul de gestiune a resurselor; cererile sunt incluse în cadrul rapoartelor periodice, conţinând informaţii cu privire la locaţia unde se găsesc informaţiile corespunzătoare fiecărei partiţii de tip map (nodurile şi rastelurile pe care se găsesc acestea), acestea fiind folosite de procesul de planificare în luarea deciziilor, încercându-se plasarea sarcinilor aferente în cadrul aceleiaşi maşini ca şi datele sau, în situaţia în care nu este posibil, cel puţin pe acelaşi rastel;+=== Tooltip ===
  
-<​note>​În cadrul cererilor pentru containere se specifică de asemenea informaţii cu privire la memoria necesară; implicit, atât proceselor de tip map cât şi proceselor de tip reduce li se alocă 1024 MB de memorie, însă această valoare poate fi configurată prin intermediul proprietăţilor ​''​mapreduce.map.memory.mb''​, respectiv ''​mapreduce.reduce.memory.mb''​. Modul în care este alocată memoria este diferit de mecanismul MapReduce tradițional,​ în care procesele de monitorizare a partiţiilor sarcinii dispuneau de un număr fix de sarcini de tip map sau de tip reduce pe care le puteau rula în paralel, stabilit la momentul configurării clusterului;​ fiecare sarcină putea dispune de o valoare maximă a memoriei (de asemenea având o valoare fixă pentru ​un cluster), existând probleme atât dacă aceasta este subutilizată (întrucât alte partiţii ale sarcinii, aflate în aşteptare, nu pot utiliza memoria nefolosită),​ cât şi dacă este suprautilizată (conducând la eşuarea sarcinii, de vreme ce aceasta nu dispune de memorie suficientă pentru a putea fi terminată). O astfel de problemă este rezolvată în YARN prin faptul că aplicaţiile ​pot solicita o anumită valoare a memoriei, ce se află între o valoare minimă şi o valoare maximă (cu condiţia de a fi un multiplu al valorii minime care poate fi alocată). Fiecare proces de planificare are valori implicite de alocare a memoriei, ​ valoarea minimă fiind de 1024 MB (stabilită de ''​yarn.scheduler.capacity.minimum-allocation-mb''​), iar valorea maximă de 10240 MB (stabilită de ''​yarn.scheduler.capacity.maximum-allocation-mb''​). Astfel, partiţiile sarcinilor pot solicita orice alocare de memorie cuprinsă între 1GB şi 10GB, însă ca multiplu de 1GB (procesul de planificare a sarcinii va realiza rotunjiri la cea mai apropiată valoare, dacă este necesar).</​note>​+Obiectele ​''​Tooltip'' ​sunt folosite ​pentru ​texte explicative ​ce pot fi asociate oricăror controale JavaFX din pachetul ​''​javafx.scene.control'' ​prin apelul metodei ​''​setTooltip()''​. ​
  
-**9.** după ce unei partiţii a sarcinii ​i-a fost alocat ​un container ​de către procesul de planificare a modulului de gestiune a resurselor, procesul specific al aplicaţiei porneşte acest container, contactând procesul de gestiune a nodului;+Starea sa poate fi activat şi vizibil (un obiect ''​Tooltip''​ care este vizibil este în același timp și activat), existând ​de regulă o întârziere între cele două momente (plasarea mouse-ului asupra obiectului ​şi afişarea propriu-zisă). ​
  
-**10.** partiţia sarcinii este executată de o aplicaţie Java a cărei clasă principală este ''​YarnChild''​; înainte de a rula partiţia sarcinii, va localiza resursele de care aceasta are nevoie (inclusiv configuraţia sarcinii ​şi arhiva ​.jar conţinând codul propriu-zis al sarcinii precum şi alte fişiere din cadrul zonei tampon de memorie aflate în cadrul sistemului distribuit de fişiere);+Fiind derivată din ''​Labeled'', ​i se poate asocia nu numai un text, ci şi o imagine. 
  
-<​note>​Aplicaţia ​''​YarnChild'' ​rulează într-o maşină virtuală Java dedicată, din acelaşi motiv pentru ​care în cazul mecanismului MapReduce "​clasic"​ procesele de monitorizare a partiţiei sarcinii creează noi maşini virtuale Java pentru a rula aplicaţiile corespunzătoare – izolarea codului utilizator de firele de execuţie ale sistemului de operare ​care rulează în fundal, având asociate sarcini care durează foarte mult. Spre diferenţă de implementarea MapReduce "​clasică",​ YARN nu suportă reutilizarea maşinilor virtuale Java, astfel încât fiecare partiţie a sarcinii va rula într-o nouă maşină virtuală Java.</​note>​+Legătura dintre un control de tip ''​Node''​ şi obiectul ''​Tooltip''​ asociat poate fi eliminată prin metoda ''​uninstall()'' ​care primeşte ca argumente elementele ​care se doresc decuplate.
  
-**11.** containerul rulează partiţia sarcinii (de tip map sau reduce).+=== TitledPane / Accordion ===
  
-În cazul Yarn, partiţia sarcinii îşi raportează starea ​şi progresul ​(inclusiv valoarea contoarelor) la procesul specific al aplicaţiei, care dispune astfel ​de o viziune de asamblu a sarcinii. +Obiectele de tip ''​TitledPane''​ reprezintă panouri care au asociat ​şi un titlu, putând fi deschise ​şi închise, încapsulând orice obiect de tip ''​Node'' ​(controale, grupuri ​de elemente din cadrul unui container). 
  
-<​note>​Astfel ​de rapoarte sunt transmise la fiecare trei secunde, prin intermediul interfeţei ombilicale. Procesul este mai simplu decât în cazul implementării MapReduce "​clasice"​ în care actualizările cu privire la progres sunt transmise ​prin procesele de monitorizare a partiţiilor sarcinilor către procesul de monitorizare a sarcinii care deţine viziunea de ansamblu asupra acesteia.</​note>​+Obiectele ''​TitledPane''​ pot fi construite primind ca parametri textul / obiectul ​de tip ''​Node''​, acestea putând fi specificate ulterior ​prin metodele ''​setText()'',​ respectiv ''​setContent()''​. Implicit, orice obiect TitledPane poate fi închis şi deschis (proprietate ce poate fi specificată prin metoda ''​setCollapsible()''​),​ acţiunea realizându-se în mod animat (metoda ''​setAnimated()''​ indică acest comportament).
  
-La rândul său, procesul specific al aplicației e interogat de client la fiecare secundă (sau în intervalul stabilit ​de proprietatea ​''​mapreduce.client.progressmonitor.pollinterval''​). Totodată, interfaţa grafică a procesului de gestiune a resurselor afişează toate aplicaţiile ​care se află în execuţie, împreună cu legături către interfeţele grafice ale proceselor specifice aplicaţiilor respective, care conţin detalii despre sarcina MapReduce, inclusiv progresul acesteia.+<note important>​Se recomandă ca înălţimea ​(minimă / maximă ​sau preferată) a unui obiect ​de tipul ''​TitledPane'' ​să nu fie specificată întrucât acest fapt poate conduce la evenimente nedorite în cazul în care acesta este expandat. Dimensiunea obiectului este ajustată astfel încât să poată fi vizualizat întreg ​conţinutul său.</​note>​
  
-<​note>​În cazul implementării MapReduce "​clasice"​, lista sarcinilor aflate în execuţie precum şi progresul lor putea fi consultat prin intermediul interfeţei grafice puse la dispoziţie ​de procesul ​de monitorizare a sarcinilor.</note>+Gruparea obiectelor ''​TitledPane''​ se face prin clasa ''​Accordion''​, acestea putând ​fi astfel afişate împreună. Un obiect ''​Accordion''​ conţine astfel mai multe obiecte ''​TitledPane''​ cu proprietatea că unul singur dintre acestea poate fi vizualizat ​la un moment dat. Obiectul ''​TitledPane''​ vizualizat în mod curent este accesat prin metodele ''​{set/​get}ExpandedPane()''​. Obiectul ​de tip ascultător este aplicat obiectului întors ​de metoda ''​expandedPaneProperty()''​ şi este de tipul ''​ChangeListener<TitledPane>''​.
  
-În acelaşi mod în care clientul interoghează procesul specific al aplicaţiei pentru a determina progresul acesteia, acesta verifică ​(la fiecare cinci secunde) dacă sarcina a fost terminată, printr-un apel al metodei ''​waitForCompletion()''​ pe obiectul de tip ''​Job''​. Există posibilitatea ca notificarea cu privire la terminare să se realizeze prin apeluri inverse folosind protocolul HTTP, însă acestea sunt iniţiate de procesul specific al aplicaţiei.+<code java> 
 +Accordion accordion = new Accordion();​ 
 +TitledPane titledPane1 = new TitledPane(), titledPane2 = new TitledPane(); 
 +// ... 
 +titledPane1.setContent(...);​ 
 +titledPane2.setContent(...);​ 
 +accordion.getPanes().add(titledPane1);​ 
 +accordion.getPanes().add(titledPane2);​ 
 +accordion.expandedPaneProperty().addListener( 
 +    (ObservableValue<?​ extends TitledPane>​ observableValue,  
 +     ​TitledPane oldValue,  
 +     ​TitledPane newValue) -> { 
 +        // ... 
 +    } 
 +); 
 +</​code>​
  
-<note tip>​Intervalul la care este verificată terminarea sarcinii poate fi stabilit prin intermediul proprietăţii ''​mapreduce.client.completion.pollinterval'',​ în fişierul de configurare.</​note>​+=== ColorPicker ===
  
-La terminarea sarcinii, procesul specific al aplicaţiei şi containerele în care sunt rulate partiţiile acesteia eliberează resursele utilizate, printr-un apel al metodei corespunzătoare din cadrul obiectului ​''​OutputCommitter''​. Informaţiile cu privire la sarcină sunt arhivate de către serverul ce reţine istoricul acestora, pentru a permite interogări ulterioare din partea clienţilor,​ în caz de nevoie.+Controlul ​''​ColorPicker'' ​este un element de interfaţă cu utilizatorul care permite selecţia unei culori dintr-o anumită gamă dar şi specificarea acesteia prin parametrii HSB (Hue/​Saturation/​Brightness) sau RGB (Red/​Green/​Blue).
  
-==== Tratarea Erorilor ====+Obiectul conţine: 
 +  * o listă pentru selecţia culorii - un obiect de tip ''​ComboBox''​ având un indicator de culoare și o etichetă corespunzătoare;​ 
 +  * o paletă de culori predefinite;​ în cazul în care au fost definite culori de către utilizator, acestea sunt incluse într-o secțiune distinctă; navigarea în cadrul paletei de culori poate fi realizată prin folosirea tastelor sus, jos, stânga, dreapta; 
 +  * fereastra de dialog pentru specificarea parametrilor acesteia (aceasta este deschisă în mod automat atunci când este selectată o anumită valoare din paleta de culori sau atunci când se selectează opţiunea ''"​Custom Color..."''​);​ utilizatorii își pot defini o culoare: 
 +    * prin mişcarea mouse-ului asupra suprafeţei de culoare şi asupra barei de culori, parametrii HSB / RGB fiind modificaţi în mod automat; 
 +    * specificând parametrii HSB / RGB sau Web (#, urmat de 6 cifre hexa)); 
 +    * transparenţa culorii poate fi specificată prin intermediul parametrul ''​Opacity'',​ care poate avea valori cuprinse între 1 şi 100
  
-Unul dintre principalele avantaje ale Hadoop constă în posibilitatea ​de **recuperare din eroare**, situaţie întâlnită cu o frecvenţă destul de mare şi datorată greşelilor din codul sursă al utilizatorilor,​ blocajelor în cadrul proceselor ​şi defectării maşinilor pe care rulează acestea.+Un element grafic ​de tip ''​ColorPicker''​ se poate crea fără parametri sau poate fi indicată o anumită culoare considerată curentă (aceasta poate fi gestionată şi prin intermediul metodelor ''​{get/​set}Value()''​). Clasa ''​Color''​ pune la dispoziţie mai multe culori predefinite care au denumiri specifice sau, pentru crearea de culori predefinite pot fi folosite metodele statice ''​rgb()''​ / ''​hsb()''​ (care primesc cei 3 parametri sau opţional 4, dacă se doreşte şi precizarea transparenţei) respectiv metoda statică ''​web()'' ​care primeşte un şir de caractere.
  
-În cazul **implementării MapReduce "​clasice"​** defectele se pot produce la nivelul: +Culorile definite de utilizator ​pot fi obţinute folosindu-se metoda ''​getCustomColors()''​ al cărui rezultat este un obiect de tipul ''​ObservableList<​Color>''​. Culorile definite de utilizator nu pot fi reîncărcate la repornirea aplicaţiei decât în situaţia în care este implementat un mecanism de persistenţă. 
-  - unei partiţii a sarcinii; +
-  ​- procesului ce o monitorizează; +
-  - procesului care monitorizează sarcina ​la nivel global.+
  
-**a)** Cel mai frecvent, **erorile ​de la nivelul unei partiţii a sarcinii** se datorează greşelilor din codul sursă, generându-se o excepţie la rulare care este raportată procesului care o monitorizează,​ aceasta fiind înregistrată şi în cadrul jurnalelor. Procesul ​de monitorizare a partiţiei sarcinii marchează această încercare ca fiind eşuată, eliberând poziţia ocupată de aceasta pentru ca în cadrul acesteia să fie rulată o altă partiţie a sarcinii. În cazul în care maşina virtuală Java îşi încetează activitatea brusc (datorită unor probleme ale acesteia pentru setul de date al partiţiei respective a sarcinii), procesul de monitorizare va detecta faptul că partiţia sarcinii nu mai rulează şi marchează încercarea de execuţie ca fiind eşuată. În situaţia în care partiţiile sarcinilor sunt suspendate în execuţie, procesul de monitorizare detectează că nu a primit o actualizare a progresului pentru o perioadă de timp mai îndelungată, declanşând procesul de marcare a încercării de rulare ​a partiţiei sarcinii ca eşuată şi determinând închiderea maşinii virtuale Java care o rula.+Implicit, aspectul unui astfel ​de obiect ​este cel de ''​ColorPickerSkin''​ (din pachetul ''​javafx.scene.control.skin''​). Alternativ, pot fi precizate stiluri asemănătoare obiectelor ''​ArrowButton''​ sau ''​SplitButton''​, folosind clasele CSS corespunzătoare, sau poate fi redefinită proprietatea ''​-fx-skin'' ​a clasei CSS ''​.color-picker''​.
  
-<note>Perioada de timp după care partiţiile sarcinilor sunt considerate eşuate e de obicei 10 minute, putând fi configurată ​(pentru fiecare sarcină în parte sau pentru fiecare cluster în parte) prin intermediul proprietăţii ''​mapred.task.timeout''​ a cărei valoare este exprimată în milisecunde. Indicarea unei valori nule pentru această proprietate dezactivează mecanismul de expirare, astfel că sarcinile a căror execuţie durează mai mult nu vor fi marcate niciodată ca fiind eşuate. Într-un astfel de caz, o partiţie a sarcinii suspendată în execuţie nu îşi va elibera niciodată poziţia, existând posibilitatea de a se înregistra încetinerea globală a cluster-ului. De aceea, acest comportament trebuie evitat, asigurându-se că partiţiile sarcinilor îşi raportează progresul.</note>+<code java> 
 +colorPicker.getStyleClass().add("​arrow-button"​);​ 
 +colorPicker.getStyleClass().add("​split-button"​);​ 
 +</code>
  
-Când procesul de monitorizare a partiţiei sarcinii este notificat de eşecul ​unei încercări (prin intermediul rapoartelor periodice), va replanifica execuţia ei, încercându-se să se evite situaţia în care rularea va fi realizată în contexul unui proces ​de monitorizare în care a eşuat anterior. Mai mult, în cazul în care o partiţie a sarcinii eşuează de mai mult de patru ori, ea nu va fi reexecutată. Implicit, dacă orice partiţie a sarcinii eşuează de mai mult de patru ori (sau de valoarea maximă configurată pentru ​numărul de încercări), ​întreaga ​sarcină va eşua. Pentru unele aplicaţii, nu este de dorit ca sacina să eşueze din cauza unor partiţii ale sale care au înregistrat erori, întrucât este posibil ca rezultatele furnizate de partiţiile terminate cu succes să poată fi folosite, motiv pentru care se poate configura proporția de partiţii ale sarcinii care pot să eşueze fără a declanşa eşuarea sarcinii. O partiţie a sarcinii ​poate fi oprită în mod forţat, însă astfel de încercări nu sunt contorizate în numărul maxim de lansare în execuţie, de vreme ce eroarea nu s-a produs din cauza partiţiei sarcinii. Şi utilizatorii au posibilitatea de a termina încercări ale partiţiilor sarcinilor ​(sau chiar sarcina în totalitate) folosind interfaţa grafică sau linia de comandă.+<note tip>​Încărcarea ​unei foi de stil care să fie valabilă pentru întreaga ​scenă poate fi realizată prin metoda ''​scene.getStyleSheets().add("​sceneStyleSheet.css"​)''​.</​note>​
  
-<note tip>​Numărul maxim de încercări de a executa o sarcină este dat de proprietatea ''​mapred.map.max.attempts''​ pentru partiţii ale sarcinii de tip map, respectiv de proprietatea ''​mapred.reduce.max.attempts''​ pentru partiţii ale sarcinii de tip reduce.</​note>​+=== DatePicker ===
  
-<note tip>​Procentul de partiţii de tip map respectiv de tip reduce care pot eșua sunt controlate independent,​ folosind proprietăţile ​''​mapred.max.map.failures.percent''​, respectiv ​''​mapred.max.reduce.failures.percent''​.</​note>​+Obiectul ​''​DatePicker'' ​este un control care permite selecția unei date dintr-un anumit calendar. El constă dintr-un obiect de tip ''​ComboBox'' ​(editabil) având un câmp dată calendaristică și o zonă de selecție a unei date dintr-un calendar.
  
-<​note>​O încercare a partiţiei sarcinii ​poate fi oprită datorită faptului că este un duplicat speculativ ​sau datorită faptului că procesul său de monitorizare a eşuat, astfel încât procesul de monitorizare a sarcinilor va termina ​în mod forţat toate partiţiile ce rulează în contextul său.</​note>​+Constructorul unui obiect de tip ''​DatePicker'' ​poate să nu primească nici un parametru, ​sau poate conține un parametru de tip ''​LocalDate''​ indicând data calendaristică selectată în mod implicit (alternativ,​ poate fi apelată metoda ''​setValue()''​). Specificarea datei curente se face printr-un apel al metodei ''​LocalDate.now()''​.
  
-**b)** **Erorile produse la nivelul procesului de monitorizare a partiţiei sarcinii** reprezintă altă situaţie care determină eşecul sarcinii. Într-un astfel ​de caz, procesul ​de monitorizare a sarcinii va detecta că acesta nu mai funcţionează dacă mesajele periodice întârzie ​de a fi transmise mai mult de 10 minute, eliminându-l din lista sa, planificând partiţiile sarcinilor care au rulat pe acesta pe alte procese de monitorizare,​ chiar în situaţia în care au fost terminate cu succes, dacă aparţin unor sarcini incomplete ​(întrucât valorile ​de ieşire intermediare se găsesc în sistemul de fişiere al procesului de monitorizare defect astfel încât pot să nu fie accesibile). Un proces de monitorizare a partiţiei sarcinii poate fi inclus de asemenea într-o "​listă neagră"​ de către procesul de urmărire a sarcinii, dacă mai mult de patru partiţii din cadrul aceleiaşi sarcini au eşuat rulând pe acesta. Unui astfel de proces nu i se vor mai repartiza partiţii ale sarcinii, continuând însă să comunice cu procesul de monitorizare a sarcinii. Există implementat un mecanism de expirare a erorilor ​(cu o rată de una pe zi), astfel încât procesele de monitorizare a partiţiei sarcinii pot fi scoase din cadrul "​listei negre" doar prin faptul că rulează în continuare. În situaţia în care erorile au fost produse de o situaţie care poate fi remediată, acesta va fi eliminat din "lista neagră" după ce este repornit şi reintegrat în cadrul clusterului.+O dată calendaristică este afișată în formatul definit ​de sistemul local și de sistemul ​de calendare ISO (de regulă ''​mm/​dd/​yyyy''​). Proprietatea ''​converter''​ și metoda ''​setConverter()''​ permit specificarea unui format alternativ pentru ​o dată calendaristică (un parametru ''​null''​ restaurează formatul implicit).
  
-<note>Defecţiunile ce se pot înregistra la un proces de monitorizare a partiției sarcinii vizează fie terminarea ​(sau blocarea sa), fie funcţionarea sa foarte lentă, ceea ce determină ca mesajele periodice să nu mai fie transmise deloc sau să fie transmise mai rar.</​note>​+<code java> 
 +private DatePicker datePicker = new DatePicker(LocalDate.now());
  
-<note tip>​Valoarea ce indică perioada de timp maximă în care se așteaptă mesajele periodice înainte ca procesul de monitorizare a sarcinii să constate o disfuncționalitate la nivelul procesului de monitorizare a pertiției sarcinii poate fi configurată prin intermediul proprietăţii ''​mapred.task.tracker.expiry.interval'',​ care specifică o valoare exprimată în milisecunde.</​note>​+private final String dateFormat = "dd.mm.yyyy";
  
-<note tip>Valoarea care indică numărul de partiții al unei sarcini care au înregistrat erori în cadrul aceluiași proces de monitorizare ​(fiind incluse pe "lista neagră"​) ​poate fi modificată prin intermediul proprietăţii ''​mapred.max.tracker.blacklists''​, acesta fiind un prag mai mare decât media de erori înregistrate de procesele de monitorizare pentru partiţiile sarcinii din cadrul unui cluster.</note>+StringConverter converter = new StringConverter<LocalDate>() { 
 +     
 +    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(dateFormat);​ 
 +             
 +    @Override 
 +    public String toString(LocalDate localDate) { 
 +        if (localDate != null) { 
 +            return dateTimeFormatter.format(localDate);​ 
 +        return ​""​; 
 +    } 
 +             
 +    @Override 
 +    public LocalDate fromString(String string) { 
 +        if (string != null && !string.isEmpty()) 
 +            return LocalDate.parse(string, dateTimeFormatter);​ 
 +        return null; 
 +    } 
 +};              
 +     
 +    datePicker.setConverter(converter);​ 
 +    datePicker.setPromptText(dateFormat.toLowerCase());​ 
 +</code>
  
-**c)** Producerea unei **erori la nivelul procesului de monitorizare a sarcinii** reprezintă situaţia cea mai gravă care poate conduce la eşecul rulării sarcinii. Fiind singurul punct vulnerabil din cadrul ​arhitecturii,​ Hadoop nu dispune de  un mecanism de recuperare dintr-o astfel de situaţie, astfel încât toate sarcinile ​care rulează la un moment dat vor eşua. După repornirea procesului ​de monitorizare a sarcinii, toate sarcinile aflate în execuţie la momentul producerii erorii respective vor trebui să fie retransmise.+Afișarea săptămânii în cadrul ​calendarului se face prin metoda ''​setShowWeekNumbers()'' ​care primește ​un parametru ​de tip ''​boolean''​.
  
-<​note>​Probabilitatea producerii unei astfel de situații este destul ​de mică (de vreme ce probabilitatea defectării unei anumite maşini din cadrul clusterului este mică), această problemă fiind rezolvată de implementarea YARN, al cărei scop a fost eliminarea punctelor de vulnerabilitate identificate în mecanismul MapReduce.</​note>​+Schimbarea funcționalității unui obiect ​de tip ''​DatePicker''​ se face prin implementarea mecanismului de tip fabrică de celule, care generează obiecte ​de tip ''​DateCell''​ având un comportament corespunzător cerințelor funcționale.
  
-<note tip>Există şi posibilitatea de a încerca recuperarea sarcinilor care rulau la momentul opririi procesului de monitorizare (prin proprietatea ''​mapred.jobtracker.restart.recover''​), însă au fost raportate anumite probleme în funcţionarea sa, astfel încât această opţiune nu ar trebui folosită.</note>+<code java> 
 +datePicker.setDayCellFactory(new Callback<​DatePicker,​ DateCell>​() { 
 +    @Override 
 +    public DateCell call(final DatePicker ) { 
 +        return new DateCell() { 
 +            @Override 
 +            public void updateItem(LocalDate item, boolean empty) { 
 +                super.updateItem(item, empty); 
 +                // ... 
 +            } 
 +        }; 
 +    } 
 +}); 
 +</code>
  
-În cazul **mecanismului YARN**, la rularea unor aplicaţii MapReduce se pot produce erori la nivelul: +Astfel, pot fi dezactivate anumite date calendaristice (printr-un apel al metodei ''​setDisable()''​) care nu pot fi selectate pentru ​a se menține consistența informațiilor introduse.
-  ​- partiţiei sarcinii; +
-  - procesului specific ​al aplicaţiei;​ +
-  - procesului de gestiune ​a nodului; +
-  - procesului de gestiune al resurselor.+
  
-**a)** **Erorile produse pentru o partiţie a sarcinii** sunt tratate într-un mod asemănător cu cazul MapReduce "​clasic"​. Excepţiile la rulare precum şi terminarea bruscă a maşinii virtuale Java sunt propagate până la procesul specific al aplicaţiei, şi încercarea ​de rulare a partiţiei sarcinii este marcată ca fiind eşuată. De asemenea, procesele ​a căror execuţie durează prea mult (care sunt blocate) sunt detectate ​prin absenţa transmiterii unui mesaj periodic ​(ping) prin interfaţa ombilicală. Se pot folosi aceleaşi proprietăţi de configurare pentru a indica eşecul definitiv al unei partiţii a sarcinii sau al întregii aplicaţii.+Un obiect de tip ''​DatePicker''​ suportă și sisteme de calendare non-ISO, cum ar fi cronologiile japoneze, Hijrah, Minguo și tailandeze-budiste. Precizarea unui sistem ​de măsurare ​a timpului alternativ se face prin intermediul metodei ''​setChronology()''​.
  
-<​note ​tip>​Perioada la care este aşteptat un mesaj periodic ​(pinb) poate fi configurat prin intermediul proprietăţii ''​mapreduce.task.timeout''​.</note>+Operațiile cu obiecte de tip dată calendaristică sunt definite în pachetul ''​java.time'',​ putând fi utilizate clasele ​care definesc obiecte corespunzătoare diferitelor sisteme de calendare definite de ISO (//eng.// International Organization for Standardization): 
 +  * ''​Clock''​ - un ceas ce oferă acces la momentul curent, dată, timp folosind o anumită zonă de timp; 
 +  * ''​Duration'' ​- o cantitate de timp; 
 +  * ''​Instant''​ - un punct specific din cadrul unei cronologii;​ 
 +  * ''​LocalDate''​ - o dată calendaristică fără zona de timp în sistemul de calendare definit de ISO-8601; 
 +  * ''​LocalDateTime''​ - o dată calendaristică și un moment de timp fără zona de timp în sistemul de calendare definit de ISO-8601; 
 +  * ''​LocalTime''​ - un moment de timp fără zona de timp în sistemul de calendare definit de ISO-860; 
 +  * ''​MonthDay''​ - o zi din cadrul unei luni în sistemul de calendare definit de ISO-8601; 
 +  * ''​OffsetDateTime''​ - o dată calendaristică și un moment de timp cu diferența de timp față de timpul Greenwich/UTC în sistemul de calendare definit de ISO-8601; 
 +  * ''​OffsetTime''​ - un moment de timp cu diferența de timp față de timpul Greenwich/​UTC în sistemul de calendare definit de ISO-8601; 
 +  * ''​Period''​ - o perioadă de timp bazată pe date calendaristice;​ 
 +  * ''​Year''​ - un an în sistemul de calendare definit de ISO-8601; 
 +  * ''​YearMonth''​ - un an-lună în sistemul de calendare definit de ISO-8601; 
 +  * ''​ZonedDateTime''​ - o dată calendaristică și un moment de timp cu zona de timp în sistemul de calendare definit de ISO-8601; 
 +  * ''​ZoneId''​ - identificatorul unei zone de timp; 
 +  * ''​ZoneOffset''​ - diferența de timp față de timpul Greenwich/​UTC.
  
-<note tip>O partiţie a sarcinii este considerată eşuată după ce au fost raportate erori pentru un anumit număr de încercări:​ ''​mapreduce.map.maxattempts''​ pentru sarcini de tip map şi ''​mapreduce.reduce.maxattempts''​ pentru sarcini de tip reduce. De asemenea, o sarcină în ansamblu ​ va fi marcată ca fiind eşuată în situaţia în care eşuează mai mult de un anumit procent de partiţii ale sale de tip map (indicat de ''​mapreduce.map.failures.maxpercent''​) sau un anumit procent de partiţii ale sale de tip reduce (indicat de ''​mapreduce.reduce.failures.maxpercent''​).</​note>​+=== PaginationControl ===
  
-**b)** Şi în cazul **aplicaţiilor care eşuează**, sunt realizate ​mai multe încercări. Acestea sunt detectate în situaţia în care procesul specific al aplicaţiei nu mai transmite mesaje periodice către procesul de gestiune a resurselor, situaţie în care va fi creată o nouă instanţă ​a procesului specific al aplicaţiei,​ însă într-un alt container, supervizat ​de un proces de gestiune a nodului. Partiţiile sarcinii care au fost deja rulate pot fi recuperate în acest caz, astfel că nu este necesară execuţia lor din nou. Întrucât clientul solicită procesului specific al aplicaţiei rapoarte cu privire la progresul înregistrat, în situaţia în care acesta eşuează şi nu mai transmite nici o informaţie,​ clientul va interoga procesul de gestiune al resurselor pentru a primi adresa noii instanţe a procesului specific al aplicaţiei (aşa cum îi fusese transmisă şi la iniţializarea sarcinii, când a fost transmisă).+Clasa ''​Pagination''​ oferă posibilitatea de a naviga între ​mai multe pagini corespunzând unui conţinut împărţit în mai multe secţiuni, fapt ce este util mai ales pentru dispozitivele mobile unde suprafaţa de afişare ​este limitată, iar interfaţa grafică nu poate fi de cele mai multe ori încadrată în aceasta.  
  
-<note tip>O aplicaţie este marcată ca fiind eşuată dacă se înregistrează erori o singură dată, însă această valoare poate fi modificată prin proprietatea ''​yarn.resourcemanager.am.max-retries''​.</​note>​+Controlul este format din conţinutul propriu-zis al paginii (redat în funcţie de logica aplicaţiei) şi din zona de navigare. În zona de navigare se găsesc butoane pentru deplasarea înainte ​şi înapoi, butoane pentru fiecare pagină în parte (cel selectat fiind corespunzător paginii curente). Totodată, pagina curentă este specificată şi printr-o etichetă având forma "​pagina curentă / număr total de pagini"​. Navigarea se face fie prin accesarea butoanelor înainte şi înapoi, fie prin accesarea butonului corespunzător paginii în cauză.
  
-<​note ​tip>​Recuperarea din eroare nu este activată în mod implicit ​(aceasta se face prin intermediul proprietăţii ''​yarn.app.mapreduce.am.job.recovery.enable''​), ​astfel că procesul ​specific ​al aplicaţiei va rula din nou toate partiţiile sarcinilor, indiferent ​de starea anterioară.</​note>​+Constructorul unui obiect de tip ''​Pagination''​ poate fi apelat şi fără parametri ​(caz in care numărul total de pagini are valoarea ​''​INDETERMINATE''​), ​poate primi 1 parametru indicând numărul total de pagini sau 2 parametri, indicându-se şi numărul paginii selectate. În cazul specificării unei pagini curente, numerotarea începe întotdeauna ​de la 0. Alternativ, pot fi folosite metodele ''​setPageCount()'',​ respectiv ''​setCurrentPageIndex()''​.
  
-**c)** Dacă se înregistrează **o eroare la nivelul procesului ​de gestiune a nodului**, acesta ​va înceta să mai transmită mesaje periodice către procesul ​de gestiune a resurselor, care îl va elimina din lista sa de noduri disponibile. Orice partiţie a sarcinii sau proces specific al aplicaţiei care rulează pe nodul marcat ca fiind eşuat vor fi recuperate. Procesele de gestiune a nodurilor pot fi incluse pe "lista neagră"​ în situaţia în care numărul de erori al aplicaţiilor rulate în contextul său este mare. Acestă operaţie este realizată de procesul specific al aplicaţiei (care va planifica partiţiile sarcinilor pe alte noduri) în cazul în care este depăşit un anumit prag minim de partiţii ale sarcinilor care înregistrează erori.+Nu se poate adăuga conţinut asociat unei pagini decât prin intermediul unei "​fabrici" ​de pagini, folosindu-se metoda ''​setPageFactory()''​ care va folosi o metodă de tip callback. Aceasta ​va fi apelată ​de fiecare dată când este selectată o pagină. În situația în care nu există indexul ​de pagină selectat, valoarea întoarsă trebuie să fie ''​null''​.
  
-<note tip>Proprietatea ''​yarn.resourcemanager.nm.liveness-monitor.expiry-interval-ms''​ (având implicit valoarea de 600000 milisecunde ​= 10 minute) determină perioada de timp (trecută de la ultimul mesaj periodic) pe care o aşteaptă procesul de gestiune a resurselor înainte de a considera procesul de gestiune a nodului ca fiind eşuat.</note>+<code java> 
 +int totalNumberOfPages = ...; 
 +int currentPageNumber ​= 0; 
 +Pagination pagination = new Pagination(totalNumberOfPage,​ currentPageNumber); 
 +Pagination.setPageFactory((Integer currentPage) -> { 
 +        // ... 
 +    } 
 +); 
 +</code>
  
-<note important>​Întrucât nu procesul ​de gestiune al resurselor este cel care realizează marcarea unui nod ca făcând parte din "lista neagră", este posibil ​ca partiţii ale noilor sarcini ​să fie planificate pe noduri ​care au fost marcate astfel ​de procesele specifice ale unor aplicaţii anterioare.</​note>​+Metoda ''​call()''​ generează un obiect ​de tip ''​Node'' ​care reprezintă conţinutul ce va fi ataşat paginii în cauză. Se recomandă ca în cadrul acestei metode ​să se verifice faptul că parametrul cu care se apelează nu depăşeşte numărul maxim de pagini.
  
-<note tip>​Implicit,​ un nod este inclus pe "lista neagră"​ dacă eşuează un număr mai mare de trei partiţii ale sarcinii rulate în contextul său, însă această valoare ​poate fi modificată prin intermediul proprietăţii ​''​mapreduce.job.maxtaskfailures.per.tracker''​.</​note>​+În condiţiile în care nu pot fi afişate în zona de navigare butoane corespunzând tuturor paginilor, se poate utiliza metoda ​''​setMaxPageIndicatorCount()'' ​care limitează dimensiunea numărului de legături vizibile către pagini.
  
-**d)** **Erorile produse la nivelul procesului de gestiune a resurselor** produc situaţii destul de delicate întrucât ​în absenţa acestuia nu pot fi lansate nici sarcini şi nici containere ale partiţiilor acestora. Totuşi, el a fost proiectat astfel încât ​să se poată realiza recuperarea din eroare prin utilizarea unui mecanism ce utilizează puncte ​de control, astfel încât starea sa este reţinută pe disc. După ce procesul de gestiune al resurselor ​se opreşte din cauza unei erori, o nouă instanţă va fi lansată de un administrator,​ aceasta putând relua execuţia prin intermediul stării încărcate de pe disc, conţinând procesele de gestiune ale nodurilor din sistem precum şi aplicaţiile ​care rulează.+Dacă se doreşte ca în locul numărului paginii respective ​să se afişeze alt tip de indicator, se poate schimba tipul clasei CSS corespunzătoare. Spre exemplu, în locul numerelor ​se pot folosi puncte, situaţie în care clasa CSS aferentă este ''​Pagination.STYLE_CLASS_BULLET''​.
  
-<note tip>​Mecanismul utilizat ​pentru ​stocarea pe disc de către procesul ​de gestiune a resurselor poate fi configurat prin proprietatea ​''​yarn.resourcemanager.store.class'' ​a cărei valoare implicită este ''​manager.recovery.MemStore'' ​(starea este reţinută în memorie astfel încât nu este disponibilă pentru procese din alte maşini virtuale), însă vor fi realizate şi implementări care vor folosi ZooKeeper pentru a realiza recuperarea din eroare în cazul problemelor întâmpinate ​la nivelul procesului de gestiune a resurselor.</​note>​+Alte atribute care pot fi precizate ​pentru ​a modifica stilul sunt: 
 +  * ''​-fx-max-page-indicator-count''​ – specifică numărul maxim de indicatori de pagină; 
 +  * ''​-fx-arrows-visible'' ​– indică vizibilitatea săgeţilor care fac legătura cu paginile anterioară şi următoare; în mod implicit, are valoarea ​''​true''​; 
 +  * ''​-fx-tooltip-visible''​ – precizează vizibilitatea informaţiei explicative asociate indicatorului de pagină; în mod implicit, are valoarea ''​true'';​ 
 +  * ''​-fx-page-information-visible''​ – setează vizibilitatea informaţiilor referitoare la pagină; în mod implicit, are valoarea ''​true'';​ 
 +  * ''​-fx-page-information-alignment''​ – reprezintă modul în care va fi aliniată secţiunea corespunzătoare informaţiilor cu privire ​la pagină.
  
-<​note>​De remarcat faptul că partiţiile sarcinii nu sunt reţinute în starea procesului de gestiune a resurselor, de vreme ce sunt gestionate de procesul specific al aplicaţiei. Ca atare, informaţiile reţinute pe disc (descriind starea procesului de gestiune a resurselor) au o dimensiune mai redusă putând fi gestionate cu uşurinţă decât în cazul procesului de monitorizare a partiţiei sarcinii din cadrul implementării MapReduce "​clasice"​.</​note> ​+=== FileChooser ===
  
-==== Politici ​pentru ​Planificarea Sarcinilor ====+Controlul ''​FileChooser''​ permite utilizatorilor să navigheze prin sistemul de fişiere. El poate fi folosit ​pentru ​deschiderea unuia sau mai multor fişiere, respectiv pentru salvarea pe disc a unor anumite conţinuturi.
  
-În privinţa planificării sarcinilor, iniţial Hadoop avea o abordare prin care sarcinile erau rulate ​în ordinea ​în care erau transmise de utilizatori, fiecare dintre acestea folosind întregul cluster. Utilizarea unui cluster partajat ar fi oferit oportunitatea folosirii unor resurse de dimensiuni mari pentru mai mulţi utilizatori,​ însă se punea problema distribuirii echitabile a acestora. Ulterior, s-a introdus posibilitatea specificării unei priorităţi pentru o sarcină astfel încât procesul ​de planificare a sarcinilor o va alege pe cea cu prioritatea cea mai mare cu toate că nu este implementat dreptul de preempţiune ​pentru ​ele. Astfel, în cazul mecanismului ​de planificare FIFO, o sarcină având o prioritate mai mare poate fi blocată de o sarcină cu prioritate inferioară ei, având o durată de execuţie semnificativă,​ în situaţia în care a fost pornită anterior.+Ulterior creării unui astfel de obiect (şi asocierii unui titlu sugestiv), acesta poate fi afişat ​în cadrul scenei respective în momentul ​în care este necesar, potrivit interacţiunii cu utilizatorul. Look and feel-ul acestui tip de control este corespunzător sistemului ​de operare ​pe care este apelat, ​pentru ​acele sisteme ​de operare ​care îl au implementat.
  
-<note tip>​Specificarea priorității unei sarcini putea fi realizată prin intermediul proprietăţii ''​mapred.job.priority''​ sau prin metoda ''​setJobPriority()''​ pe obiectul ''​JobClient''​ (specificând una din valorile ''​VERY_HIGH'',​ ''​HIGH'',​ ''​NORMAL'',​ ''​LOW''​ sau ''​VERY_LOW''​).</​note>+<columns 100% 50%>
  
-Curent, MapReduce implementează mai multe mecanisme de planificare. Implicit în MapReduce ​"clasic" ​este algoritmul bazat pe cozi de procese, însă există şi procese de planificare care să ruleze într-un mediu concurent, denumite mecanismul de planificare echitabilă (//eng.// Fair Scheduler) şi mecanismul folosind planificare pe bază de capacitate (//eng.// Capacity Scheduler).+<code java> 
 +FileChooser fileChooser = new FileChooser();​ 
 +fileChooser.setTitle("Open File"); 
 +// ... 
 +File file = fileChooser.showOpenDialog(stage); 
 +</code>
  
-Prin intermediul **mecanismului de planificare echitabilă** se doreşte să se dea fiecărui utilizator o şansă egală pentru a utiliza capacitatea clusterului de-a lungul timpului. ​+<​newcolumn>​
  
-<note tip>Utilizarea acestui mecanism de planificare se face prin plasarea ​.jar-ului corespunzător în directorul ''​lib''​ al Hadoop şi specificând pentru proprietatea ''​mapred.jobtracker.taskScheduler''​ valoarea ''​org.apache.hadoop.mapred.FairScheduler''​. Acesta va funcţiona fără alte configurări,​ însă acestea sunt disponibile inclusiv prin intermediul unei interfeţe web, pentru a utiliza toate facilităţile de care dispune.</note>+<code java> 
 +FileChooser fileChooser = new FileChooser();​ 
 +fileChooser.setTitle("​Open Files"​);​ 
 +// ... 
 +List<​File>​ fileList = fileChooser.showOpenMultipleDialog(stage);​ 
 +</code>
  
-În situaţia în care rulează o singură sarcină, acesteia îi va fi alocat întregul cluster. Pe măsură ce sunt transmise mai multe sarcini, sunt distribuite resurse pentru partiţiile acestora, astfel încât fiecare să aibă acces, în mod echitabil, la aceleaşi mijloace ca şi ceilalţi utilizatori. Astfel, o sarcină de dimensiuni mai mici va fi terminată într-un timp optim în timp ce concomitent este rulată o sarcină a cărei execuţie durează mai mult timp, aceasta înregistrând,​ la rândul ei, anumite progrese.+</​columns>​
  
-Sarcinile fac parte dintr-un anumit grup, în mod implicit fiecărui utilizator fiindu-i repartizat ​un astfel ​de grup. În acest fel, un utilizator ​care transmite mai multe sarcini decât altul nu va primi mai multe resurse în cadrul clusterului. Totodată, există posibilitatea de a crea anumite grupuri care să aibă garantat ​un număr minim de resurse ​(partiţii ale sarcinii ​de tip map sau de tip reduce care vor rula), stabilind ponderi pentru fiecare dintre acestea. Acest mecanism implementează dreptul de preemţiune, astfel încât ​în situaţia în care un grup nu şi-a primit resursele necesare pentru o perioadă ​de timp, procesul de planificare va termina partiţii ale sarcinilor din grupuri care şi-au depăşit capacitatea,​ pentru a oferi acces la resursele cuvenite grupului care a primit mai puţine resurse. De asemenea, în cadrul aceluiaşi grup, sarcinile transmise de fiecare utilizator vor partaja în mod echitabil resursele de care dispune acesta.+Obiectul de tip ''​FileChooser''​ poate fi configurat şi în privinţa directorului pe care îl deschide, prin apelarea metodei ''​setInitialDirectory()''​ care primeşte ca parametru ​un obiect ​de tip ''​File''​. În cazul în care se doreşte să se lase utilizatorului ​posibilitatea de a preciza directorul implicit, se poate folosi ​un obiect ''​DirectoryChooser'',​ iar rezultatul metodei ''​showDialog()'' ​(de tip ''​File''​) să fie pasat metodei ''​setInitialDirectory()''​ asociat obiectului ​de tip ''​FileChooser''​. Alternativ, se poate folosi directorul specific utilizatorului autentificat ​în cadrul sistemului ​de operare, obținut prin metoda: ''​System.getProperty("​user.home"​);''​.
  
-Abordarea din cazul **mecanismului folosind planificare pe bază de capacitate** utilizează un număr de cozi pentru fiecare cluster, fiecare având alocată ​o anumită capacitate. Prin această caracteristică,​ mecanismul folosind planificare pe bază de capacitate se deosebeşte de mecanismul de planificare echitabilă, permiţând ca pentru fiecare ​utilizator să se specifice ​o anumită pondere din totalul clusterului care va fi folosită exclusiv de acesta. Ele pot fi organizate în mod ierarhic, astfel încât între ele se stabilesc relaţii de tip părinte-copil,​ fiind asemănătoare grupurilor. Fiecare coadă este asociată unui utilizator şi implementează în cadrul său un mecanism de planificare de tip FIFO , folosind priorităţi. Astfel, ​se permite utilizatorilor ​să îşi simuleze propriul cluster de tip MapReduce, în care aplicaţiile pe care le transmit vor fi executate în ordinea specificată ​şi în funcţie de priorităţile indicate. +Metoda ''​showOpenDialog()''​ întoarce ​o valoare care specifică fişierul care a fost selectat ​de către utilizator ​sau ''​null''​ în cazul în care nu s-a realizat nici o selecţie. Această metodă este folosită în situaţia în care se doreşte ​să se poată selecta un singur ​fişier. 
  
-<​note>​Şi mecanismul de planificare echitabilă implementează posibilitatea ca în cadrul unui grup, sarcinile să fie planificare în funcţie de ordinea ​în care sunt transmise ​de către un utilizator, asemănându-se astfel cu mecanismul folosind planificare pe bază de capacitate.</​note>​+Metoda ''​showOpenMultipleDialog()''​ este utilizată în condițiile ​în care se dorește selectarea mai multor fișiere concomitent;​ aceasta va întoarce o listă ​ a fişierelor care au fost selectate ​de utilizator ​sau ''​null''​ dacă nu s-a realizat nici o selecţie. 
  
-===== Sistemul Distribuit de Fișiere HDFS =====+Metodele ''​showOpenDialog()'' ​și ''​showOpenMultipleDialog()''​ sunt blocante şi nu întorc nici un rezultat până când utilizatorul nu furnizează un răspuns. ​
  
-[[:​laboratoare:​laborator10a|Sistemul Distribuit de Fișiere HDFS]]+Vizualizarea conţinutului unui fişier (folosind aplicaţia asociată în mod implicit) se face prin clasa ''​java.awt.Desktop''​ care pune la dispoziţie metoda ''​open()''​.
  
-===== Sistemul ​de Gestiune pentru Baze de Date Distribuite HBase =====+<note important>​Înainte ​de a folosi funcţionalităţile puse la dispoziţie ​de această clasă trebuie să se verifice dacă platforma pe care se rulează le suportă. În acest sens, se poate folosi metoda statică ''​isDesktopSupported()''​.</​note>​
  
-[[:​laboratoare:​laborator10b|Sistemul ​de Gestiune ​pentru ​Baze de Date Distribuite HBase]]+<note tip>Alte metode implementate ​de clasa ''​Desktop''​ sunt ''​browse()''​ (pentru ​a deschide navigatorul implicit folosind o adresă dată ca parametru), ''​edit()''​ (pentru editarea conţinutului unui fişier), ''​mail()''​ (pentru transmiterea unui mesaj electronic către o adresă specificată în câmpul ''​mailto''​) şi ''​print()''​ (care tipăreşte la imprimanta implicită un fişier).</​note>​
  
-===== API-ul Java pentru dezvoltarea ​de aplicaţii distribuite folosind framework-ul Hadoop =====+Unui astfel ​de obiect i se pot aplica ​filtre cu privire la tipul fişierelor care vor fi afişate. Aceasta se face adăugând obiecte de tip ''​ExtensionFilter''​ extensiilor deja existente la obiectul de tip ''​FileChooser''​ (lista acestora putând fi obţinută prin metoda ''​getExtensionFilters()''​). Constructorul clasei ''​ExtensionFilter''​ primeşte ca parametri un şir de caractere sugestiv pentru tipul de fişiere respectiv şi o listă de extensii în formatul ''​*.ext''​ (de exemplu ''​*.*'',​ ''​*.docx'',​ ''​*.pdf'',​ ''​*.jpg'',​ ''​*.png''​).
  
-Dezvoltarea unei aplicaţii MapReduce folosind Hadoop presupune configurarea unui obiect de tip ''​Job'' ​(prin specificarea formatului pe care îl au datele de intrare şi datele de ieşire şi prin indicarea claselor care implementează sarcinile de tip Map, respectiv Reduce - opţional, se poate specifica şi o clasă de tip Combiner), prin implementarea claselor care realizează funcţionalitatea claselor de tip Map, respectiv Reduce urmată de lansarea în execuţie a aplicaţiei.+<code java> 
 +FileChooser fileChooser = new FileChooser(); 
 +fileChooser.setTile("​File Chooser"​);​ 
 +fileChooser.setInitialDirectory(new File(System.getProperty("​user.home"​)));​ 
 +FileChooser.ExtensionFilter allFiles = new FileChooser.ExtensionFilter("​All Files", "​*.*"​);​ 
 +FileChooser.ExtensionFilter documents = new FileChooser.ExtensionFilter("​Documents"​, "​*.docx",​ "​*.pdf"​); 
 +FileChooser.ExtensionFilter images = new FileChooser.ExtensionFilter("​Images"​, "​*.jpg"​, "*.png"​);​ 
 +fileChooser.getExtensionFilters().addAll(allFiles,​ documents, images); 
 +</​code>​
  
-Clasa ''​Job'' ​înglobează toate informaţiile despre ​o sarcină, controlând totodată execuţia acesteia.+Dacă se doreşte salvarea unui conţinut sub forma unui fişier pe disc, obiectul de tip ''​FileChooser'' ​trebuie apelat cu metoda ''​showSaveDialog()''​. Acesta întoarce tot un obiect de tip ''​File''​ care poate fi folosit la scrierea unui conţinut. 
 + 
 +=== Controale Definite de Utilizator === 
 + 
 +În situaţia în care un control predefinit nu corespunde necesităţilor, se pot crea controale definite de utilizator ce extind clasa ''​javafx.scene.control.Control''​. 
 + 
 +De asemenea, comportamentul implicit al unor controale predefinite poate fi suprascris (chiar la creearea acestora) redefinind metodele al căror mod de operare nu corespunde cerinţelor.  
 + 
 +Pentru obiectele ''​TableView'',​ ''​ListView'',​ ''​TreeView'',​ ''​ComboBox''​ se pot defini "​fabrici"​ de celule pentru generarea de conținut având ​o anumită funcționalitate. În acest sens, se folosește metoda ''​setCellFactory()''​ ce primește ca parametru un obiect de tip ''​Callback''​ pentru care se suprascrie metoda ''​call()'',​ întorcând controalele grafice dorite. 
 + 
 +=== Compatibilitatea JavaFX cu Dispozitive Mobile === 
 + 
 +Pentru dispozitivele mobile, JavaFX implementează operații specifice:​ 
 +  * apăsare (doar pentru ecran tactil, o singură apăsare la un moment dat); 
 +  * gesturi (atât pentru ecran tactil cât și pentru trackpad, doar glisare). 
 + 
 +De asemenea, poate fi utilizată o tastatură virtuală de fiecare dată când obiectul curent conține un câmp pentru introducerea de text. Formatul acesteia poate fi particularizat prin intermediul proprietății ''​vkType''​ care poate lua valorile ''​numeric'',​ ''​url'',​ ''​email''​ sau ''​text''​ (implicit). 
 + 
 +Unele elemente grafice au un comportament modificat pentru dispozitivele mobile: 
 +  * ''​ScrollBar'',​ ''​ScrollPane''​ - elementele derulante nu sunt afișate dacă utilizatorul nu interacționează cu controlul respectiv; schimbarea porțiunii vizibile se face ca urmare a gesturilor de apăsare iar elementele derulante au doar rolul de a indica poziția curentă; 
 +  * ''​TextField'',​ ''​PasswordField'',​ ''​TextArea'',​ ''​DatePicker''​ - este vizualizat cursorul; 
 +  * ''​ContextMenu''​ - meniul contextual este dispus orizontal. 
 + 
 +^  **Control** ​ ^  **Acțiunea Utilizatorului** ​ ^  **Comportament** ​ ^ 
 +| ''​Button'',​\\ ''​Hyperlink'',​\\ ''​MenuButton'',​\\ ''​ToggleButton''​ | atingere | activează butonul | 
 +| ''​CheckBox''​ | atingere (//eng.// tap) | comută între stările selectat / deselectat | 
 +| ''​ComboBox''​ | atingere pictogramă | afișează sau ascunde lista activă; elementul afișat în câmpul text este selectat când lista activă este vizibilă | 
 +| ::: | atingere câmp text | ♦ controale non-editabile:​ afișează lista activă | 
 +| ::: | ::: | ♦ controale editabile: plasează cursorul în câmpul text | 
 +| ::: | atingere element din cadrul listei | închide lista activă și salvează valoarea sa | 
 +| ::: | atingere element din afara listei | închide lista | 
 +| ::: | tragere (//eng.// drag) | pornește defilarea conținutului | 
 +| ::: | plasare (//eng.// drop) | oprește defilarea conținutului | 
 +| ::: | glisare (//eng.// swipe) | defilare rapidă a conținutului | 
 +| ''​ListView''​ | tragere | pornește defilarea conținutului | 
 +| ::: | plasare | oprește defilarea conținutului | 
 +| ::: | glisare | defilare rapidă a conținutului | 
 +| ::: | atingere | selectează un element și activează acțiunea asociată acestuia (oprește defilarea conținutului,​ dacă este cazul) | 
 +| ::: | dublă atingere | dacă este activat, intră în modul de editare | 
 +| ''​TextField'',​\\ ''​PasswordField'',​\\ ''​TextArea''​ | atingere | poziționează cursorul | 
 +| ::: | dublă atingere | selectează conținutul | 
 +| ::: | atingere și așteptare | deschidere meniul contextual | 
 +| ::: | glisare ​ | defilarea rapidă a conținutului | 
 +| ::: | tragere | pornește defilarea conținutului | 
 +| ::: | plasare | oprește defilarea conținutului;​ dacă se depășesc limitele controlului,​ conținutul va fi deselectat iar cursorul plasat în cadrul elementului grafic | 
 +| ''​RadioButton''​ | atingere | dacă controlul este selectat, nu se realizează nici o acțiune\\ dacă controlul nu este selectat, îl selectează,​ deselectând celelalte elemente din cadrul grupului | 
 +| ''​ScrollBar'',​\\ ''​ScrollView''​ | tragere | pornește defilarea conținutului | 
 +| ::: | plasare | oprește defilarea conținutului | 
 +| ::: | glisare | defilarea rapidă a conținutului | 
 +| ::: | atingere | selectează un element și activează acțiunea asociată acestuia (oprește defilarea conținutului,​ dacă este cazul) | 
 +| ''​TableView'',​\\ ''​TreeView''​ | atingere | ''​TableView''​ - selectează celula sau invocă acțiunea asociată ​acesteia ​(dacă este cazul);\\ ''​TreeView''​ - expandează sau pliază nodul | 
 +| ::: | dublă atingere | intră în modul de editare dacă această operație este suportată de celula respectivă ​ | 
 +| ::: | tragere | pornește defilarea conținutului | 
 +| ::: | plasare | oprește defilarea conținutului | 
 +| ::: | glisare | defilarea rapidă a conținutului | 
 +| ''​ColorPicker''​ | atingere scurtă în câmpul de culori sau a culorilor definite de utilizator în paleta de culori | actualizează culoarea în câmpul de culori; închide paleta de culori; aplică culoarea | 
 +| ::: | atingere în afara paletei de culori ​ | închide paleta de culori | 
 +| ::: | atingere în orice punct în câmpul de culori sau în fereastra pentru definirea de culori | actualizează valorile în panourile RGB / HSB / Web; actualizează noua culoare în zona de previzualizare a culori | 
 +| ::: | atingerea în orice punct din panoul pentru specificarea culorii în fereastra pentru definirea de culori | actualizează valorile în panourile RGB / HSB / Web; actualizează noua culoare în fereastra pentru definirea de culori | 
 +| ::: | atingerea în orice punct din cadrul pistei de derulare\\ tragerea cursorului de derulare spre stânga sau dreapta | închide fereastra de dialog; închide paleta de culori; actualizează culoarea în câmpul de culori; aplică culoarea | 
 +| ''​Pagination''​ | atingerea unui buton corespunzător paginii | deschide pagina selectată | 
 +| ::: | atingerea butonului următor\\ glisare la stânga | deschide pagina următoare | 
 +| ::: | atingerea butonului anterior\\ glisare la dreapta | deschide pagina anterioară | 
 +| ''​DatePicker''​ | atingerea câmpului corespunzător datei calendaristice | afișează cursorul în cadul câmpului; afișează tastatura virtuală | 
 +| ::: | atingerea pictogramei corespunzătoare calendarului | afișează / ascunde calendarul | 
 +| ::: | atingerea săgeților stânga / dreapta din cadrul calendarului | afișează luna / anul anterior / următor | 
 +| ::: | atingerea oricărei date calendaristice din cadrul calendarului | actualizează câmpul cu data selectată și închide calendarul | 
 +| ::: | atingerea oricărui punct în afara calendarului | închide calendarul fără a actualiza câmpul | 
 + 
 +Pe dispozitivele mobile nu este posibilă:​ 
 +  * redimensionarea / rearanjarea coloanelor și nici ordonarea datelor dintr-un tabel; 
 +  * selecția multiplă în liste sau arbori; 
 +  * suport pentru copierea textului în câmpuri pentru introducerea parolelor. 
 + 
 +Totodată, unele funcționalități ale clasei ''​Stage''​ (specificarea unui titlu, redimensionarea,​ posibilitatea de particularizare),​ navigatorul pentru pagini Internet și redarea de conținut multimedia folosind JavaFX nu sunt implementate pentru dispozitivele mobile. 
 + 
 +==== Gestiunea Meniurilor ==== 
 + 
 +Un meniu este o listă de elemente acționabile care sunt făcute vizibile la solicitarea utilizatorului. La un moment dat, se poate selecta un singur element din cadrul unui meniu, ulterior acestei acțiuni meniul devenind din nou invizibil. 
 + 
 +<​note>​Utilizând meniuri, se optimizează spațiu în interfața cu utilizatorul întrucât acestea conțin funcționalități care nu sunt afișate tot timpul.</​note>​ 
 + 
 +În JavaFX pot fi definite mai multe tipuri de meniuri: 
 +  * ''​MenuBar''​ - meniul principal al unei aplicații 
 +  * ''​MenuItem''​ - pentru asocierea unei acțiuni 
 +    * ''​Menu''​ - pentru implementarea unui submeniu 
 +    * ''​CheckMenuItem''​ - pentru elemente a căror stare are o valoare binară 
 +    * ''​RadioMenuItem''​ - pentru selecţii mutual exclusive 
 +    * ''​CustomMenuItem''​ - pentru tipuri de meniu definite de utilizator 
 +      * ''​SeparatorMenuItem''​ - pentru separarea intrărilor din cadrul unui meniu 
 +  * ''​ContextMenu''​ - pentru meniuri asociate unor controale grafice 
 + 
 +De regulă, se construieşte un obiect ''​MenuBar'',​ se definesc categoriile acestuia care sunt populate cu elemente de tip ''​Menu'',​ fiecare dintre acestea conținând intrări de tip ''​MenuItem''​ (sau subtipurile acestuia) corespunzând unei opţiuni acţionabile.  
 + 
 +Frecvent, obiectul de tip ''​MenuBar''​ ocupă partea de sus a scenei, fiind redimensionat la spaţiul disponibil. Constructorul clasei ''​MenuBar''​ nu primește nici un parametru. Asocierea categoriilor din cadrul acestui tip de meniu se face prin metodele ''​add()''​ / ''​addAll()''​ apelabile pe lista observabilă de meniuri, întoarsă de metoda ''​getMenus()''​.
  
 <code java> <code java>
-Job job = Job.getInstance(getConf(), "JobName");+MenuBar containerMenu ​= new MenuBar(); 
 +Menu fileMenu = new Menu("​File"​); 
 +Menu operationsMenu = new Menu("Operations"); 
 +Menu helpMenu = new Menu("​Help"​);​ 
 +containerMenu.getMenus().addAll(fileMenu,​ operationsMenu,​ helpMenu);
 </​code>​ </​code>​
  
-O sarcină este împachetată în cadrul unei arhive ​''​.jar''​ care este distribuită în mod automat de sistemul Hadoop. Pentru ​a şti care este sarcina ​de transmis, trebuie apelată metoda ''​setJarByClass()'', ​primind ​ca argument chiar arhiva ​''​.jar'' ​în care se găseşte sarcina curentă. Sistemul Hadoop ​ va localiza prin aceasta ​fişierul care conţine clasa indicată.+Un obiect de tip ''​MenuItem''​ poate avea asociat un text și o pictogramă, specificate ​în momentul în care acesta este construit. Pentru acest tip de obiect se va preciza o acțiune, prin intermediul metodei ​''​setOnAction()'' ​ce primește ca parametru un obiect de tip ''​EventHandler<​ActionEvent>''​ pentru ​care se implementează metoda ''​handle()''​. Apartenența sa la un obiect ​de tip ''​Menu''​ se face prin metodele ''​add()''​ / ''​addAll()''​ apelabile pe lista observabilă de intrări ale acestuia, întoarsă de metoda ''​getItems()''​. 
 + 
 +Pentru un obiect ''​MenuItem'', ​se poate asocia o combinaţie de taste având acelaşi efect ca şi accesarea propriu-zisă a acestuia (folosind mouse-ul), apelând metoda ​''​setAccelerator()''​ care primește un parametru obţinut din metoda statică ''​keyCombination()''​ a clasei omonime (combinaţia are forma "Ctrl+...", "​Alt+...",​ "​Shift+..."​).  
 + 
 +O intrare de tipul ''​MenuItem''​ a unui meniu poate fi dezactivată printr-un apel al metodei ''​setDisable()''​. O intrare dezactivată a unui meniu este continuare vizibilă, fără ca utilizatorul să aibă posibilitatea de a o selecta.
  
 <code java> <code java>
-job.setJarByClass(getClass());+Menu operationsMenu = new Menu("​Operations"​);​ 
 +MenuItem databaseManagementMenu = new MenuItem("​DataBase Management"​);​ 
 +databaseManagementMenu.setAccelerator(KeyCombination.keyCombination("​Ctrl+D"​)); 
 +operationsMenu.getItems().addAll(databaseManagementMenu);
 </​code>​ </​code>​
  
-În continuare, trebuie specificat formatul datelor ​de intrare respectiv al datelor de ieşire, acestea putând ​fi fişiere, directoare, texte sau tabele dintr-o bază de date.+<note tip>​Obiectele ​de tip ''​MenuItem''​ nu extind clasa ''​Node''​, astfel încât nu pot fi incluse direct în scena aplicației și nici nu sunt vizibile până când nu sunt asociate unui obiect ​de tip ''​MenuBar''​.</​note>​
  
-Datele ​de intrare sunt indicate ​de o implementare a clasei ​''​InputFormat'', ​responsabilă de crearea partiţiilor şi a sistemului de preluare ​a înregistrărilor.+Obiectele ''​CheckMenuItem''​ pot avea starea selectat / deselectat, valoare accesibilă din proprietatea ''​selectedProperty()''​ (pentru care se și specifică metoda ​de tip ascultător ce monitorizează schimbările ​de la acest obiect) și prin intermediul metodelor ​''​{get|set}Selected()''​. Dacă este selectată, intrarea dintr-un astfel de meniu este însoțită de simbolul ✔, dacă este deselectată,​ se afișează doar textul / imaginea asociate. 
 + 
 +Obiectele ''​RadioMenuItem''​ sunt de obicei asociate unui obiect ''​ToggleGroup''​ (prin metoda ''​setToggleGroup()''​) care implică selecţia lor mutual exclusivă. Elementul selectat în mod curent poate fi gestionat prin metodele ''​{get|set}SelectedToggle()''​. Tratarea evenimentelor ce vizează modificarea selecției la nivelul grupului de obiecte ''​RadioMenuItem''​ se face prin asocierea unei metode ascultător pentru proprietatea ''​selectedToggleProperty()''​. 
 + 
 +Dacă spaţiul de afișare nu permite utilizarea unor meniuri de tip ''​MenuBar''​ / ''​MenuItem'' ​ se pot folosi meniuri contextuale (''​ContextMenu''​),​ atașabile oricărui tip de control JavaFX. Acestea devin vizibile atunci când este apelată metoda ''​show()''​ asociată de regulă la accesarea unui control (printr-un click de mouse) căruia ​i-a fost asociat meniul. Afişarea meniului contextual se face la coordonatele la care a fost înregistrat click-ul pe mouse (acestea fiind obținute prin apelul metodelor ''​getScreenX()''​ / ''​getScreenY()''​ pe evenimentul generat).  
 + 
 +Obiectele ''​CustomMenuItem''​ sunt folosite atunci când intrările meniului utilizează alte tipuri de controale, derivate din clasa ''​Node''​. 
 + 
 +=== Exemplu === 
 + 
 +În cadrul unui fișier FXML se definesc un meniu principal (obiect ''​MenuBar''​ denumit ''​containerMenu''​) și o categorie / submeniu (obiect de tip ''​Menu''​ denumit ''​databaseManagementMenu''​). 
 + 
 +Pe baza denumirii tabelelor dintr-o bază de date se construiesc intrări în cadrul meniului (obiecte de tip ''​MenuItem''​),​ ale căror evenimente vor fi tratate în cadrul aceleiași clase, asociate ulterior categoriei / submeniului.
  
 <code java> <code java>
-job.setInputFormatClass(CustomInputFormat.class);+@FXML private MenuBar ​   containerMenu;​ 
 +@FXML private Menu databaseManagementMenu;​ 
 + 
 +// ... 
 + 
 +@FXML 
 +private void initialize() { 
 +    try { 
 +        DataBaseWrapper databaseWrapper = DataBaseWrapperImplementation.getInstance(); 
 + ArrayList<​String>​ tableNames = databaseWrapper.getTableNames();​ 
 +        for (String tableName: tableNames) { 
 +            MenuItem menuItem = new MenuItem(Utilities.tableNameToMenuEntry(tableName));​ 
 +            menuItem.addEventHandler(EventType.ROOT,​ (EventHandler<​Event>​)this);​ 
 +            databaseManagementMenu.getItems().add(menuItem);​ 
 +        } 
 +    } catch (SQLException sqlException) { 
 +        System.out.println("​An exception has occured: "​+sqlException.getMessage());​ 
 +  if (Constants.DEBUG) 
 +      ​sqlException.printStackTrace();​ 
 +    } 
 +    // ... 
 +}
 </​code>​ </​code>​
  
-<note tip>În cazul în care datele de intrare nu respectă formatul nici uneia dintre clasele care implementează interfaţa ''​InputFormat'',​ va fi specificată o clasă definită de utilizator care defineşte metoda ''​createRecordReader(InputSplit,​ TaskAttemptContext)''​ întorcând obiectul (derivat din clasa ''​RecordReader''​) care gestionează preluarea înregistrărilor din sursa respectivă.</​note>​+{{ :​laboratoare:​laborator09:​06menus.png?nolink }}
  
-După ce sunt preluate înregistrările din sursa de date, acestea sunt partiţionate şi fiecare secvenţă este transmisă unui proces de tip Mapper spre a fi prelucrată în continuare.+==== Diagrame ====
  
-Hadoop foloseşte propriul mecanism de serializare pentru transmiterea datelor prin infrastructura de comunicaţie, fiind optimizat pentru cazul reţelelor ​de calculatoare. Serializarea este folosită pentru interacțiunea cu fișiere și cu baze de date. În pachetul ​''​org.apache.hadoop.io''​ sunt definite clasele ​''​IntWritable'' ​(pentru ​''​Integer''​), ''​Text''​ (pentru ​''​String''​) ​şi altele, însă implementarea propriilor clase pentru tipuri ​de date serializabile este destul de facilă.+În JavaFX pot fi utilizate ​şi grafice, definite ​de pachetul ''​javafx.scene.chart'',​ fiind suportate următoarele tipuri: 
 +  * ''​PieChart''​ - diagramă în care datele sunt reprezentate sub forma unui cerc împărțit în secțiuni triunghiulare (arce de cerc) denumite felii; 
 +  * ''​LineChart'' ​- diagramă definită pe baza a două axe de coordonate în care datele ​sunt prezentate sub forma unei serii de puncte conectate prin linii drepte; 
 +  * ''​AreaChart'' ​- diagramă în care datele sunt reprezentate sub forma unor suprafețe între o serie de puncte conectate cu axele de coordonate prin linii drepte; 
 +  * ''​BubbleChart'' ​- diagramă definită pe baza a două axe de coordonate în care datele sunt prezentate sub formă de baloane; 
 +  * ''​ScatterChart''​ - diagramă în care datele sunt prezentate sub forma unei mulțimi de puncte; 
 +  * ''​BarChart''​ (cu varianta ​''​StackedBarChart''​) ​- diagramă definită pe baza a două axe de coordonate în care datele sunt prezentate sub forma unor dreptunghiuri.
  
-Datele ​de ieşire sunt specificate ​de o implementare a clasei ​''​OutputFormat'', ​indicându-se ​şi locaţia la care sarcinile ​de tip reduce îşi vor plasa rezultatele.  ​Fiecare sarcină de tip reduce dispune ​de propriile ​date de ieşire, de tip text, sub forma unor perechi ​(cheie, valoare). +În momentul în care se defineşte un model pentru un anumit tip de diagramă, trebuie să se distingă între acele tipuri de tabele care folosesc axele de coordonate ​şi cele care nu le utilizează. 
 + 
 +Proprietăţile comune tuturor tipurilor ​de grafice sunt titlul (''​setTitle()''​), poziţia sa (sus, jos, stânga, dreapta), vizibilitatea etichetelor (''​setLabelsVisible()''​),​ vizibilitatea (''​setLegendVisible()''​) ​şi poziţia (''​setLegendSide()''​ / ''​setLabelLineLength()''​) legendei. 
 + 
 +=== Tipuri de Diagrame ce nu folosesc sistemul de coordonate === 
 + 
 +Graficele ​care nu folosesc sistemul ​de coordonate (pie), derivate din clasa ''​PieChart'',​ folosesc ''​PieChart.Data''​ pentru a indica valorile fiecărei secţiuni. În acest tip de grafic, datele sunt afişate în ordinea acelor de ceasornic (modul de afişare putând fi schimbat prin metoda ''​setClockwise()''​) ​şi au un anumit unghi de pornire (ce poate fi modificat prin metoda ''​setStartAngle()''​). 
 + 
 +Constructorul clasei ''​PieChart''​ primește ca parametru o listă observabilă de obiecte ​de tip ''​PieChart.Data'',​ definite sub forma unor asocieri între o etichetă (de tip șir de caractere) - denumirea categoriei respective și o valoare numerică. 
 + 
 +=== Tipuri de Diagrame ce folosesc sistemul de coordonate === 
 + 
 +Graficele ce utilizează sistemul de coordonate (de tipul line, area, bubble, scatter, bar) sunt derivate din clasa ''​XYChart'',​ modelul ​de date fiind specificat ​de clasa ''​XYChart.Data''​. Valorile aferente axelor de coordonate sunt reprezentate de proprietăţile ''​xValue''​, respectiv ''​yValue''​. De asemenea, pentru fiecare element al graficului se pot specifica valori suplimentare (proprietatea ''​extraValue''​). Acestea sunt specificate ca parametri în constructorul obiectului ​de tip ''​XYChart.Data''​. 
 + 
 +Constructorul unei diagrame ce folosește sistemul de coordonate primește ca parametrii cele două axe (obiecte de tipul ''​Axis'':​ ''​NumberAxis''​ sau ''​CategoryAxis''​). 
 + 
 +Pentru aceste tipuri de grafice pot fi definite mai multe serii de date, folosind clasa ''​XYChart.Series''​. Fiecare serie de date poate avea un nume (indicată prin metoda ''​setName()''​), iar valorile sunt adăugate prin metoda ''​add()''​ apelabilă pe rezultatul metodei ''​XYChart.Series.getData()'',​ acestea având tipul ''​XYChart.Data''​.  
 + 
 +Pentru fiecare axă poate fi specificată eticheta (prin metoda ''​setLabel()''​),​ poziţia relativă faţă de grafic (apelând metoda ''​setSide()''​ pentru obiectul de tip ''​NumberAxis''​ / ''​CategoryAxis''​),​ limitele inferioară şi superioară (''​setLowerBound()''​ / ''​setUpperBound()''​),​ distanţa dintre marcaje (''​setTickUnit()''​),​ valorile între care vor fi poziţionate (''​setTickLabelGap()''​),​ culoarea etichetelor (''​setTickLabelFill()''​),​ distanța între categorii (''​setCategoryGap()''​). 
 + 
 +Este posibilă și rotirea axelor de coordonate, astfel încât interpretarea valorilor reprezentate în cadrul diagramelor să se realizeze mai ușor: metoda ''​setTickLabelRotation()''​ primește ca parametru valoarea unghiului (exprimată în grade) cu care să se facă repoziționarea.  
 + 
 +Totodată, axele îşi pot determina unele proprietăţi din datele care le sunt asociate. În momentul în care sunt modificate proprietăţile axelor de coordonate sau din cadrul graficului se poate specifica faptul că operaţia să se realizeze în mod animat, printr-un apel al metodei ''​setAnimated()''​.  
 + 
 +Dacă datele conţinute în tabel sunt de tip numeric, axele cu care se crează acesta au tipul ''​NumberAxis'',​ altfel se va folosi ''​CategoryAxis''​. 
  
 <code java> <code java>
-job.setOutputFormatClass(CustomOutputFormat.class);+CategoryAxis xAxis = new CategoryAxis();​ 
 +NumberAxis yAxis = new NumberAxis();​ 
 +yAxis.setTickLabelFormatter(new NumberAxis.DefaultFormatter(yAxis,​ "RON ", null)); 
 +LineChart<​String,​ Number> lineChart = new LineChar<​String,​ Number>​(xAxis,​ yAxis); 
 +lineChart.setTitle("​Profit Statistics"​);​ 
 +XYChart.Series series2015 = new XYChart.Series();​ 
 +series2015.setName("​Year 2015"​);​ 
 +series2015.getData().add(new XYChart.Data("​January",​ ...)); 
 +// ... 
 +lineChart.getData.add(series2015);
 </​code>​ </​code>​
  
-<note important>​Locaţia la care vor fi plasate datele de ieşire trebuie să nu existe, în caz contrar generându-se ​ o excepţie care determină eşuarea globală a sarcinii.</​note>​+==== ====
  
-<note tip>În mod implicit, este definit un singur proces ​de tip reduce.</​note>​+Un element al unui grafic poate avea asociată o metodă de tratare în cazul producerii unor evenimente, aceasta realizându-se similar ca pentru orice obiect din clasa ''​Node''​. Metodele ​de tratare trebuie adăugate pentru fiecare nod în parte, obţinut prin iterare pe rezultatul metodei ''​chart.getData()''​.
  
-Pentru fiecare sarcină trebuie specificat formatul pentru cheia şi valoarea datelor de ieşire, ​pentru ​procesele ​de tip map cât şi pentru procesele ​de tip reduce. Sunt folosite în acest scop metodele ​''​setMapOutputKeyClass()''​ şi ''​setMapOutputValueClass()''​, care pot primi ca parametrii ​tipuri predefinite ​de date sau tipuri de date definite de utilizator.+Şi pentru ​o diagramă poate fi schimbat modul de vizualizare prin asocierea unei foi de stil sau a unei clase CSS. Proprietăţile CSS corespunzătoare sunt prefixate de regula de ''​.default-colorx'' ​(cu x valoare numerică) ​şi pot avea valorile: 
 +  * ''​chart-area-symbol'' ​- parametrii ​simbolurilor din legenda diagramei pentru un set de date; 
 +  * ''​chart-series-area-line''​ - parametrii liniilor drepte; 
 +  * ''​chart-series-area-fill''​ - parametrii suprafețelor;​ 
 +  * ''​chart-symbol''​ - simbolul folosit pentru reprezentarea unei valori.
  
-În cazul în care datele de intrare sau datele de ieşire au tipurile ''​TextInputFormat''​ respectiv ''​TextOutputFormat'',​ locaţia ​de la care pot fi preluate informaţiile va fi indicată prin metodele ​''​FileInputFormat.setInputPaths()''​, respectiv ''​FileOutputFormat.setOutputPath()''​ care vor primi ca parametru obiectul de tip ''​Job'' ​şi un obiect de tip ''​Path''​ care conţine calea din sistemul de fişiere local sau din cadrul sistemului distribuit de fişiere HDFS.+Utilizatorul îşi poate defini propriul tip de tabel (care extinde clasa ''​Chart''​) şi suprascriind metodele definite în această clasă.
  
-Ulterior, trebuie indicate clasele ​de tip Mapper ​şi Reducer ​(având ​de regulă aceeaşi cheie pentru datele ​de ieşire):+==== Elemente de tip Text ==== 
 + 
 +În aplicaţiile JavaFX componentele text pot fi create ca instanţe ale clasei ''​javafx.scene.text.Text''​ (derivată din clasa ''​Node''​). 
 + 
 +Astfel, se pot aplica efecte sau transformări şi se pot crea animaţii folosind obiectul text respectiv. De asemenea, având în vedere că ''​Node''​ extinde ''​Shape'',​ se poate specifica şi o culoare pentru fundalul textului, respectiv se poate aplica un efect de îngroşare pentru forma asociată lui. 
 + 
 +Constructorul unui obiect ​de tip ''​Text''​ poate primi (sau nu) textul respectiv, precum ​şi poziţia unde se doreşte a fi afişat. Pentru aceste obiecte se pot utiliza şi metodele ''​setText()'',​ ''​setFont()''​ şi ''​setColor()''​.  
 + 
 +=== === 
 + 
 +Parametrul metodei ''​setFont()''​ se obţine prin metoda statică ''​font()''​ a clasei cu acelaşi nume, specificându-se numele tipului ​de caractere (ca ''​String''​) şi dimensiunea acestuia. Se poate specifica utilizarea setului de caractere implicit, diferit de la o platformă la alta, acesta putând fi obținut print-un apel al metodei ''​Font.getDefault()''​. Se pot utiliza ​şi tipuri ​de caractere definite de utilizator (conţinute în fişiere de tip ''​.ttf''​ sau ''​.otf''​ aflate în directorul proiectului), acestea putând fi încărcate prin metoda ''​loadFont()''​. 
 + 
 +De asemenea, proprietăţile de tip bold / italic pot fi specificate ca parametri ai aceleiaşi metode, utilizându-se constantele ''​FontWeight.BOLD''​ respectiv ''​FontPosture.ITALIC''​. 
 + 
 +==== ====
  
 <code java> <code java>
-job.setMapperClass(MyMapper.class); +Text text = new Text(); 
-job.setReducerClass(MyReducer.class);+text.setText("​Sample Text"​);​ 
 +text.setFont(Font.getDefault(),​FontWeight.BOLD|FontPosture.ITALIC,​24);​ 
 +text.setFontSmoothingType(FontSmoothingType.LCD); 
 +text.setFill(Color.BEIGE);
 </​code>​ </​code>​
  
-În continuare, sarcina este lansată în execuţie ​prin apelarea metodei ​''​waitForCompletion()'' ​ce primeşte un parametru ​care indică dacă sunt afişate valori la consolă. Metoda transmite sarcina, aşteptând terminarea acesteia. Rezultatul pe care îl întoarce este ''​true''​ în caz că sarcina a fost terminată cu succes şi ''​false'' ​în caz contrar.+Gruparea mai multor obiecte de tip ''​Text''​ se poate face prin intermediul clasei ​''​TextFlow''​ care ignoră coordonatele elementelor pe care le conține, poziționându-le în funcție de proprietățile sale (lățime, înălțime și aliniere). Asocierea obiectelor de tip ''​Text''​ în cadrul unui obiect ​''​TextFlow'' ​se face prin apelul metodelor ''​add()''​ / ''​addAll()''​ pentru lista observabilă a componentelor sale.
  
-**Clasa de tip ''​Map''​** este derivată din clasa ''​org.apache.hadoop.mapreduce.Mapper'',​ fiind parametrizată cu 4 valori ​de tip JavaGenerics având semnificaţia tipurilor de date pe care le au cheia şi valoarea datelor de intrare, respectiv cheia şi valoarea datelor de ieşire. Sarcina programatorului constă în a defini metoda ​''​map()''​ care primeşte ca parametru ​o cheie şi o valoare (cu tipurile aferente celor specificate la parametrizarea ​clasei) corespunzătoare ​datelor de intrare şi un obiect de tip ''​Context''​ folosit pentru datele de ieşire, dar şi pentru specificarea unor contoare definite de utilizator.+Se recomandă totuşi ca proprietățile unui text să fie precizate în foi de stil care apoi să fie încărcate prin intermediul metodei ​''​setId()'' ​(care primeşte ca parametru ​numele ​clasei ​CSS corespunzătoare).
  
-<file java MyMapper.java>​ +Efectele care se pot crea asupra textelor ​ sunt: 
-public class MyMapper extends Mapper<​LongWritable, Text, Text, Text> {+  * ''​PerspectiveTransform''​, indicându-se cele 4 puncte ale formei ce defineşte transformarea de perspectivă ca perechi (x,y); 
 +  * ''​GaussianBlur''​ pentru estomparea textului; 
 +  * ''​DropShadow''​ pentru umbre exterioare - indicându-se un offset (''​setOffsetX()''​ / ''​setOffsetY()''​), o culoare (''​setColor()''​),​ raza umbrei (''​setRadius()''​),​ împrăştierea (''​setSpread()''​);​ 
 +  * ''​InnerShadow''​ pentru umbre interioare;​ 
 +  * ''​Reflection''​ pentru reflectarea conţinutului respectiv - indicându-se opacitatea de sus şi de jos (''​setTopOpacity()''​ / ''​setBottomOpacity()''​),​ fracţia din original care va fi vizibilă în reflecţie (''​setFraction()''​),​ un offset între original şi reflecţie (''​setTopOffset()''​).
  
 +Aplicarea unui efect se face prin metoda ''​setEffect()'',​ care primeşte ca parametru obiect de tipul transformării respective.
 +
 +Combinarea de efecte se face folosind clasa ''​Blend''​ (modul fiind în acest caz ''​BlendMode.MULTIPLY''​),​ efectele fiind specificate ca parametri ai metodelor ''​setBottomInput()'',​ respectiv ''​setTopInput()''​.
 +
 +<note tip>​Atunci când se doreşte combinare a mai mult de 2 efecte, combinarea se va face între un efect propriu-zis şi alt obiect de tip Blend care conţine la rândul său o altă combinaţie.</​note>​
 +
 +<code java>
 +Text text = new Text();
 +Blend blend1 = new Blend(), blend2 = new Blend();
 +blend1.setMode(BlendMode.MULTIPLY); ​
 +blend2.setMode(BlendMode.MULTIPLY);​
 +DropShadow dropShadow = new DropShadow(); ​   //...
 +blend1.setBottomInput(dropShadow);​
 +InnerShadow innerShadow = new InnerShadow();​ // ...
 +Reflection reflection = new Reflection ();   // ...
 +blend2.setBottomInput(innerShadow);​
 +blend2.setTopInput(reflection);​
 +blend1.setTopInput(blend2);​
 +text.setEffect(blend1);​
 +</​code>​
 +
 +==== Conținut pentru Pagini Internet ====
 +
 +JavaFX dispune şi de un navigator încorporat,​ bazat pe WebKit, un motor open-source care implementează foi se stil CSS (//eng.// Cascading Stype Sheets), JavaScript, interfața de programare Document Object Model (DOM) și HTML5.
 +
 +=== ===
 +
 +Caracteristicile HTML5 suportate sunt:
 +  * etichetele Canvas și SVG pentru:
 +    * redarea de conținut grafic;
 +    * construirea de forme folosind sintaxa Scalable Vector Graphics, aplicarea de configurări referitoare la culoare, efecte vizuale, animații;
 +  * redarea de conținut media, codec-urile implementate fiind:
 +    * audio: AIFF, WAV(PCM), MP3, AAC;
 +    * video: VP6, H264;
 +    * containere media: FLV, FXM, MP4, MpegTS (HLS);
 +  * controale pentru redarea de formulare și procesarea datelor;
 +  * gesiunea istoricului de navigare din cadrul unei sesiuni, prin intermediul obiectului ''​WebEngine'';​
 +  * etichete interactive:​ ''​details'',​ ''​summary'',​ ''​command'',​ ''​menu'';​
 +  * acces la modelul obiectual al unei pagini Internet (DOM), obținut prin intermediul obiectului ''​WebEngine''​ (metoda ''​getDocument()'';​
 +  * rularea de scripturi Web (//eng.// Web workers) concomitent cu realizarea altor activități din cadrul paginii Internet, astfel încât interacțiunea cu utilizatorul să nu fie afectată;
 +  * sockeți Web (clasa ''​WebSocket''​) pentru realizarea de comunicații bidirenționale cu diverse servere;
 +  * seturi de caractere declarate cu regula ''​@font-face''​ (//eng.// Web fonts) descărcate de pe alte servere, la nevoie (alegerea unui set de caractere care este adecvat scopurilor de proiectare pentru o pagină dată).
 +
 +==== ====
 +
 +Funcționalitățile implementate de navigatorul încorporat de JavaFX sunt:
 +  * redarea de conţinut HTML5 stocat local sau de la o adresă la distanţă;
 +  * obţinerea istoricului de vizitare;
 +  * executarea de comenzi JavaScript;
 +  * acces la metodele JavaFX din acest JavaScript;
 +  * gestiunea ferestrelor proeminente (//eng.// pop-up window);
 +  * aplicarea de efecte asupra sa.
 +
 +Acesta moşteneşte toate atributele şi metodele de la clasa ''​Node'',​ având toate funcţionalităţile acesteia. ​
 +
 +Clasele pe care le foloseşte navigatorul se găsesc în pachetul ''​javafx.scene.web''​.
 +
 +**Clasa ''​WebEngine''​** oferă funcţionalitate de navigare de bază implementând interacţiunea cu utilizatorul cum ar fi accesarea unor legături Internet şi transmiterea de formulare HTML. Ea gestionează o singură pagină HTML la un moment dat, suportând operații precum încărcarea de conţinut Internet şi accesarea proprietăţilor DOM corespunzătoare precum şi execuţia unor comenzi JavaScript (această funcţionalitate poate fi dezactivată pentru anumite motoare web).
 +
 +O instanţă a acestei clase poate fi creată folosind un constructor fără parametri (conţinutul Internet aferent putând fi indicat prin metoda ''​load()''​) sau un constructor căruia i se transmite o locaţie.
 +
 +Utilizatorii pot indica foi de stil care le înlocuiesc pe cele implicite, folosite în cadrul paginilor Internet care sunt redate de navigator.
 +
 +**Clasa ''​WebView''​** reprezintă o extensie a clasei ''​Node'',​ încapsulând obiectul ''​WebEngine'',​ încorporând conţinutul HTML în scena unei aplicaţii şi oferind atributele şi metodele pentru a aplica efecte şi transformări. Legătura dintre acest obiect şi motorul asociat se face prin metodele ''​{get|set}Engine()''​.
 +
 +<code java>
 +String URL = "​http://​aipi2015.andreirosucojocaru.ro";​
 +WebView webView = new WebView();
 +WebEngine webEngine = webView.getEngine();​
 +webEngine.load(URL);​
 +</​code>​
 +
 +Modul în care sunt gestionate ferestrele proeminente poate fi specificat prin intermediul unei metode de tratare care poate întoarce acelaşi motor web ca cel curent (caz în care pagina respectivă este deschisă în acelaşi navigator) sau alt motor web. Clasa ''​PopupFeatures''​ descrie proprietățile unei ferestre proeminente (așa cum sunt descrise de specificația JavaScript),​ instanța sa fiind transmisă metodei de tratare a evenimentului de încărcare a unui conținut de acest tip.
 +
 +<code java>
 +webEngine.setCreatePopupHandler(new Callbak<​PopupFeatures,​ WebEngine>​() {
     @Override     @Override
-    public ​void map(LongWritable key, Text value, Context context) +    public ​WebEngine call(PopupFeatures configuration){
-        throws IOException,​ InterruptedException ​{ +
-        Text outputKey = new Text(); +
-        Text outputValue = new Text();+
         // ...         // ...
-        context.write(outputKey,​ outputValue);​ 
     }     }
-} +}); 
-</file>+</code>
  
-Analog, **clasa de tip ''​Reduce''​** este derivată din ''​org.apache.hadoop.mapreduce.Reducer'',​ având acelaşi tip de parametrizare ​cu menţiunea faptului că tipurile specificate pentru datele de intrare (pentru cheie şi pentru valoare) ale acestuia trebuie să fie identice cu tipurile specificate pentru datele de ieşire ale clasei de tip ''​Map''​, întrucât perechile (cheie, valoare) produse de aceasta vor fi grupate ​astfel ​că pentru fiecare cheie va exista un set de una sau mai multe valori. Acest proces este cunoscut sub denumirea de amestecare şi sortare (//eng.// shuffle and sort). Intrările pentru ​clasa de tip ''​Reduce''​ sunt sortate în funcţie de cheie, fiecare set de valori fiind prelucrat în metoda ''​reduce()''​ care primeşte ca argumente o cheie şi un set de valori, dar şi obiectul de tip ''​Context''​. ​Un set de valori este reprezentat sub forma ''​Iterable<​V>''​. Prelucrările în cadrul metodei ​''​reduce()''​ sunt realizate prin parcurgerea acestei liste şi realizarea unor agregări asupra acestor valori pentru obţinerea rezultatului.+Componenta ​''​WebView'' ​reține informațiile ​cu privire la navigare în memorie, astfel ​încât acestea sunt pierdute atunci când aplicația este terminată. Persistența poate fi însă implementată în mod explicit prin clasa ''​java.net.ResponseCache''​.
  
-<​file ​java MyReducer.java> +Clasa ''​WebEngine''​ pune la dispoziţie metoda ''​executeScript()''​ pentru a rula o comandă JavaScript declarată în cadrul documentului încărcat în navigator la momentul de timp respectiv. Rezultatul execuției metodei este convertit la un obiect ''​java.lang.Object'',​ pe baza următoarelor reguli: 
-public class MyReducer extends Reducer<​Text,​ Text, Text, Text> {+  * tipul JavaScript ''​Int32''​ este convertit la ''​java.lang.Integer'';​ 
 +  * numerele JavaScript sunt covertite la ''​java.lang.Double'';​ 
 +  * valorile de tip șir de caractere din JavaScript sunt convertite la ''​java.lang.String'';​ 
 +  * valorile de tip adevărat / fals din JavaScript sunt converite la ''​java.lang.Boolean''​.
  
-    @Override +De asemenea, există posibilitatea de a invoca cod JavaFX din cadrul JavaScript prin crearea unui obiect de interfaţă în aplicaţie care este transmis prin metoda ''​JSObject.setMember()''​. Ea trebuie apelată într-o metodă de tratare asociată evenimentului de încărcare al paginii, care se realizează pe un fir  de execuţie separat. Pentru acest obiect, atributele şi metodele publice definite în JavaFX vor fi accesibile din JavaScript. 
-    ​public void reduce(Text key, Interable<Text> values, Context context) + 
-        ​throws IOException,​ InterruptedException ​{ +<code java> 
-        Text outputKey ​= new Text(); +webEngine.getLoadWorker().stateProperty().addListener( 
-        Text outputValue = new Text(); +    (ObservableValue<? extends State> observableValue, State oldState, State newState) -> { 
-        for (Text value: values) { +        ​if (newState == State.SUCCEEDED) ​{ 
-            // ... +            ​JSObject jsObject ​= (JSObject)webEngine.executeScript("​window"​); 
-        } +            ​jsObject.setMember("​myObject", ​new MyClass()); 
-        ​context.write(outputKey,​ outputValue);+         } 
 +         ​// ... 
 +    } 
 +); 
 + 
 +// JavaScript interface object 
 +public class MyClass { 
 +    public void myMethod() { 
 +        // ...
     }     }
 } }
-</file>+</code>
  
-Opţional, se poate defini şi o clasă Combiner, spre a combina informaţiile pentru fiecare sarcină de tip ''​Map''​, astfel ​încât cantitatea datelor procesate de sarcina ''​Reduce''​ să fie limitată. Aceste clase nu sunt însă garantate să ruleze, fiind folosite mai mult pentru optimizări şi nu în cazul operaţiilor critice pentru logica aplicaţiei.+Un astfel de obiect ​poate fi folosit într-un document HTML, astfel:
  
-Informaţiile oferite la rularea unei sarcini sunt identificatorul acesteia (folosit pentru ​a monitoriza şi a gestiona sarcina), numărul de partiţii generate, progresul şi valoarea contoarelor exprimând statistici referitoare la operaţiile care au fost realizate în cadrul rulării sarcinii.+<code html> 
 +<a href="​about:​blank"​ onclick="​myObject.myMethod()">...</​a>​ 
 +</​code>​
  
-Întrucât HBase este scris în limbajul de programare Java, el oferă un API pentru acces programatic la informaţiile conţinute. Aceasta reprezintă metoda cea mai rapidă de a accesa informaţiile din cadrul unei baze de date distribuite de tip HBase. Sunt suportate operaţii de tip CRUD, dar şi unele operaţii administrative.+Pentru obiectele ''​WebView''​, meniurile contextuale sunt activate implicit, dezactivarea lor realizându-se prin metoda ''​setContextMenuEnabled()''​.
  
-Accesul la o bază de date HBase presupune crearea unui obiect ​de tip ''​Configuration'', ​în care sunt încărcate proprietăţi specifice, indicate de utilizator în fişierele de configurare,​ construirea unui obiect de tip ''​HTable'' ​(pentru care trebuie să se specifice atât obiectul ​de configurare cât şi denumirea tabelului), realizarea diferitelor operaţii (''​put()'', ​''​get()''​, ''​scan()''​, ''​delete()''​) şi închiderea instanţei care implică eliberarea tuturor resurselor folosite şi a zonelor de memorie tampon.+Istoricul paginilor vizitate poate fi obţinut prin metoda ''​getHistory()''​ aplicată obiectului ​de tip ''​WebEngine'', ​întorcând un obiect de tip ''​WebHistory''​. Acesta este o listă de intrări ce poate fi accesată prin metoda ​''​getEntries()'', ​conţinând informaţii despre pagină ​(URL şi titlu) sau despre data la care aceasta a fost vizitată cel mai recent. Metoda ​''​go()'' ​a acestei clase forțează navigatorul să încarce pagina reţinută la indexul respectiv.
  
-Clasa ''​Configuration'' ​extinde ​clasa de configurare Hadoop cu care păstrează compatibilitatea, la crearea unui astfel de obiect fiind încărcate din classpath documentele ​''​hbase-default.xml'' ​şi ''​hbase-site.xml''​. ​Valorile ​proprietăţilor din ''​hbase-site.xml'' ​suprascriu valorile proprietăţilor ​conţinute ​în ''​hbase-default.xml''​.+Conținutul unei pagini Internet poate fi tipărit folosint imprimanta instalată în cadrul mașinii, folosind metoda ​''​print()'' ​din clasa ''​WebEngine''​. Aceasta primește un obiect ​de tip ''​PrinterJob'',​ obținut prin apelul metodei statice ''​PrinterJob.createPrinterJob()''​. În situația în care nu există nici o imprimantă instalată, rezultatul întors va fi ''​null''​. De asemenea, trebuie apelată metoda ​''​endJob()''​ a obiectului ''​PrinterJob''​ pentru a se asigura faptul că procesul de tipărire a fost terminat. 
 + 
 +<​note>​Fiecare sarcină de tipărire poate fi configurată prin specificarea parametrilor: ​''​collation'',​ ''​copies'',​ ''​pageLayout'',​ ''​pageRanges'',​ ''​paperSource'',​ ''​printColor'',​ ''​printResolution'',​ ''​printQuality'',​ ''​printSides''​.</​note>​ 
 + 
 +În cazul în care se doreşte folosirea mai multor navigatoare,​ acestea pot fi create în cadrul unor obiecte de tip ''​TabPane''​. 
 + 
 +==== Mecanisme de Dispunere a Conținutului ==== 
 + 
 +În JavaFX sunt disponibile mai multe mecanisme de dispunere a conținutului,​ denumite containere, care pot fi utilizate pentru gestiunea interfeței cu utilizatorul. În situația în care o fereastră este redimensionată,​ elementele componente sunt își modifică în mod automat coordonatele și mărimea, în funcție de proprietățile pe care le au. 
 + 
 +Alternativ, un programator ar trebui să dispună manual elementele grafice, indicând proprietăți precum poziția și dimensiunea. Adițional, ar trebui să gestioneze explicit actualizarea acestor valori în cazul producerii unor evenimente de tip minimizare sau maximizare a ferestrei în care sunt conținute. 
 + 
 +=== BorderPane === 
 + 
 +Un container de tip ''​BorderPane''​ oferă cinci regiuni pentru poziționarea nodurilor: sus, jos, stânga, dreapta şi centru, acestea putând avea orice dimensiune. 
 + 
 +<note tip>În situația în care aplicația JavaFX nu are nevoie de o anumită regiune, aceasta nu va fi definită, nefiind alocat spațiu pentru ea.</​note>​ 
 + 
 +O situație în care un astfel de mecanism al conținutului este oportun de folosit este cazul în care în partea de sus este plasat un meniu, în partea de jos o bară de stare, în stânga un panou de navigare, în dreapta un panou pentru informații suplimentare iar în centru conținutul propriu-zis. 
 + 
 +Dacă spațiul de afișare este prea mic, regiunile se pot suprapune. Modul în care sunt suprapuse regiunile este determinat de ordinea în care acestea au fost definite. 
 + 
 +Dacă spațiul de afișare este prea mare, acesta va fi alocat în zona centrală. 
 + 
 +Pentru un obiect ​''​BorderPane''​ sunt disponibile metodele ''​setTop()'',​ ''​setBottom()'',​ ''​setLeft()'',​ ''​setRight()'',​ ''​setCenter()'',​ toate primind ca parametru un obiect de tip ''​Node''​ (inclusiv de tip container) al cărui conținut va fi redat în regiunea respectivă. 
 + 
 +=== HBox / VBox === 
 + 
 +Un container de tip ''​HBox''​ oferă un mecanism de dispunere a nodurilor într-un singur rând. 
 + 
 +Un container de tip ''​VBox''​ oferă un mecanism de dispunere a nodurilor într-o singură coloană. 
 + 
 +Metoda ''​setPadding()'',​ ce primește ca parametru un obiect de tip ''​Insets'',​ definește distanțele față de cele patru laturi ale continerului la care vor fi dispuse elementele componente. 
 + 
 +Metoda ''​setSpacing()'',​ ce primește ca parametru o valoare întreagă, specifică distanțele dintre elementele componente. 
 + 
 +Metoda ''​setMagin()''​ poate fi utilizată pentru a indica un spațiu suplimentar în jurul unui control grafic. Aceasta primește ca parametri elementul la care se referă și un obiect de tip ''​Insets''​ care precizează valoarea spațierii pentru fiecare latură în parte. 
 + 
 +Asocierea unor controale grafice la un obiect ''​HBox''​ / ''​VBox''​ se face prin metodele ''​add()''​ / ''​addAll()''​ apelată pentru lista observabilă a componentelor sale:
  
 <code java> <code java>
-Configuration conf = HBaseConfiguration.create();+HBox hBox = new HBox(); 
 +hbox.setPadding(new Insets(5, 5, 5, 5)); 
 +hbox.setSpacing(5);​ 
 +Control control1 = new Control();​ 
 +hBox.getChildren().addAll(control1);​ 
 +// ... 
 +VBox vBox = new VBox(); 
 +Control control2 = new Control();​ 
 +vBox.setMargin(control2,​ new Insets(5, 5, 5, 5)); 
 +vBox.getChildren().addAll(control2);
 </​code>​ </​code>​
  
-Unele proprietăţi pot fi suprascrise manual, însă un astfel de comportament ​nu este de regulă necesar ​şi nici de dorit.+=== StackPane === 
 + 
 +Un container de tip ''​StackPane''​ plasează toate nodurile într-o singură stivă în care un nod nou este așezat peste un nod vechi. 
 + 
 +Un astfel de mecanism de dispunere poate fi utilizat pentru a suprapune un text peste o imagine sau pentru a suprapune mai multe forme pentru a obține o formă complexă. 
 + 
 +Metoda ''​setAlignment()''​ (ce primește ca parametri valori din interfața ''​Pos''​) indică modul în care componentele sunt poziționate în cadrul containerului,​ referindu-se la întregul conținut. Locația la care va fi plasat fiecare element grafic poate fi controlat prin intermediul marginilor. 
 + 
 +=== GridPane === 
 + 
 +Un container de tip ''​GridPane''​ permite dispunerea elementelor grafice la orice poziție din cadrul unui tabel având un anumit număr de rânduri și coloane, un nod putând să ocupe spațiul corespunzător mai multor celule. 
 + 
 +Acest mecanism de dispunere a conținutului este util de folosit atunci când sunt proiectate formulare sau pentru orice conținut organizat sub formă de rânduri și coloane. 
 + 
 +Proprietatea ''​gridLinesVisible''​ delimitează liniile și coloanele, evidențiind și spațiile dintre acestea, fiind utilă mai ales în partea de testare a aplicației. 
 + 
 +Spațiile dintre linii și coloane sunt controlate prin metodele ''​setHgap()''​ și ''​setVgap()'',​ ce primesc ca parametrii valori întregi indicând distanțele propriu-zise. 
 + 
 +Metoda ''​setPadding()''​ controlează distanța față de marginile containerului. 
 + 
 +Asocierea unui element grafic la obiectul de tip ''​GridPane''​ se face prin metoda ''​add''​ ce primește ca parametru nodul care va fi inclus, coloana și linia la care va fi poziționat și, în cazul controalelor care ocupă mai multe coloane / linii, numărul acestora. 
 + 
 +Pentru un obiect ''​GridPane'' ​pot fi specificate constrângeri de aliniere pentru rânduri și coloane, prin intermediul claselor ''​RowConstraints'',​ respectiv ''​ColumnConstraints'',​ care definesc metodele ''​setHalignment()'',​ respectiv ''​setValingment()'',​ având ca parametri valori din interfețele ''​HPos'',​ respectiv ''​VPos''​. 
 + 
 +În situația în care fereastra este redimensionată, nodurile din cadrul acestui mecanism de dispunere a conținutului sunt redimensionate în funcție de constrângerile fiecăreia. 
 + 
 +=== FlowPane === 
 + 
 +Un container de tip ''​FlowPane''​ sunt dispuse continuu, unul după celălalt, în funcție de orientare (verticală - în coloane, orizontală - în rânduri) și de limitele mecanismului de dispunere (înălțime,​ respestiv lățime). 
 + 
 +=== TilePane === 
 + 
 +Un container de tip ''​TilePane''​ poziționează fiecare element într-o matrice în care fiecare celulă are aceeași dimensiune. 
 + 
 +Dispunerea se poate face orizontal (în rânduri) sau verical (în coloane) limitându-se la lățimea, respectiv înălțimea mecanismului de dispunere. 
 + 
 +Dimensiunea unei celule poate fi determinată dacă se specifică numărul preferat de rânduri și se coloane, prin intermediul metodelor ''​setPrefRows()'',​ respectiv ''​setPrefColumns()''​. 
 + 
 +=== AnchorPane === 
 + 
 +Un container de tip ''​AnchorPane''​ permite raportarea poziției unui nod la marginile de sus, jos, din stânga, dreapta sau la centrul mecanismului de dispunere.  
 + 
 +În situația în care fereastra este redimensionată,​ elementele grafice își mențin poziția relativ la punctul față de care au fost definite. 
 + 
 +Poziția unui nod poate fi specificată în funcție de mai multe elemente de referință și un element de referință poate servi drept reper pentru mai multe noduri. 
 + 
 +Metodele pe care le definește un obiect ''​AnchorPane''​ sunt ''​setTopAnchor()'',​ ''​setBottomAnchor()'',​ ''​setLeftAnchor()'',​ ''​setRightAnchor()''​ și ''​setCenterAnchor()'',​ acestea primind ca parametri elementul grafic care este poziționat și distanța față de referință la care este plasat. 
 + 
 +==== ==== 
 + 
 +Dimensiunile unui control grafic sunt în general determinate de conținutul acestuia, ​astfel ​încât acesta să fie vizibil în totalitate. Astfel ​de proprietăți sunt controlate și de containerul în care acestea sunt incluse. 
 + 
 +Totuși pentru fiecare control sunt definite: 
 +  * dimensiuni minime, controlate prin metodele: 
 +    * ''​setMinWidth()''​ / ''​setMinHeight()''​ 
 +    * ''​setMinSize()''​ 
 +  * dimensiuni maxime, controlate prin metodele: 
 +    * ''​setMaxWidth()''​ / ''​setMaxHeight()''​ 
 +    * ''​setMaxSize()''​ 
 +  * dimensiuni preferate, controlate prin metodele ''​setPrefWidth()''​ / ''​setPrefHeight()''​ 
 + 
 +În cazul în care se dorește ca un element grafic să sibă valori constante indiferent de modificarea dimensiunii containerului din care face parte, se va specifica valoarea ''​Control.USE_PREF_SIZE''​ atât ca valoare minimă cât și ca valoare maximă, precizând eventual și o valoare explicită pentru valoarea preferată. 
 + 
 +<note tip>​Implicit,​ valoarea preferată este cea calculată, pe baza conținutului elementului grafic și a constrângerilor containerului din care face parte.</​note>​ 
 + 
 +În situația în care se dorește ca un element grafic să nu fie limitat, fiind redimensionat automat la întregul spațiu disponibil pe care îl are la dispoziție,​ se va specifica valoarea ''​Double.MAX_VALUE''​ ca valoare maximă. 
 + 
 +Alinierea controalelor se face prin intermediul metodei ''​setAlignment()''​ aplicată pentru obiectul de tip container din care fac parte, acesta putând lua valori: 
 +  * precizate de interfața ''​VPos''​ pentru aliniere verticală;​ 
 +  * precizate de interfața ''​HPos''​ pentru aliniere orizontală;​ 
 +  * precizate de interfața ''​Pos''​ pentru aliniere verticală și orizontală (valorile sunt separate prin caracterul ''​_''​ astfel: în stânga sa este precizat tipul de aliniere verticală, în dreapta sa este indicat tipul de aliniere orizontală);​ centrarea pe verticală și orizontală se face prin valoarea ''​Pos.CENTER''​. 
 +==== Foi de Stil ==== 
 + 
 +O foaie de stil (//eng.// CSS - Cascading Style Sheet) conține definiții cu privire la aspectul elementelor de interfață cu utilizatorul.  
 + 
 +Utilizarea foilor de stil în aplicaţiile JavaFX este similară ca în cazul paginilor Internet HTML întrucât este utilizată aceeași specificație ([[http://​www.w3.org/​TR/​CSS21/​|versiunea 2.1 a W3C CSS]] cu unele actualizări din versiunea 3). 
 + 
 +<note tip>​Implicit,​ orice aplicație JavaFX folosește foaia de stil ''​modena.css'',​ disponibilă în arhiva ''​jfxrt.jar''​ (din ''​$JAVA_HOME/​jre/​lib/​ext''​) - în directorul ''​com/​sun/​javafx/​scene/​control/​skin/​modena/''​.</​note>​ 
 + 
 +**1.** Pentru fiecare obiect instanţă a unui control se poate apela metoda ''​setStyle()''​ primind ca parametru un şir de caractere de forma ''​atribut:​valoare'',​ separate prin '';'',​ unde atribut este denumirea elementului de stil (prefixat cu ''​-fx-''​),​ iar valoare reprezintă caracteristica asociată, respectând o semantică specifică.  
 + 
 +**2.** Un fişier ''​.css''​ care specifică formatul asociat pentru diferite elemente este asociat unei scene prin metoda ''​scene.getStyleSheets().add("​custom_style.css"​)''​. 
 + 
 +O definiție a unui stil constă din denumirea acestuia (denumită selector sau clasă de stil, prefixată de regulă de caracterul ''​.''​) și o serie de reguli incluse între acolade (''​{}''​) care indică proprietățile respective. 
 + 
 +<file css custom_style.css>​ 
 +.custom-control { 
 +    -fx-font: 12px "​Arial";​ 
 +    -fx-padding:​ 5; 
 +    -fx-background-color:​ beige; 
 +} 
 +</​file>​ 
 + 
 +<note tip>​Dimensiunea pentru caractere poate fi specificată fie în puncte (pt), fie în pixeli (px). Se presupune că rezoluția este de 96 dpi (dots per inch), astfel că 1px = 0.75pt.</​note>​ 
 + 
 +<note tip>​Dacă se dorește specificarea unui stil pentru un anumit control, în locul clasei de stil poate fi specificat identificatorul elementului grafic respectiv (dat prin metoda ''​setId()''​),​ prefixat de caracterul ''#''​.</​note>​ 
 + 
 +<note tip>În situația în care un control poate avea mai multe stări și se dorește specificarea unor clase de stil pentru fiecare dintre acestea, clasa de stil va avea forma ''​denumire element grafic:​stare element grafic''​.</​note>​ 
 + 
 +Folosirea unei clase de stil pentru un element grafic se face prin metoda ''​add()''​ apelată pentru clasa de stil a obiectului respectiv, primind ca parametru denumirea indicată în fișierul ''​.css'':​
  
 <code java> <code java>
-conf.set("​mapreduce.input.keyvaluelinerecordreader.key.value.separator", ​"\t");+customControl.getStyleClass().add("custom-control");
 </​code>​ </​code>​
  
-Un obiect de tip ''​Configuration''​ trebuie partajat cât de mult posibil întrucât obiectele de tip ''​HTable''​ create cu aceeaşi configurație vor avea aceeaşi conexiune la ZooKeeper şi HBaseMaster,​ de vreme ce o conexiune ​ este reţinută intern printr-un obiect de tip asociere care foloseşte drept cheie instanţe ale obiectului de tip ''​Configuration''​. Când se reutilizează un obiect de tip ''​Configuration''​ pentru mai multe instanţe ''​HTable'',​ trebuie apelat ''​close()''​ ca ''​HConnectionManager''​ să elimine instanţa din lista tabelelor ce folosesc conexiunea respectivă. Când toate tabelele unei conexiuni sunt închise, este terminată şi conexiunea corespunzătoare. O conexiune e reprezentată de clasa ''​HConnection''​ fiind gestionată de clasa ''​HConnectionManager''​.+==== Gestiunea Evenimentelor ====
  
-Clasa ''​org.apache.hadoop.client.HTable'' ​reprezintă ​interfaţa clientului către o singură tabelă HBase, oferind acces la operaţii CRUD, fiind proiectată ​pentru a fi utilizată cu uşurinţă. Operaţiile care modifică datele sunt atomice pentru fiecare înregistrare în parte, neexistând conceptul ​de tranzacţie (care să implice mai mult de o înregistrare). Astfel, există ​o consistenţă de 100% per înregistrare,​ clientul realizând operaţii de citire sau de scriere asupra acesteia ​sau aşteptând eliberarea accesului. Atomicitatea se păstrează indiferent ​de numărul ​de coloane utilizate în cadrul cererii.+Evenimentele ​reprezintă ​mecanisme utilizate ​pentru a transmite aplicaţiei acţiunile realizate ​de utilizator, astfel încât aceasta ​să reacţioneze corespunzător. În JavaFX, un eveniment e o instanţă a clasei ''​javafx.event.Event'' ​sau a oricărei subclase a acesteia. Pe lângă tipurile predefinite ​de evenimente (''​KeyEvent'',​ ''​MouseEvent'',​ ''​TouchEvent'',​ ''​ScrollEvent'',​ ''​DragEvent'',​ ''​DropEvent''​),​ programatorul îşi poate defini propriile tipuri ​de evenimente (derivate din clasa ''​Event''​).
  
-<note>Un obiect ''​HTable''​ poate fi utilizat pentru grupuri de comenzi (spre a se asigura performanţa), însă aceste operaţii nu sunt atomice.</​note>​+|< 100% >| 
 +^  **Proprietate** ​ ^  **Descriere** ​ ^ 
 +| tip eveniment | categoria evenimentului care s-a produs | 
 +| sursă | originea evenimentului,​ raportat la locaţia evenimentului în lanţul de propagare | 
 +| ţintă | nodul asupra căruia ​a avut loc acţiunea şi nodul frunză în lanţul de propagare ​ |
  
-<​note>​O astfel de abordare nu reprezintă o problemă în cazul în care există mai multe procese care realizează operaţii de citire, însă există o problemă în cazul în care mai multe procese încearcă să scrie aceeaşi înregistrare.</​note>​+<​note>​Sursa se modifică pe măsură ce evenimentul este transmis de-a lungul lanţului de propagare.</​note>​
  
-Crearea unui obiect ''​HTable''​ este destul de costisitoare întrucât este scanat întregul catalog ''​.META.'',​ verificându-se dacă tabela există ​şi este activată. Astfel, aceasta trebuie apelată o singură dată în cadrul unui fir de execuţie, fiind refolosit cât de mult posibil. Operaţiile realizate ​cu obiecte ​''​HTable'' ​nu sunt garantate să funcţioneze corect într-un mediu distribuit.+<​note>​Deşi ţinta nu se schimbă, dacă un filtru pentru evenimente consumă evenimentul ​în procesul ​de tratare a avenimentului, ​ţinta nu va primi evenimentul.</​note>​ 
 + 
 +Un **tip de eveniment** este o instanţă a clasei ''​EventType''​, acestea ​fiind organizate ierarhic, pe nivelul cel mai înalt aflându-se ''​Event.ROOT''​ echivalent ​cu ''​Event.ANY''​. Pe fiecare nivel, subtipul ''​ANY''​ este folosit pentru a desemna orice tip de eveniment din clasă. Mecanismul este foarte util în cazul în care se folosesc filtre pentru evenimente, putându-se trata fie doar anumite tipuri de evenimente, fie toate tipurile de evenimente specifice clasei respective. 
 + 
 +{{ :​laboratoare:​laborator09:​07event_type_hierarchy.png?nolink }}
    
 +**Sursa** unui eveniment desemnează nodul care are asociat mecanismul de tratare a evenimentului,​ aflându-se cel mai aproape de nodul propriu-zis (asupra căruia s-a exercitat acţiunea respectivă) în ierarhia de obiecte a scenei.
 +
 +**Ţinta** unui eveniment este instanţa clasei ''​EventTarget''​ sau a oricărei subclase a acesteia. Lanţul de transmitere al evenimentului (ruta pe care evenimentul o urmează pentru a ajunge la ţintă) este realizată prin metoda ''​buildEventDispatchChain()''​. Clasele ''​Window'',​ ''​Scene''​ şi ''​Node''​ implementează interfaţa ''​EventTarget''​ şi toate subclasele lor moştenesc această proprietate,​ ceea ce înseamnă că pentru majoritatea obiectelor nu va fi necesar să se stabilească lanţul de transmitere a evenimentului,​ implementându-se doar modul de reacţie la evenimentul respectiv. Pentru controalele definite de utilizator, în cazul în care nu sunt subclase ale ''​Window'',​ ''​Scene''​ şi ''​Node'', ​ va trebui să se implementeze interfaţa ''​EventTarget'',​ pentru ca acesta să gestioneze acţiunile utilizatorului.
 +
 +Prin **lanţ de propagare** a unui eveniment se înţelege un proces format din următoarele etape: selecţia ţintei, stabilirea parcursului urmat de eveniment, capturarea propriu-zisă evenimentului şi întoarcerea sa la nodul rădăcină.
 +
 +În etapa de //selecţie a ţintei//, se determină care este nodul ţintă, în funcţie de următoarele reguli:
 +  * în evenimente legate de tastatură, nodul ţintă este cel ce deţine controlul la momentul respectiv;
 +  * în evenimente legate de mouse, nodul ţintă este cel de la locaţia cursorului; pentru evenimente legate de mouse sintetizate,​ punctul de atingere este considerat locația cursorului;
 +  * în evenimente ce implică gesturi în cazul dispozitivelor cu ecran tactil, nodul ţintă este cel situat în centrul acţiunilor utilizatorului,​ la începutul gestului respectiv; în cazul unor evenimente ce implică gesturi realizate pe un dispozitiv ce nu conţine ecran tactil, nodul ţintă este cel de la locaţia cursorului;
 +  * în evenimente de tip glisare în cazul dispozitivelor cu ecran tactil, nodul ţintă este cel situat în centrul acţiunilor utilizatorului,​ considerându-se întregul parcurs al acestuia; în cazul unor evenimente ce implică gesturi realizate pe un dispozitiv ce nu conţine ecran tactil, nodul ţintă este cel de la locaţia cursorului;
 +  * în evenimente de tip atingere în cazul dispozitivelor cu ecran tactil, nodul ţintă pentru fiecare punct este cel de la locaţia primei apăsări; se poate specifica un alt nod ţintă folosind metodele ''​grab(node)''​ sau ''​ungrab()''​ pentru un anumit punct într-un filtru de evenimente sau mecanism de tratare a evenimentelor.
 +
 +În cazul în care la locaţia evenimentului se află mai multe noduri, ţinta este cea de la nivelul cel mai înalt. De asemenea, când se produce un eveniment cum ar fi o apăsare la nivel de tastatură sau de mouse, evenimentele succesive (până ce tasta sau butonul respectiv sunt eliberate) vor fi legate de nodul ţintă iniţial.
 +
 +Pentru //​stabilirea parcursului urmat de eveniment//,​ în principiu se foloseşte lanţul de propagare a evenimentului dat de metoda ''​buildEventDispatchChain()''​ de la nivelul nodului ţintă selectat (aceasta va conţine în mod obligatoriu obiectele ''​Stage''​ şi ''​Scene''​ care conţin nodul respectiv şi apoi calea propriu-zisă către nodul respectiv în graful de scene). Totuşi, ruta poate fi modificată după cum filtrele de evenimente respectiv metodele de tratare pentru evenimente de pe parcursul urmat de eveniment îl procesează (spre exemplu, dacă evenimentul este "​consumat"​ înainte de a ajunge la nodul ţintă).
 +
 +În etapa de //capturare propriu-zisă//​ (//eng.// event capturing phase), evenimentul în cauză este transmis de la nodul rădăcină către nodul ţintă prin lanţul de propagare a evenimentului. Fiecare nod din acest lanţ de propagare al evenimentului care are implementată o metodă pentru respectivul tip de eveniment îl va gestiona, ulterior transmiţându-l mai departe. Dacă pe parcurs nu există un filtru pentru eveniment care să îl consume, acesta va ajunge la nodul ţintă într-un final.
 +
 +După ce evenimentul a ajuns la nodul ţintă şi / sau a fost procesat de către toate filtrele, acesta se va //întoarce la nodul rădăcină//​ (//eng.// event bubbling phase), urmărind parcursul dat de lanţul de propagare, însă în sens invers. Dacă vreun nod în lanţul de propagare are definită o metodă de tratare pentru respectivul tip de eveniment, aceasta este apelată, transmiţând evenimentul mai departe după ce se termină. Evenimentul va fi transmis într-un final şi nodului rădăcină doar dacă metodele de tratare a acestuia nu îl consumă.
 +
 +{{ :​laboratoare:​laborator09:​08event_managing.png?​nolink&​600 }}
 + 
 +În JavaFX, gestiunea evenimentelor se face prin **filtre** şi **metode de tratare**, acestea fiind implementări ale interfeţei ''​EventHandler''​. Atunci când se dorește ca aplicaţia să fie notificată de apariţia unui eveniment, trebuie asociat fie un filtru, fie o metodă de tratare specifică evenimentului respectiv.
 +
 +Diferenţa dintre un filtru şi o metodă de tratare constă în momentul la care fiecare dintre acestea sunt executate.
 +
 +Un **filtru** este executat în etapa de capturare propriu-zisă. La nivelul unui nod părinte, pot fi implementate filtre pentru mai multe noduri fiu şi în caz de necesitate, evenimentul poate fi consumat spre a preveni ca acesta să mai ajungă la nodul ţintă. Un nod poate avea asociate mai mult de un singur filtru. Ordinea în care acestea sunt executate ţine de ierarhia tipurilor de evenimente. Filtrele asociate unui tip de eveniment mai specific sunt executate înainte de filtrele asociate unui tip de eveniment mai generic. Nu se specifică însă ordinea în care sunt executate filtrele corespunzătoare unor tipuri de evenimente aflate pe acelaşi nivel.
 +
 +O **metodă de tratare** este executată în etapa de întoarcere la nodul rădăcină. Dacă metoda de tratare de la nivelul nodului fiu nu consumă evenimentul,​ atunci nodul părinte îl poate gestiona ulterior. Şi în cazul metodelor de tratare se aplică aceeaşi regulă din cazul filtrelor cu privire la numărul de evenimente pe care acestea îl pot gestiona precum şi a ordinii în care acestea sunt executate. ​
 +
 +Evenimentele specificate prin metode de oportunitate (//eng.// convenience methods) se execută ultimele.
 +
 +Un eveniment poate fi consumat de un filtru sau de o metodă de tratare oricând în lanţul de propagare al evenimentelor prin metoda ''​consume()''​ care anunţă faptul că procesarea evenimentului s-a încheiat. Consumarea unui eveniment de un filtru împiedică nodurile fii să îl primească la fel cum consumarea sa de către o metodă de tratare împiedică nodurile părinte să îl primească. Nu este afectată însă gestiunea altor tipuri de evenimente din cadrul nodului respectiv.
 +
 +Unele clase JavaFX definesc proprietăţi pentru metodele de tratare, oferind un mecanism de a specifica un comportament în cazul în care se produc anumite evenimente. Acestea poartă numele de //mecanisme de oportunitate//​ pentru asocierea unor metode de tratare. Acestea sunt definite în clasa ''​Node'',​ fiind disponibile pentru toate subclasele lor. Alte clase işi au definite propriile mecanisme de oportunitate.
 +
 +^  **Acţiunea Utilizatorului** ​ ^  **Tip de Eveniment** ​ ^  **Clasa** ^
 +| Se apasă o tastă de pe tastatură. | ''​KeyEvent''​ | ''​Node'',​\\ ''​Scene''​ |
 +| Mouse-ul este mişcat sau se apasă un buton de pe mouse. | ''​MouseEvent''​ | ''​Node'',​\\ ''​Scene''​ |
 +| Se produce o secvenţă de acţiuni care implică apăsarea unui buton de pe mouse, mişcarea mouse-ului urmată de eliberarea butonului. | ''​MouseDragEvent''​ | ''​Node'',​\\ ''​Scene''​ |
 +| Se transmite conţinut printr-o metodă alternativă de introducere a caracterelor (limbă ce utilizează alte tipuri de caractere) | ''​InputMethodEvent''​ | ''​Node'',​\\ ''​Scene''​ |
 +| Un obiect este mutat între locaţii prin selectarea, transportarea şi deselectarea sa. | ''​DragEvent''​ | ''​Node'',​\\ ''​Scene''​ |
 +| Obiectul este derulat. | ''​ScrollEvent''​ | ''​Node'',​\\ ''​Scene''​ |
 +| Se produce un gest de tip rotaţie asupra obiectului. | ''​RotateEvent''​ | ''​Node'',​\\ ''​Scene''​ |
 +| Se produce un eveniment de tip derulare asupra unui obiect. | ''​SwipeEvent''​ | ''​Node'',​\\ ''​Scene''​ |
 +| Pe ecranul tactil, este atinsă locaţia la care se află un obiect. | ''​TouchEvent''​ | ''​Node'',​\\ ''​Scene''​ |
 +| Se produce un gest ce implică modificarea rezoluţiei asupra obiectului respectiv. | ''​ZoomEvent''​ | ''​Node'',​\\ ''​Scene''​ |
 +| Este solicitată vizualizarea meniului contextual. | ''​ContextMenuEvent''​ | ''​Node'',​\\ ''​Scene''​ |
 +| Butonul este apăsat.\\ Lista derulantă este vizibilă sau este ascunsă.\\ Elementul unui meniu este selectat. | ''​ActionEvent''​ | ''​ButtonBase'',​\\ ''​ComboBoxBase'',​\\ ''​ContextMenu'',​\\ ''​MenuItem'',​\\ ''​TextField''​ |
 +| Se editează elementele dintr-un obiect de tip listă, tabel sau arbore. | ''​ListView.EditEvent''​\\ ''​TableColumn.CellEditEvent''​\\ ''​TreeView.EditEvent''​ | ''​ListView'',​\\ ''​TableColumn'',​\\ ''​TreeView''​ | 
 +| Obiectul de redare a conţinutului multimedia întâlneşte o eroare. | ''​MediaErrorEvent''​ | ''​MediaView''​ |
 +| Meniul este vizibil sau ascuns. | ''​Event''​ | ''​Menu''​ |
 +| O fereastră pop-up este ascunsă. | ''​Event''​ | ''​PopupWindow''​ |
 +| Panoul este închis sau selectat. | ''​Event''​ | ''​Tab''​ |
 +| Fereastra e închisă, vizibilă, ascunsă | ''​WindowEvent''​ | ''​Window''​ |
 +
 +O metodă de tratare e asociată nodului prin mecanismul de oportunitate folosind următoarea sintaxă:
 <code java> <code java>
-HTable myTable = new HTable(conf, "​TableName"​);+setOnEvent-type(EventHandler<?​ super event-class>​ value)
 </​code>​ </​code>​
 +unde:
 +  * ''​event-type''​ este tipul evenimentului pe care îl gestionează metoda de tratare;
 +  * ''​event-class''​ este clasa care defineşte tipul de eveniment (sintaxa ''<?​ super event-class>''​ indică faptul că metoda acceptă o metodă de tratare fie pentru clasa care defineşte tipul de eveniment (event-class),​ fie pentru una dintre superclasele acesteia).
  
-<note tip>În cazul în care se folosesc prea multe instanţe ''​HTable'' ​la un moment dat, ar trebui utilizat un obiect de tip ''​HTablePool''​ pentru că reutilizează instanţele acestor clase.</​note>​+Totodată, se poate implementa metoda de tratare prin definirea acesteia într-o clasă anonimă ​în cadrul mecanismului de oportunitate,​ specificându-se comportamentul în cazul producerii evenimentului în contextul funcţiei ''​handle()''​.
  
-Pentru a se scrie date într-o tabelă, se foloseşte un obiect de tip ''​Put'',​ care este instanţiat cu identificatorul (cheia de rând) a înregistrării care se doreşte transmisă, în format binar.+<columns 100% 50%>
  
 <code java> <code java>
-Put myPut = new Put(Bytes.toBytes("​myRow"​));+tableContent.setOnMouseClicked(new EventHandler<​MouseEvent>​() {  
 +    @Override 
 +    public void handle(MouseEvent event) {    
 +        // ... 
 +    } 
 +});
 </​code>​ </​code>​
  
-Un astfel de obiect implementează metoda ''​add()'',​ prin care se indică coordonatele celulei la care se doreşte să se scrie valoarea în cauză.+<​newcolumn>​
  
 <code java> <code java>
-Put.add(family, column, value); +tableContent.setOnMouseClicked( 
-Put.add(family, column, value, timestamp, value);+    (MouseEvent event) -> {    
 +        // ​... 
 +    } 
 +);
 </​code>​ </​code>​
  
-Toţi parametrii sunt în format binar, fiind reponsabilitatea programatorului conversia acestora.+</​columns>​
  
-Transferul propriu-zis al datelor ​se realizează la apelul metodei ​''​put()'', ​pe instanţa ''​HTable'':​+Eliminarea metodei de tratare a evenimentului ​se face prin specificarea unui parametru cu valoarea ​''​null'' ​pentru nodul în cauză, dacă se doreşte ca acesta să nu mai proceseze astfel de evenimente.
  
 <code java> <code java>
-myTable.put(myPut);+tableContent.setOnMouseClicked(null);
 </​code>​ </​code>​
  
-Pentru a se citi date dintr-o tabelă, se foloseşte ​un obiect ​de tip ''​Get''​, care este instanţiat cu identificatorul ​(cheia de rând) a înregistrării ​care se doreşte obţinută, în format binar.+{{ :​laboratoare:​laborator09:​09observer_listener.png?​nolink&​600 }} 
 + 
 +Un filtru de eveniment permite gestiunea evenimentului în timpul etapei de capturare propriu-zisă. Un nod poate avea asociate unul sau mai multe filtre pentru gestiunea unui eveniment. De asemenea un filtru poate fi utilizat pentru unul sau mai multe noduri, pentru unul sau mai multe tipuri de evenimente. Totodată, nodurile părinte pot oferi o procesare de nivel înalt a evenimentului pentru nodurile fiu, interceptându-le astfel ca acestea să nu mai ajungă la ţintă. ​Pentru a gestiona un eveniment în timpul etapei de capturare propriu-zisă, nodul trebuie sa asocieze ​un filtru ​de eveniment, care implementează interfaţa ​''​EventHandler''​. Metoda ''​handle()''​ conţine codul executat la momentul în care evenimentul ajunge la nodul care are filtrul asociat. 
 + 
 +Asocierea unui filtru de eveniment pentru un nod se face prin metoda ''​addEventFilter()'',​ primind ca parametri tipul de eveniment ​şi filtrul propriu-zis. Eliminarea unui filtru de eveniment corespunzător unui nod se face prin metoda ''​removeEventFilter()''​, primind aceeaşi parametri.
  
 <code java> <code java>
-Get myGet = new Get(Bytes.toBytes("​myRow"​));+node.addEventFilter(MouseEvent.MOUSE_CLICKED,​  
 +                    new EventHandler<​MouseEvent>​() { 
 +                        @Override 
 +                        public void handle(MouseEvent) { ... }; 
 +                    });
 </​code>​ </​code>​
  
-Un astfel ​de obiect implementează metoda ''​add()''​, prin care se indică coordonatele celulei ​la care se doreşte să se scrie valoarea în cauză. Metoda ​''​add()'' ​permite specificarea mai multor familii de coloane ​şi a mai multor coloane.+<code java> 
 +EventHandler filter = new EventHandler(<​InputEvent>​() { 
 +    @Override 
 +    public void handle(InputEvent event) { 
 +        // ... 
 +        event.consume();​ 
 +    } 
 +node1.addEventFilter(MouseEvent.MOUSE_PRESSED,​ filter); 
 +node2.addEventFilter(MouseEvent.MOUSE_PRESSED,​ filter); 
 +node.addEventFilter(KeyEvent.KEY_PRESSED,​ filter); 
 +// ... 
 +node.removeEventFilter(KeyEvent.KEY_PRESSED,​ filter); 
 +</​code>​ 
 + 
 +De remarcat faptul că filtrul este definit pentru un tip de eveniment generic (''​InputEvent''​),​ fiind utilizat apoi pentru tratarea unor evenimente specifice (legate de mouse şi de tastatură). 
 + 
 +O metodă de tratare a unui eveniment permite gestiunea evenimentului în timpul etapei de întoarcere la nodul rădăcină. ​Un nod poate avea asociată una sau mai multe metode pentru tratare a unui eveniment. De asemenea, o metodă pentru tratarea unui eveniment poate fi folosită pentru unul sau mai multe noduri, respectiv unul sau mai multe tipuri ​de eveniment. În cazul când o metodă de tratare a unui eveniment de la nivelul nodului fiu nu consumă evenimentul,​ acesta va fi gestionat şi de metoda ​de tratare de la nivelul nodului părinte, oferind un mecanism de gestiune mai general caracteristic tuturor nodurilor fiu. Pentru a gestiona un eveniment în timpul etapei de întoarcere la nodul rădăcină,​ nodul trebuie sa asocieze o metodă de tratare, care implementează interfaţa EventHandler. Metoda ​''​handle()'' ​conţine codul executat la momentul în care evenimentul ajunge ​la nodul care are metoda de tratare asociată. 
 + 
 +Asocierea unei metode de tratare pentru un nod se face prin metoda ''​addEventHandler()'',​ primind ca parametri tipul de eveniment ​şi metoda de tratare propriu-zis. Eliminarea unei metode de tratare corespunzătoare unui nod se face prin metoda ​''​removeEventHandler()''​, primind aceeaşi parametri.
  
 <code java> <code java>
-Get.addFamily(family); +node.addEventHandler(DragEvent.DRAG_ENTERED,​  
-Get.addColumn(family, column);+                     new EventHandler<​DragEvent>​() { 
 +                         @Override 
 +                         ​public void handle(DragEvent) { ... }; 
 +                    });
 </​code>​ </​code>​
  
-Este foarte important să fie indicate exact datele necesare în cadrul aplicaţiei,​ altfel fiind returnat un rând întreg.+<code java> 
 +EventHandler handler = new EventHandler<​InputEvent>​() { 
 +    @Override 
 +    public void handle(InputEvent event) { 
 +        // ... 
 +        event.consume();​ 
 +    }
  
-Filtrarea se poate realiza prin specificarea unui interval de timp, respectiv al unui număr de versiuni (prin metodele ''​setTimeRange()''​ şi ''​setMaxVersions()''​).+node1.addEventHandler(DragEvent.DRAG_EXITED, handler); 
 +node2.addEventHandler(DragEvent.DRAG_EXITED,​ handler); 
 +node.addEventHandler(MouseEvent.MOUSE_DRAGGED,​ handler); 
 +node.removeEventHandler(DragEvent.DRAG_EXITED,​ handler); 
 +</​code>​
  
-Transferul ​propriu-zis al datelor ​se realizează la apelul ​metodei ''​get()'',​ pe instanţa ''​HTable'':​+Şi în acest caz metoda de tratare este definită pentru un tip de eveniment generic urmând a fi folosită pentru tratarea unor evenimente specifice. 
 + 
 +Pentru anumite tipuri de dispozitive mobile, pot fi detectate evenimente de tipul atingerilor,​ operaţiilor de micşorare/​mărire (//eng.// zoom), rotire, derulare (//eng.// scroll) sau glisare (//eng.// swipe). Aceste tipuri de gesturi pot implica unul sau mai multe puncte de contact. Tipul de eveniment generat corespunde gestului pe care îl realizează utilizatorul. 
 + 
 +^  **Gest** ​ ^  **Descriere** ​ ^  **Evenimente generate** ​ ^ 
 +| Rotaţie | Mişcarea unui deget în jurul altuia în sensul acelor de ceasornic sau în sens contrar acelor de ceasornic | ''​ROTATION_STARTED''​\\ ''​ROTATE''​\\ ''​ROTATION_FINISHED''​ | 
 +| Derulare | Mişcare de derulare, pe verticală (sus/jos) sau pe orizontală (stânga/​dreapta) | ''​SCROLL_STARTED''​\\ ''​SCROLL''​\\ ''​SCROLL_FINISHED''​\\ Dacă se foloseşte rotiţa de mouse se generează doar evenimentul ''​SCROLL''​. | 
 +| Glisare | Mişcare de glisare de-a lungul ecranului la stânga, dreapta, în sus sau în jos. Mişcarea pe diagonală nu este recunoscută ca glisare. | ''​SWIPE_LEFT'',​ ''​SWIPE_RIGHT'',​\\ ''​SWIPE_UP'',​ ''​SWIPE_DOWN''​\\ Pentru fiecare gest se generează un singur eveniment de parcurgere. | 
 +| Mărire/​Micşoare | Depărtarea a două degete pentru mărire, respectiv apropierea lor pentru micşorare. | ''​ZOOM_STARTED''​\\ ''​ZOOM''​\\ ''​ZOOM_FINISHED''​ | 
 + 
 +Aşa cum s-a precizat, ţinta celor mai multe gesturi este reprezentată de nodul aflat în centrul tuturor punctelor de apăsare de la începutul gestului respectiv. În situaţia în care există mai mult de un nod aflat la poziţia respectivă,​ ţinta este considerată nodul aflat deasupra celorlalte. 
 + 
 +Unele gesturi pot genera şi alte tipuri de evenimente în plus faţă de cele care erau intenţionate. Operaţiile de glisare pot genera operaţii de derulare în funcţie de amploarea gestului. Totodată, operaţiile de atingere generează atât evenimente de tip ''​TOUCH_PRESSED''​ / ''​TOUCH_RELEASED''​ cât şi evenimente de tip ''​MOUSE_PRESSED''​ / ''​MOUSE_RELEASED''​. În aceste cazuri, este posibil ca nodurile ţintă asociate celor două evenimente să fie diferite. De asemenea, în acest mod, aplicaţiile desktop pot fi portate foarte uşor pe sisteme încorporate ce utilizează ecranul tactil. Pentru ca acelaşi eveniment să nu fie procesat de două ori, trebuie apelată metoda ''​isSynthesized()''​ pentru a se verifica dacă evenimentele nu au fost generate din alte evenimente. În acelaşi scop poate fi folosită metoda ''​isDirect()''​ care indică faptul că evenimentul a fost generat de un gest realizat pe ecranul tactil. Pentru a verifica dacă anumite evenimente nu s-au generat ca urmare a inerţiei unui gest se poate apela metoda ''​isInertia()''​.  
 + 
 +În cazul în care se doreşte ca evenimentele de apăsare a ecranului să fie tratate individual (sau se doreşte implementarea de alte gesturi) pot fi utilizate evenimentele puse la dispoziţie de clasa ''​TouchEvent'',​ ce pot avea tipurile ''​TOUCH_PRESSED'',​ ''​TOUCH_MOVED'',​ ''​TOUCH_STATIONARY''​ şi ''​TOUCH_RELEASED''​. Pentru fiecare apăsare a ecranului (punct de contact) se poate genera un eveniment având acest tip. Un punct de contact este reprezentat de o instanţă a clasei ''​TouchPoint''​ conţinând informaţii despre locaţie, stare şi nodul ţintă al punctului de contact. În cazul apăsărilor concomitente ale ecranului tactil, numărul de evenimente generate poate fi limitat de platforma pe care rulează aplicaţia. 
 + 
 +Un eveniment de apăsare are asociate următoarele elemente: 
 +  * punctul de contact – reprezintă punctul principal de contact asociat evenimentului respectiv;​ 
 +  * numărul de apăsări – numărul punctelor de contact legate de acţiunea de apăsare; 
 +  * lista punctelor de contact – mulţimea punctelor de contact asociate evenimentului de apăsare în cauză; 
 +  * identificatorul mulţimii de evenimente – identificatorul mulţimii ce conţine evenimentul de apăsare; fiecare set de evenimente are un identificator unic care este incrementat pentru fiecare mulţime care este generată ca urmare a unei operaţii de apăsare; evenimentele din mulţime pot avea tipuri diferite sau acelaşi tip astfel că fiecare punct de contact este identificat şi el printr-un identificator unic. 
 + 
 +Nodul ţintă al unui eveniment de apăsare corespunde cu nodul ţintă al punctului de contact, reprezentând controlul cel mai vizibil (de pe nivelul frunză al grafului de scene) de la coordonatele respective. Toate evenimentele asociate unui punct de contact sunt transmise aceluiaşi nod ţintă. Totuşi, un nod care procesează un eveniment poate apela metoda ''​grab()''​ pentru a deveni ţinta respectivului punct de contact , sau poate specifica această ţintă ca parametru al metodei respective: ''​grab(node)''​. De asemenea, metoda ''​ungrab()''​ este folosită pentru a detaşa punctul de contact de ţinta curentă, evenimentele asociate fiind transmise nodului corespunzător locaţiei la care se află punctul de contact. În acest fel, există posibilitatea ca toate evenimentele aparţinând unei anumite mulţimi să fie tratate de acelaşi nod ţintă. 
 + 
 +JavaFX oferă suport şi pentru operaţii de tip drag-and-drop,​ ce implică un transfer de date între două obiecte: sursa gestului şi ţinta gestului, acestea putând fi instanțe ale obiectelor de tip ''​Node''​ şi ''​Scene'',​ putând aparţine aceleiaşi aplicaţii sau unor aplicaţii diferite (una dintre aplicaţii poate să nu fie aplicaţie JavaFX ci o aplicaţie a sistemului de operare).  
 + 
 +O astfel de operaţie este implementată folosind clasa ''​javafx.scene.input.DragEvent''​. Modurile de transfer suportate între sursă şi ţintă sunt ''​COPY'',​ ''​MOVE''​ şi ''​LINK''​.  
 + 
 +Gestul de tip drag and drop poate fi pornit doar din cadrul unui nod sursă prin apelarea metodei ''​startDragAndDrop()''​ care primeşte ca argument tipurile de transfer pe care aceasta le suportă, în cadrul metodei de tratare a evenimentului ''​DRAG_DETECTED''​. Pentru a specifica toate modurile de transfer, se va indica parametrul ''​TransferMode.ANY''​.  
 + 
 +Acceptarea unei operaţii se face în cadrul nodului ţintă prin metoda ''​acceptTransferModes()''​ în cadrul metodei de tratare a avenimentului ''​DRAG_OVER''​ prin specificarea tipurilor de transfer pe care le acceptă. De regulă, se verifică tipul de date pe care îl conţine obiectul pentru care se doreşte să se realizeze operaţia de transfer, conţinut ce poate fi obţinut prin metoda ''​getDragboard()''​.  
 + 
 +Trecerea obiectului pentru care se încearcă operaţia drag and drop deasupra anumitor noduri generează evenimente de tip ''​DRAG_ENTERED''​ sau ''​DRAG_EXITED''​. Astfel, pot fi definite metode de tratare ale acestor evenimente care să schimbe aspectul acestui tip de obiecte pentru a indica faptul că nodul respectiv acceptă sau respinge transferul în cauză.  
 + 
 +Pe lângă conţinutul obiectului se poate verifica şi sursa acestuia prin metoda ''​getGestureSource()''​. În momentul în care obiectul este transferat asupra ţintei, aceasta primeşte un eveniment de tip ''​DRAG_DROPPED''​ în care pot fi preluate informaţiile pe care le conţine marcând rezultatul operaţiei prin metoda ''​setDropCompleted()''​ care primeşte un argument de tip ''​boolean''​.  
 + 
 +Când gestul drag and drop este terminat, sursa primeşte un eveniment ''​DRAG_DONE''​ care poate fi tratat în sensul că pentru anumite moduri de transfer trebuie realizate operaţii suplimentare . 
 + 
 +JavaFX permite şi transferul de controale definite de utilizator însă în acest caz tipul de date trebuie să fie specificat explicit şi trebuie să fie serializabil. 
 + 
 +==== Conținut Multimedia ==== 
 + 
 +=== Efecte Vizuale === 
 + 
 +JavaFX definește mai mult efecte vizuale în pachetul ''​javafx.scene.effect'',​ derivate din clasa ''​Effect''​. 
 + 
 +== Blend == 
 + 
 +Efectul de combinare (//eng.// blend) realizează un amestec între mai multe surse, folosind una dintre modalitățile predefinite pentru realizarea acestei operații: ''​SRC_ATOP'',​ ''​MULTIPLY'',​ ''​SRC_OVER''​ (din interfața ''​BlendMode''​). 
 + 
 +În cazul în care metoda ''​setBlendMode()''​ este apelată pentru un nod, elementele care sunt îmbinate sunt nodul care este redat (intrarea de nivel superior) și toate elementele care se găsesc sub acesta (intrarea de nivel inferior). Delimitarea intrării de nivel inferior se bazează pe mai multe reguli: 
 +  * sunt incluse toate elementele inferioare (folosind ordinea Z); 
 +  * dacă grupul are definită o modalitate de combinare, procesul este terminat; 
 +  * dacă grupul are modalitatea de combinare implicită, toate elementele aflate sub grup sunt incluse recursiv, folosind aceleași reguli; 
 +  * dacă s-a ajuns la nodul rădăcină,​ se include fundalul scenei. 
 + 
 +<note tip>În situația în care fundalul scenei, care este de regulă o culoare opacă, este inclus în intrarea de nivel inferior, modalitățile de combinare ''​SRC_ATOP''​ și ''​SRC_OVER''​ sunt echivalente și nu au nici un fel de efect.</​note>​ 
 + 
 +== Bloom == 
 + 
 +Efectul de înflorire (//eng.// bloom) face ca porțiunile de imagine mai deschise să pară că strălucesc. De regulă, se definește un prag, cuprins între 0.0 și 1.0, acesta fiind transmis ca parametru al metodei ''​setThreshold()''​ a unui obiect de tip ''​Bloom''​. 
 + 
 +Un astfel de efect este asociat unui nod prin intermediul metodei ''​setEffect()''​. 
 + 
 +== Blur == 
 + 
 +Efectul de estompare (//eng.// blur) este utilizat pentru a capta atenția asupra anumitor obiecte.  
 + 
 +În JavaFX pot fi aplicate efecte de tip: 
 +  * ''​BoxBlur''​ - efect de estompare ce folosește un nucleu de filtrare de tip cutie, cu valori configurabile independent ale ambelor dimensiuni pentru a controla cantitatea de estompare aplicată unui obiect precum și un parametru ''​Iterations''​ care gestionează calitatea estompării obținute; aceste valori sunt specificate prin metodele ''​setWidth()'',​ ''​setHeight()'',​ respectiv ''​setIterations()'';​ 
 +  * ''​MotionBlur''​ - efect de estompare de tip Gauss, oferind posibilitatea de configurare a razei și a unghiului pentru a crea senzația de obiect în mișcare; aceste valori sunt specificate prin metodele ''​setRadius()'',​ respectiv ''​setAngle()'';​ 
 +  * ''​GaussianBlur''​ - efect de estompare pe baza unui algoritm Gauss, cu posibilitatea de configurare a razei; această valoare poate fi specificată prin metoda ''​setRadius()''​ dar poate fi și omisă; 
 + 
 +Toate efectele de tip estompare pot fi asociat unui nod prin intermediul metodei ''​setEffect()''​. 
 + 
 +== Drop Shadow == 
 + 
 +Un efect de tip umbră exterioară (//eng.// drop shadow) realizeză o umbră a conținutului pe care este aplicat. 
 + 
 +Este permisă specificarea culorii, razei, distanței (pe ambele axe de coordonate) precum și a altor parametri, prin metodele ''​setColor()'',​ ''​setRadius()'',​ ''​setOffsetX()'',​ ''​setOffsetY()''​. 
 + 
 +<note tip>​Culoarea asociată efectului de tip umbră exterioară trebuie să fie mai deschisă cu câteva nuanțe decât culoarea de fundal.</​note>​ 
 + 
 +<note tip>În cazul în care există mai multe obiecte în cadrul scenei asupra cărora s-a aplicat un efect de tip umbră exterioară,​ este recomandat ca pentru toate să se folosească aceeași orientare, pentru a da impresia unei surse de lumină ce provine dintr-o unică direcție.</​note>​ 
 + 
 +== Inner Shadow == 
 + 
 +Un efect de tip umbră interioară (//eng.// inner shadow) realizează o umbră înăuntrul marginilor conținutului pe care este aplicat. 
 + 
 +Este permisă specificarea culorii, razei, distanței (pe ambele axe de coordonate) precum și a altor parametri, prin metodele ''​setColor()'',​ ''​setRadius()'',​ ''​setOffsetX()'',​ ''​setOffsetY()''​ 
 + 
 +== Reflection == 
 + 
 +Efectul de tip reflexie (//eng.// reflection) redă o copie reflectată a conținutului pe care este aplicat, plasând-o sub acesta. 
 + 
 +Proprietățile unui astfel de efect sunt opacitatea superioară și inferioară,​ fracția de reflexie și distanța la care este redată, acestea putând fi specificate prin metodele ''​setTopOpacity()'',​ ''​setBottomOpacity()'',​ ''​setFraction()'',​ ''​setTopOffset()''​. 
 + 
 +== Lightning == 
 + 
 +Efectul de iluminare (//eng.// lightning) simulează o sursă de lumină care acționează asupra conținutului pe care este aplicat pentru a da obiectelor plate o aparență mai realistică,​ tridimensională. 
 + 
 +Configurarea unui astfel de efect implică specificarea:​ 
 +  * sursa de lumină, prin metoda ''​setLight()''​ ce primește ca parametru un obiect de tip ''​Light''​ 
 +    * ''​Light.Distant''​ - sursă de lumină distantă;​ 
 +    * ''​Light.Point''​ - sursă de lumină având o poziție specificată prin coordonatele (x, y, z); 
 +    * ''​Light.Spot''​ - sursă de lumină având o poziție specificată prin coordonatele (x, y, z), o direcție și un focus; 
 +  * suprafața de scalare, prin metoda ''​setSurfaceScale()'';​ 
 +  * constanta de difuzie, prin metoda ''​setDiffuseConstant()'';​ 
 +  * constanta și exponentul de reflexie, prin metodele ''​setSpecularConstant()'',​ respectiv ''​setSpecularExponent()''​. 
 + 
 +== Perspective == 
 + 
 +Efectul de perspectivă (//eng.// perspective) transformă un obiect bidimensional în spațiul tridimensional,​ realizând o transformare între două dreptunghiuri,​ menținând proprietatea de linii drepte a laturilor, fără a păstra și paralelismul acestora. 
 + 
 +Parametrii ce trebuie specificați în cazul unei astfel de transformări sunt coordonatele (x, y) pentru cele patru colțuri: 
 +  * stânga jos - metodele ''​setLlx()'',​ ''​setLly()'';​ 
 +  * dreapta jos - metodele ''​set Lrx()'',​ ''​setLry()'';​ 
 +  * stânga sus - metodele ''​setUlx()'',​ ''​setUly()'';​ 
 +  * dreapta sus - metodele ''​setUrx()'',​ ''​setUry()''​. 
 + 
 +<note tip>​Efectul nu actualizează coordonatele pentru evenimentele asociate unui astfel de control grafic, comportamentul nefiind precizat într-o astfel de situație.</​note>​ 
 + 
 +== Înlănțuirea Efectelor == 
 + 
 +Unele efecte dispun de proprietatea ''​inputProperty''​ care poate fi utilizată pentru realizarea unui lanț de efecte. Astfel, metoda ''​setInput()''​ primește ca parametru un alt efect care va fi realizat înaintea aplicării ​propriu-zise a efectului pentru care se apelează. 
 + 
 +Un lanț de efecte are o structură arborescentă,​ întrucât unele efecte au două intrări în timp ce alte efecte nu au nici o intrare. 
 + 
 +=== Transformări 2D / 3D === 
 + 
 +JavaFX permite realizarea de transformări,​ acestea fiind conținute în pachetul ''​javafx.scene.transform'',​ ele fiind derivate din clasa ''​Transform''​ și din subclasa acesteia ''​Affine'',​ care definește conceptul de transformări înrudite. Acestea sunt bazate pe algebra euclidiană și realizează o asociere liniară (prin utilizarea unor matrici) între două sisteme de coordonate, menținând caractere ale liniilor cum ar fi proprietatea de a fi drepte și paralelismul. 
 + 
 +O transformare schimbă locația unui element grafic într-un sistem de coordonate în funcție de anumiți parametri. 
 + 
 +În JavaFX, sunt definite mai multe tipuri de transformări,​ ce pot fi aplicate unui singur nod sau unui grup de noduri, astfel de operații putând fi realizate independent sau grupate împreună:​ 
 +  * translatări 
 +  * rotiri 
 +  * scalări 
 +  * tăieri 
 + 
 +Transformările pot fi realizate de-a lungul celor trei coordonate, oferind posibilitatea de a crea transformări 3D. În acest scop, trebuie folosită și camera de perspectivă. 
 + 
 +Un obiect 3D poate fi redat prin tehnica Z-buffering care asigură o perspectivă cât mai apropată de realitate: un obiect solid aflat în prim plan blochează elementele din spatele său. O astfel de proprietate poate fi gestionată prin intermediul metodei ''​setDepthTest()''​ care primește ca parametri valori din interfața ''​DepthTest'':​ ''​ENABLE''​ și ''​DISABLE''​. 
 + 
 +== Translatarea == 
 + 
 +O transformare de tip translatare mută un nod dintr-o locație în alta de-a lungul axelor relativ la poziția sa. 
 + 
 +Metodele ce trebuie apelate pe un obiect de tip ''​Translate''​pentru a realiza o translatare de-a lungul axelor sunt: ''​setX()'', ​ ''​setY()'',​ ''​setZ()'',​ acestea primind ca parametri valori reale exprimând cantitatea cu care se modifică poziția curentă, de-a lungul fiecărei coordonate. 
 + 
 +Alternativ, pentru obiectul de tip element grafic se pot apela metodele ''​setTranslateX()'',​ ''​setTranslateY()''​ și ''​setTranslateZ()''​. 
 + 
 +== Rotația == 
 + 
 +O transformare de tip rotație mută un nod în jurul unui punct considerat pivot al scenei. 
 + 
 +Metodele ce trebuie apelate pe un obiect de tip ''​Rotate''​ pentru a realiza o rotație sunt: 
 +  * ''​setAxis()'',​ ce primește ca parametru axa din sistemul de coordonate în jurul căreia se va realiza rotația (''​Rotate.X_AXIS'',​ ''​Rotate.Y_AXIS'',​ ''​Rotate.Z_AXIS''​);​ 
 +  * ''​setAngle()'',​ ce primește o valoare reală indicând unghiul cu care se va reaiza rotația; 
 +  * ''​setPivotX()'',​ ''​setPivotY()'',​ ''​setPivotZ()'',​ indicând coordonatele punctului pivot. 
 + 
 +== Scalarea == 
 + 
 +O transformare de tip scalare face ca un nod să apară mai mic sau mai mare, în funcție de factorul de scalare. Printr-o astfel de transformare,​ dimensiunile de-a lungul axelor sunt multiplicate cu factorul de scalare. Operația de scalare ​se realizează ​în jurul unui punct considerat pivot. 
 + 
 +Metodele ce trebuie apelate pe un obiect de tip ''​Scale''​ pentru a realiza o scalare sunt: ''​setX()'',​ ''​setY()''​ și ''​setZ()''​ ce indică factorii de multiplicare de-a lungul celor trei axe de coordonate. 
 + 
 +== Tăierea == 
 + 
 +O transformare de tip tăiere rotește o axă astfel încât axele Ox și Oy să nu mai fie perpendiculare,​ valorile coordonatelor fiind modificate prin valorile specificate. 
 + 
 +Metodele ce trebuie apelate pe un obiect de tip ''​Shear''​ pentru a realiza o scalare sunt: ''​setX()''​ și ''​setY()''​ ce indică factorii de multiplicare cu care sunt deplasate coordonatele în sensul pozitiv al axelor. 
 + 
 +== Combinarea Transformărilor == 
 + 
 +Mai multe efecte pot fi combinate prin specificarea unui lanț de transformări ordonat. 
 + 
 +Asocierea unei transformări se face prin intermediul metodelor ''​add()''​ / ''​addAll()''​ apelabilă pe lista observabilă de transformări asociată nodului curent, obținută ca valoare returnată de metoda ''​getTransforms()''​. 
 + 
 +=== Animații === 
 + 
 +JavaFX oferă programatorului posibilitatea de a crea animaţii, sub forma tranziţiilor sau a animaţiilor bazate pe timp, implementate în clasele ''​Transition''​ şi ''​Timeline''​ din pachetul ''​javafx.animation.Animation''​. 
 + 
 +Tranziţiile implementează animaţiile asociindu-le o anumită cronologie (intern), acestea putând fi executate secvenţial sau în paralel.  
 + 
 +În JavaFX, au fost implementate mai multe tipuri de tranziţii:​ 
 +  * ''​FadeTransition''​ – este folosită pentru a schimba opacitatea unui nod de-a lungul unei secvenţe de timp; constructorul primeşte durata (exprimată în milisecunde) şi nodul pe care se va realiza animaţia; ulterior se pot specifica valorile extreme ale transparenţei (prin metodele ''​setFromValue()''​ respectiv ''​setToValue()''​),​ dacă va fi reluată după terminarea ei (metoda ''​setAutoReverse()''​) şi numărul de rulări (metoda ''​setCycleCount()''​);​ rularea animaţiei se face prin metoda ''​play()'';​ 
 +  * ''​PathTransition''​ – este folosită pentru a muta un nod de-a lungul unei căi într-o anumită perioadă de timp; pentru o astfel de animaţie se specifică, suplimentar,​ calea (prin metoda ''​setPath()''​ care primeşte ca parametru un obiect de tip ''​Path''​ - care se construieşte din obiecte de tip ''​CubicCurveTo''​ care defineşte o curbă Bézier între elementul curent şi un anumit punct (x, y) trecând prin alte două puncte de control (''​controlX<​sub>​1</​sub>'',​ ''​controlY<​sub>​1</​sub>''​) şi (''​controlX<​sub>​2</​sub>'',​ ''​controlY<​sub>​2</​sub>''​) date ca parametrii ​la construirea obiectului) precum şi orientarea nodului respectiv de-a lungul căii (valorile posibile sunt exprimate în ''​PathTransition.OrientationType''​);​ 
 +  * ''​FillTransition''​ – schimbă culoarea suprafeţei de umplere a unui nod de-a lungul unui interval de timp; valorile limită trebuie să aibă semnificaţia unor culori; 
 +  * ''​StrokeTransition''​ – schimbă culoarea conturului unui nod de-a lungul unui interval de timp; valorile limită trebuie să aibă semnificaţia unei culori; 
 +  * ''​PauseTransition''​ – folosită ca perioadă de aşteptare între tranziţii, în cadrul unei tranziţii secvenţiale sau apelată în cadrul ''​Animation.onFinished()'';​ 
 +  * ''​RotateTransition''​ – utilizată pentru rotirea unui nod cu un anumit unghi (dat în grade) de-a lungul unei perioade de timp; 
 +  * ''​ScaleTransition''​ – folosită pentru scalarea unui nod cu anumite valori pe axele ''​Ox'',​ ''​Oy'',​ ''​Oz'';​ pot fi folosiţi atât factori de multiplicare cât şi intervale de valori (pentru fiecare axă în parte); 
 +  * ''​TranslateTransition''​ – modifică poziţia nodului între anumite coordonate (''​x<​sub>​1</​sub>'',​ ''​y<​sub>​1</​sub>'',​ ''​z<​sub>​1</​sub>''​) → (''​x<​sub>​2</​sub>'',​ ''​y<​sub>​2</​sub>'',​ ''​z<​sub>​2</​sub>''​) sau de la poziţia curentă la o poziţie obţinută prin intermediul unor multiplicatori;​ 
 +  * ''​ParallelTransition''​ – utilizată spre a executa mai multe tranziţii simultan; spre exemplu, dacă se definesc mai multe tranziţii asupra unui nod, acestea pot fi adăugate unui obiect ''​ParallelTransition''​ prin metoda ''​addAll()''​ aplicabilă listei componentelor acestuia (obţinută cu metoda ''​getChildren()''​) pentru a fi executate în paralel; durata tranziţiei obţinute va fi dată de durata celei mai lungi tranziţii din cadrul listei asociate; 
 +  * ''​SequentialTransition''​ – utilizată pentru a executa mai multe tranziţiile secvenţial,​ în ordinea în care au fost adăugate; durata tranziţiei este dată de suma duratelor tranziţiilor componente. 
 + 
 +În cadrul animaţiilor bazate pe timp, se consideră că nodul ce va fi animat este definit de anumite proprietăţi care pot fi modificate automat de către sistem atâta vreme cât se precizează valorile sale extreme (de început şi de sfârşit, numite cadre cheie – //eng.// key frames). De asemenea, astfel de obiecte (implementate de clasa ''​Timeline''​) au posibilitatea de a fi oprite (cu sau fără posibilitatea reluării animaţiei din punctul la care au fost oprite), de a fi redate în sens invers sau de a fi repetate. 
 + 
 +Un obiect ''​KeyFrame''​ primeşte la creare ca parametru durata animaţiei, metoda de tratare a evenimentului de tip terminare a anumației şi unul sau mai multe obiecte de tip ''​KeyValue''​ (care specifică un atribut ce se doreşte modificat în intervalul respectiv și valoarea cu care este modificat). 
 + 
 +JavaFX oferă posibilitatea de a folosi obiecte de interpolare (fie existente, fie definite de utilizator),​ specificând diferite poziţii intermediare ale obiectului pentru care se realizează animaţia. Un obiect ''​Interpolator''​ este specificat pentru un obiect ''​KeyValue''​ atunci când este creat. În cazul în care nu se specifică nici un obiect de tip ''​Interpolator'',​ va fi folosit în mod implicit valoarea ''​Interpolator.LINEAR''​.  
 + 
 +Tipurile de interpolare predefinite sunt ''​Interpolator.LINEAR'',​ ''​Interpolator.DISCRETE'',​ ''​Interpolator.EASE_BOTH'',​ ''​Interpolator.EASE_IN'',​ ''​Interpolator.EASE_OUT''​.  
 + 
 +Dacă utilizatorul doreşte să construiască un obiect de tip interpolare,​ trebuie să definească o clasă (ce extinde ''​Interpolator''​) în care trebuie să definească metoda ''​curve()'',​ folosită pentru a determina fracţia în implementarea ​metodei ''​interpolate()''​. 
 + 
 +=== Redarea Conținutului Audio/Video === 
 + 
 +Pachetul ''​javafx.scene.media''​ oferă funcţionalităţi pentru redarea de conţinut multimedia în cadrul aplicaţiei JavaFX. 
 + 
 +Formatele suportate în mod curent sunt: 
 +  * **audio**: MP3; AIFF şi WAV conţinând PCM (Pulse Code Modulation) necomprimat;​ MPEG-4 folosind AAC (Advanced Audio Coding); 
 +  * **video**: FLV în care formatul video este VP6, iar cel audio este MP3; MPEG-4 cu compresie video H.264/AVC (Advanced Video Coding). 
 + 
 +Decodificarea unor tipuri de compresii audio sau video  se bazează ​pe motoarele multimedia ale sistemelor de operare. 
 + 
 +<​note>​Decodificarea unor formate AAC sau H.264/AVC au unele limitări dependente de platformă. JavaFX nu îşi propune să trateze toate formatele multimedia şi tipurile de codificare din aceste containere, ci să ofere un comportament consistent a acestor obiecte pe toate platformele pe care aceasta a fost implementată.</​note>​ 
 + 
 +Printre funcţionalităţile pe care le pune la dispoziţie pachetul JavaFX pentru conţinut multimedia se numără redarea tipurilor de formate amintite, suport pentru protocoalele HTTP şi FILE, descărcarea de conţinut în mod progresiv, căutare, folosirea unei zone de memorii tampon (//eng.// buffer) şi funcţii legate de redare (play, pause, stop, volume, mute, balance, equalizer). ​ Totodată, poate fi redat conţinut aflat în Internet, parametrii de redare (rata de biţi pentru audio, rezoluţia pentru video) fiind ajustaţi în funcţie de condiţiile existente. Capabilităţile multimedia sunt extinse la comutarea între fluxuri alternative, ​aşa cum sunt specificate în cadrul listei de redare (//eng.// playlist) în funcţie de limitările impuse de reţea. Pentru un flux, se definește o listă de redare precum şi o listă de segmente în care fluxul este corupt. Fluxul poate avea formatul MP3 sau MPEG-TS ce conţine o multiplexare între conţinut audio AAC şi conţinut video H.264. 
 + 
 +Conceptul multimedia al JavaFX se bazează pe următoarele clase, care trebuie utilizate împreună pentru a implementa funcţionalitatea de redare a conţinuturilor de acest tip: 
 +  * ''​Media'' ​– o resursă multimedia, conţinând informaţii (metadate) despre aceasta; 
 +  * ''​MediaPlayer''​ – componenta care oferă funcţionalităţile pentru redarea conţinutului multimedia respectiv;​ 
 +  * ''​MediaView''​ – un obiect de tip ''​Node''​ care suportă animaţii şi efecte. 
 + 
 +**Clasa ''​MediaPlayer''​** oferă toate atributele şi metodele necesare pentru controlul redării de conţinut multimedia.  
 + 
 +Astfel, se poate preciza proprietatea ''​AUTO_PLAY'',​ se poate apela direct metoda ''​play()''​ sau se poate specifica explicit numărul de repetări ale conţinutului respectiv.  
 + 
 +Atributele ''​VOLUME''​ şi ''​BALANCE''​ pot fi folosite pentru ajustarea nivelului de redare şi a echilibrului stânga-dreapta. Pentru atributul ''​VOLUME''​ se pot specifica valori cuprinse între 0.0 şi 1.0, iar pentru ''​BALANCE''​ valori cuprinse între -1.0 (doar stânga), 0 (centru) şi 1.0 (doar dreapta).  
 + 
 +Alte metode ce pot fi apelate pentru redarea conţinutului sunt ''​pause()''​ şi ''​stop()''​.  
 + 
 +Utilizatorul îşi poate defini mai multe metode de tratare pentru evenimente legate de starea obiectului care redă conţinutul şi anume: fluxul de date este transferat în zona tampon de memorie, redarea conţinutului s-a terminat, stagnare datorată faptului că datele nu au fost primite suficient de rapid spre a asigura redare continuă, producerea de erori definite în clasa ''​MediaErrorEvent''​. 
 + 
 +**Clasa ''​MediaView''​** extinde clasa ''​Node''​ şi oferă o vizualizare a conţinutului ce este redat, fiind responsabilă mai mult pentru efecte şi transformări.  
 + 
 +Atributul ''​mediaPlayer''​ specifică obiectul ''​MediaPlayer''​ care se ocupă cu redarea conținutului. 
 + 
 +Alte atribute sunt ''​onError'',​ indicând metoda de tratare care va fi invocată când se produce vreo eroare, ''​preserveRatio''​ care specifică faptul că raportul lăţime/​înălţime trebuie păstrat în cazul operaţiilor de scalare, ''​smooth''​ pentru ca operaţia de scalare să folosească un algoritm de filtrare mai performant (aceasta are loc în momentul în care conţinutul multimedia trebuie ajustat la dimensiunile obiectului care îl conţine, dimensiuni specificate de atributele ''​fitHeight''​ şi ''​fitWidth''​),​ ''​viewport''​ pentru cadrul de vizualizare al conţinutului multimedia, respectiv coordonatele ''​x''​ şi ''​y''​ ale originii obiectului.
  
 <code java> <code java>
-Result myResult ​= myTable.get(myGet);+Scene scene = new Scene(new Group(), 500, 500); 
 +String source = getParameters().getRaw().get(0); 
 +Media media = new Media(source);​ 
 +// Media media = new Media(MEDIA_URL);​ 
 +MediaPlayer mediaPlayer = new MediaPlayer(media);​ 
 +mediaPlayer.setAudio(true);​ 
 +MediaView mediaView = new MediaView(mediaPlayer);​ 
 +((Group)scene.getRoot()).getChildren().add(mediaView);
 </​code>​ </​code>​
  
-Obţinerea rezultatelor dintr-un ​obiect de tip ''​Result''​ se face prin metoda ''​getValue()'',​ specificându-se denumirea familiei de coloane ​şi a coloanei. Alte metode sunt ''​getRow()''​ pentru obţinerea identificatorului unei înregistrări, ''​isEmpty()''​ pentru ​a verifica dacă rezultatul este vid, ''​size()'' ​pentru ​a obţine numărul de celule ​şi ''​containsColumn(family:​column)''​ pentru a verifica existenţa unei coloane.+Unui obiect de tip ''​MediaView'' ​trebuie să i se adauge controale grafice din categoria controalelor JavaFX astfel încât utilizatorul să aibă funcţionalitatea pe care o oferă orice produs ce redă conţinut multimedia ​(cronometru ​şi bară de progres care indică momentul la care s-a ajuns, un buton pentru ​redare conţinut / oprire cu posibilitatea reluării sau nu precum ​şi un control pentru reglarea volumului). 
  
-Un obiect ''​HTable'' ​trebuie întotdeauna închis dacă nu mai este necesar sau atunci când s-a produs ​o excepţie (fiind plasat ​de regulă pe ramura ​''​catch'', ​operaţiile pe tabela ​respectivă ​fiind plasate pe ramura ​''​try''​):​+În implementarea acestor cerinţe funcţionale,​ pot fi utilizate metodele: 
 +  * ''​mediaPlayer.getStatus()''​ care întoarce starea curentă a obiectului ''​MediaPlayer'',​ valorile pe care le poate întoarce fiind ''​Status.UNKNOWN'',​ ''​Status.HALTED'',​ ''​Status.PLAYING'',​ ''​Status.PAUSED'',​ ''​Status.READY''​ sau ''​Status.STOPPED'';​ 
 +  * ''​mediaPlayer.seek()''​ care stabileşte ca redarea conţinutului să fie făcută începând de la momentul indicat ca parametru;​ 
 +  * ''​mediaPlayer.getStartTime()''​ care identifică momentul de început al conţinutului multimedia;​ 
 +  * ''​mediaPlayer.setCycleCount()''​ care precizează numărul de redări. 
 + 
 +Metodele de oportunitate pentru gestiunea evenimentelor ce pot apărea în procesul de redare al conţinutului sunt ''​setOnPlaying()'',​ ''​setOnPaused()'',​ ''​setOnReady()'',​ ''​setOnEndOfMedia()'',​ toate primind ca argument un obiect ​de tip ''​Runnable''​, reprezentând fire de execuţie în care sunt realizate astfel de operaţii. 
 + 
 +===== Dezvoltarea unei Interfețe Grafice în mod vizual ===== 
 + 
 +==== FXML ==== 
 + 
 +FXML reprezintă un limbaj bazat pe XML care oferă structura necesară pentru dezvoltarea unei interfeţe cu utilizatorul,​ separând-o de logica aplicaţiei. Astfel, se poate modifica aspectul grafic al unei aplicații fără a fi necesară compilarea codului sursă, putându-se obține interfețe cu utilizatorul complexe fără a avea cunoștințe referitoare la limbajul de programare Java. 
 + 
 +Deşi nu respectă în mod necesar o anumită schemă, FXML are o structură de bază predefinită. Astfel, cele mai multe clase JavaFX pot fi utilizate ca elemente şi cele mai multe proprietăţi (ale unor componente de tip JavaBeans) pot fi folosite ca atribute.  
 + 
 +Dintr-o perspectivă a arhitecturii MVC (Model View Controller),​ fişierul FXML care conţine descrierea interfeţei cu utilizatorul reprezintă partea de vizualizare. Controlul ​este realizat prin clasele Java (implementând opțional interfața ''​Initializable'',​ responsabilă cu gestiunea unui fișier ''​.fxml''​),​ iar modelul va fi reprezentat prin obiecte domeniu (definite în context Java) ce se asociază vizualizării prin control.  
 + 
 +FXML este extrem de util în special pentru interfeţele cu utilizatorul ce conţin grafuri de scene complexe, de dimensiuni mari, formulare, animaţii complicate, precum şi pentru interfeţe statice (formulare, controale, tabele). Pot fi definite şi interfeţe dinamice prin utilizarea de scripturi. 
 + 
 +Utilizarea FXML implică numeroase beneficii:​ 
 +  * are o sintaxă similară cu XML, punând la dispoziţia diferiţilor dezvoltatori un mecanism familiar pentru a construi interfeţe grafice; 
 +  * FXML nu este un limbaj compilat, astfel încât proiectul nu trebuie reconstruit ​atunci când se produc modificări ca acestea ​să fie vizibile; 
 +  * graful de scene este mai transparent în FXML, facilitând atât construirea cât şi menţinerea interfeţei cu utilizatorul;​ 
 +  * conţinutul unui fişier FXML poate fi localizat pe măsură ce este parcurs; acest lucru nu se întâmplă în cazul codului sursă dezvoltat în limbajul de programare Java unde conţinutul fiecărui element trebuie modificat în mod manual (se obţine o referinţă către el după care se apelează metoda de stabilire ​a proprietăţii corespunzătoare);​ 
 +  * FXML este compatibil cu orice limbaj JVM (Java Virtual Machine) ca: Java, Scala, Clojure; 
 +  * FXML nu este limitat doar la partea de vizualizare a arhitecturii MVC, ci se pot construi servicii, sarcini sau obiecte domeniu, existând şi o integrare ​ cu limbaje pentru scripturi (ca JavaScript). 
 + 
 +În versiunea 2.2 a JavaFX au fost introduse câteva facilităţi: 
 +  * utilizarea ''​\''​ pentru a prefixa caracterele speciale; 
 +  * definirea unei variabile implicite pentru controller spre a documenta spațiul de nume, realizând astfel o legătură cu interfața grafică; 
 +  * constructor pentru clasa ''​FXMLLoader'',​ ca alternativă a metodei statice ''​load()'';​ 
 +  * instanțierea clasei controller poate fi particularizată,​ prin specificarea unei fabrici în obiectul ''​FXMLLoader'',​ astfel încât construirea unei astfel ​de clase este delegată către acesta; 
 +  * foi de stil mai ușor de utilizat; 
 +  * posibilitatea de definire a metodelor de tratare a evenimentelor în cadrul clasei controller, fără parametri;​ 
 +  * eticheta ​''​<​fx:​constant>​'' ​înlesneşte procesul de căutare a constantelor, astfel încât constanta ''​java.lang.Double.NEGATIVE_INFINITY''​ definită în Java poate fi referită ca ''<​Double fx:​constant="​NEGATIVE_INFINITY"/>'';​ 
 +  * accesul la sub-clasele care asigură controlul unor noduri definite ca elemente ale scenei din fișierul FXML a fost îmbunătăţit – pentru fiecare nod se pot defini clase în cadrul cărora sunt tratate evenimente; în cazul în care acesta conţine la rândul său alte noduri, atunci când acestea sunt create se vor construi şi sub-clasele care asigură controlul (în cadrul metodei ''​initialize()''​);​ 
 +  * iniţializarea claselor care asigură controlul se face prin mecanismul de reflectare, instanţa clasei ''​FXMLLoader''​ identificând automat metoda ''​initialize()'' ​pe care o şi apelează; în cazul în care nu este publică, pentru această metodă trebuie folosită adnotarea ''​@FXML'';​ 
 +  * uşurinţa în realizarea de noi controale FXML – prin intermediul metodelor ''​setRoot()''​ şi ''​setController()'',​ codul sursă care le apelează poate stabili valori pentru nodul rădăcină, ​respectiv ​pentru obiectul care se ocupă de control astfel încât aceste operaţii nu mai trebuie realizate de către ​''​FXMLLoader'';​ se pot dezvolta astfel controale care pot fi reutilizate. 
 + 
 +=== Exemplu === 
 + 
 +O interfață grafică pentru procesul de autentificare în cadrul unei aplicații poate fi realizată prin intermediul unui fișier FXML: 
 + 
 +<file xml authentication.fxml>​ 
 +<?xml version="​1.0"​ encoding="​UTF-8"?>​ 
 + 
 +<?import java.lang.*?>​ 
 +<?import java.net.*?>​ 
 +<?import java.util.*?>​ 
 +<?import javafx.geometry.*?>​ 
 +<?import javafx.scene.control.*?>​ 
 +<?import javafx.scene.layout.*?>​ 
 +<?import javafx.scene.paint.*?>​ 
 + 
 +<​AnchorPane fx:​id="​AnchorPane"​ maxHeight="​-Infinity"​ maxWidth="​-Infinity"​ minHeight="​-Infinity"​ minWidth="​-Infinity"​ prefHeight="​128.0"​ prefWidth="​336.0000999999975"​ style="​-fx-background-color:​ beige;"​ xmlns="​http://​javafx.com/​javafx/​8"​ xmlns:​fx="​http://​javafx.com/​fxml/​1"​ fx:​controller="​ro.pub.cs.aipi.lab09.controller.Authentication">​ 
 +  <​children>​ 
 +    <​GridPane layoutX="​15.0"​ layoutY="​8.0"​ prefWidth="​309.0">​ 
 +      <​children>​ 
 +        <Label text="​User name:" GridPane.columnIndex="​0"​ GridPane.rowIndex="​0"​ /> 
 +        <Label text="​Password:"​ GridPane.columnIndex="​0"​ GridPane.rowIndex="​1"​ /> 
 +        <​TextField fx:​id="​usernameTextField"​ prefWidth="​200.0"​ GridPane.columnIndex="​1"​ GridPane.rowIndex="​0"​ /> 
 +        <​PasswordField fx:​id="​passwordTextField"​ prefWidth="​200.0"​ GridPane.columnIndex="​1"​ GridPane.rowIndex="​1"​ /> 
 +        <HBox prefHeight="​100.0"​ prefWidth="​200.0"​ spacing="​5.0"​ GridPane.columnIndex="​1"​ GridPane.columnSpan="​2147483647"​ GridPane.rowIndex="​2">​ 
 +          <​children>​ 
 +            <Button mnemonicParsing="​false"​ onAction="#​okButtonHandler"​ text="​OK"​ /> 
 +            <Button mnemonicParsing="​false"​ onAction="#​cancelButtonHandler"​ text="​Cancel"​ /> 
 +          </​children>​ 
 +          <​padding>​ 
 +            <Insets bottom="​5.0"​ left="​5.0"​ right="​5.0"​ top="​5.0"​ /> 
 +          </​padding>​ 
 +        </​HBox>​ 
 +        <HBox id="​rezultat"​ prefHeight="​100.0"​ prefWidth="​200.0"​ GridPane.columnIndex="​0"​ GridPane.columnSpan="​2147483647"​ GridPane.rowIndex="​3">​ 
 +          <​children>​ 
 +            <Label fx:​id="​errorLabel"​ textFill="​RED"​ /> 
 +          </​children>​ 
 +        </​HBox>​ 
 +      </​children>​ 
 +      <​columnConstraints>​ 
 +        <​ColumnConstraints hgrow="​SOMETIMES"​ maxWidth="​155.0"​ minWidth="​10.0"​ prefWidth="​114.0"​ /> 
 +        <​ColumnConstraints hgrow="​SOMETIMES"​ maxWidth="​206.0"​ minWidth="​10.0"​ prefWidth="​195.0"​ /> 
 +      </​columnConstraints>​ 
 +      <​rowConstraints>​ 
 +        <​RowConstraints maxHeight="​30.0"​ minHeight="​10.0"​ prefHeight="​30.0"​ vgrow="​SOMETIMES"​ /> 
 +        <​RowConstraints maxHeight="​30.0"​ minHeight="​10.0"​ prefHeight="​30.0"​ vgrow="​SOMETIMES"​ /> 
 +        <​RowConstraints maxHeight="​30.0"​ minHeight="​10.0"​ prefHeight="​30.0"​ valignment="​CENTER"​ vgrow="​SOMETIMES"​ /> 
 +        <​RowConstraints maxHeight="​30.0"​ minHeight="​10.0"​ prefHeight="​30.0"​ vgrow="​SOMETIMES"​ /> 
 +      </​rowConstraints>​ 
 +    </​GridPane>​ 
 +  </​children>​ 
 +</​AnchorPane>​ 
 +</​file>​ 
 + 
 +Pe baza acestei ierarhii de nodurilor din fișierul FXML, se poate construi graful de scene: 
 + 
 +{{ :​laboratoare:​laborator09:​10authentication.png?​nolink&​800 }} 
 + 
 +De remarcat faptul că elementul rădăcină (de tip ''​AnchorPane''​) ​specifică proprietatea ''​fx:controller'',​ indicând clasa care se va ocupa de gestiunea fișierului FXML, aceasta fiind ''​ro.pub.cs.aipi.lab09.controller.Authentication''​. 
 + 
 +Controalele care vor fi referite în codul sursă au specificat un identificator (proprietatea ''​fx:​id''​). Acestea vor fi adnotate cu ''​@FXML'',​ nefiind necesar ca ele să mai fie instanțiate,​ putând fi utilizate odată ce scena corespunzătoare fișierului FXML a fost încărcată.
  
 <code java> <code java>
-myTable.close();+@FXML private TextField ​    ​ usernameTextField; 
 +@FXML private PasswordField passwordTextField;​ 
 +@FXML private Label             ​errorLabel;  ​
 </​code>​ </​code>​
  
-===== Activitate ​de Laborator =====+Unele metode ​de tratare a evenimentelor sunt precizate explicit (''#​okButtonHandler'',​ ''#​cancelButtonHandler''​),​ clasa controller trebuind să le implementeze în mod obligatoriu,​ în caz contrar generându-se o excepție la încărcarea fișierului FXML. Și acestea trebuie adnotate cu ''​@FXML'': ​
  
-  * schelet de cod +<code java> 
-    ​* {{ :​laboratoare:​laborator10:​aipi2014-lab10-hadoop251hbase09861.tar.gz }} (varianta Hadoop 2.5.1 / HBase 0.98.6.1) +@FXML  
-    * {{ :​laboratoare:​laborator10:​aipi2014-lab10-hadoop260hbase0988.tar.gz ​}} (varianta Hadoop 2.6.0 / HBase 0.98.8)+protected void okButtonHandler(ActionEvent event) { 
 +    // ... 
 +}  
  
-  * script-uri HBase: ​{{ :​laboratoare:​laborator10:​aipi2014-lab10-hbasescripts.tar.gz }}+@FXML  
 +protected void cancelButtonHandler(ActionEvent event) ​{ 
 +    // ... 
 +}  
 +</​code>​
  
-**1.** Să se deschidă maşina virtuală [[http://​aipi2014.andreirosucojocaru.ro/​Ubuntu1404.zip|Ubuntu 14.04]] / [[http://​aipi2014.andreirosucojocaru.ro/​Ubuntu1410.zip|Ubuntu 14.10]], autentificarea făcându-se cu utilizatorul aipi2014 şi parola StudentAipi2014.+Încărcarea documentului FXML se realizează în cadrul unei scene (obiect de tipul ''​javafx.scene.Scene''​) prin intermediul metodei statice ''​load()''​ din clasa ''​FXMLLoader''​:
  
-**2.** Într-un terminal, să se pornească sistemul de fişiere distribuite HDFS şi sistemul de gestiune al resurselor YARN.+<code java> 
 +try { 
 +    applicationScene = new Scene((Parent)FXMLLoader.load(getClass().getResource(Constants.AUTHENTICATION_FXML)));​ 
 +} catch (Exception exception) { 
 +   ​System.out.println ("An exception has occured: "​+exception.getMessage());​ 
 +   if (Constants.DEBUG) 
 +        exception.printStackTrace();​ 
 +} 
 +</​code>​
  
-<code bash> +==== JavaFX Scene Builder ==== 
-student@aipi2015:~$ start-dfs.sh + 
-student@aipi2015:~$ start-yarn.sh+Documentele FXML pot fi dezvoltate în mod vizual folosind utilitarul [[http://​gluonhq.com/​open-source/​scene-builder/​|SceneBuilder]],​ disponibil pe platformele Windows (32/64 de biţi), Mac OS X şi Linux (32/64 biţi) – sub formă de pachete ''​.deb''​ şi arhive ''​tar.gz''​.  
 + 
 +Acesta permite construirea interfeței grafice interactiv, simultan cu generarea automată a documentului FXML, fiecare control putând fi configurat, grupate în proprietăţi,​ moduri de dispunere şi cod. 
 + 
 +Caracteristicile utilitarului SceneBuilder sunt: 
 +  * interfaţă WYSIWYG de tip drag and drop care permite crearea rapidă a unei interfeţe cu utilizatorul fără a fi nevoie de a scrie cod sursă; controalele pot fi preluate dintr-o bibliotecă şi dispuse în modul în care se doreşte afişarea lor; 
 +  * integrare facilă cu orice IDE pentru Java de vreme ce este un utilitar de sine stătător;​ 
 +  * generare automată a codului FXML se produce la construirea interfeţei cu utilizatorul,​ acesta fiind menţinut separat de logica aplicaţiei şi foile de stil; 
 +  * editare în timp real şi funcţionalităţi de previzualizare ce permit ca modificările la interfaţa cu utilizatorul să fie vizibile pe măsură ce sunt implementate,​ fără a fi necesar ca aplicaţia să fie compilată, reducând timpul de dezvoltare al proiectului;​ 
 +  * acces la întreaga bibliotecă de controale JavaFX 8; 
 +  * posibilitatea de specificare a unor elemente de interfață grafică definite de utilizator, importate din arhive JAR, fișiere FXML sau importate în panourile de ierarhie / conținut;​ 
 +  * suport 3D, pentru obiectele de acest tip putând fi specificate proprietățile din panoul de inspectare (cu excepția proprietăților ''​Material''​ și ''​Mesh''​);​ încă nu pot fi create obiecte 3D; 
 +  * suport pentru text particularizat,​ prin implementarea containerului ''​TextFlow''​ ce poate conține mai multe noduri de tip ''​Text'',​ acestea putând fi gestionate autonom; 
 +  * JavaFX Scene Builder Kit este un API ce permite integrarea funcționalităților direct în interfața grafică a unui mediu de dezvoltare integrat precum NetBeans, IntelliJ, Eclipse; 
 +  * suport pentru CSS permite gestiunea flexibilă a modului în care arată aplicaţia;​ 
 +  * suport pentru mai multe sisteme de operare, având pe toate un comportament consistent;​ 
 +  * gratuitate pentru toate tipurile de utilizatori. 
 + 
 +{{ :​laboratoare:​laborator09:​11scene_builder.png?​nolink&​800 }} 
 + 
 +Utilitarul Scene Builder are interfața grafică împărțită în 7 secțiuni. 
 + 
 +În secţiunea 1 (''​Library''​) este disponibilă o bibliotecă de componente cu care se poate construi interfaţa cu utilizatorul. Ele pot indica modul de dispunere al obiectelor sau pot constitui controale propriu-zise. Acestea sunt grupate pe categorii: ''​Containers'',​ ''​Controls'',​ ''​Menu'',​ ''​Miscellaneous'',​ ''​Shapes'',​ ''​Charts'',​ ''​3D''​. 
 + 
 +În secţiunea 2 (''​Document''​) este prezentată:​ 
 +  * ierarhia de noduri (''​Hierarchy''​). Un obiect care conţine şi alte obiecte la rândul său va avea asociată un semn de plus sau minus, după cum conținutul său poate fi expandat, respectiv restrâns;​ 
 +  * elementele care pot fi injectate în codul sursă (''​Controller''​). Este specificată clasa controller asociată fișierului FXML precum și componentele care au precizat un identificator unic pe baza căruia pot fi accesate în codul sursă. 
 + 
 +În secţiunea 3 se poate previzualiza interfaţa cu utilizatorul. Aici aceasta se construieşte propriu-zis scena prin operaţii de tip drag and drop. În partea de sus a secțiunii este indicată scena de grafuri pentru nodul curent. Dacă nodul care se adaugă interfeţei se află deasupra unui alt obiect, acesta va fi evidenţiat în mod deosebit, astfel încât să se poată determina cu exactitate ierarhia nodurilor din interfaţa cu utilizatorul. În situaţia în care un nod este adăugat peste un alt obiect, acesta va fi inclus în nodul respectiv, stabilindu-se o relaţie de tip părinte-fiu. 
 + 
 +În secțiunea 4 (''​Inspector''​) pot fi căutate elemente fie din biblioteca de controale, fie din interfaţa grafică. O astfel de funcţionalitate este deosebit de utilă în special pentru interfeţele cu utilizatorul mai complexe, în care identificarea unui element este mai dificilă. 
 + 
 +În secţiunea 5 (''​Properties''​) se pot stabili proprietăţile obiectului selectat în mod curent (efecte, transformări,​ asocierea unor foi de stil, aliniere, vizibilitate,​ opacitate, orientare). 
 + 
 +În secţiunea 6 (''​Layout''​) sunt tratate aspecte legate de modul de dispunere a nodului (dimensiuni,​ aliniere, poziție, transformări,​ limite). 
 + 
 +În secţiunea 7 (''​Code''​) sunt indicate metodele executate din clasa controller atunci când o acţiune de tipul respectiv se produce asupra interfeţei respective. Categoriile de evenimente incluse sunt main, drag and drop, evenimente legate de tastaura şi mouse, precum şi evenimente specifice dispozitivelor cu ecran tactil (rotire, glisare, atingere, modificarea rezoluţiei de vizualizare). 
 + 
 +===== Modele de Date asociate Controalelor JavaFX ===== 
 + 
 +JavaFX utilizează un model JavaBeans pentru reprezentarea obiectelor, oferind suport pentru proprietăţi şi pentru crearea de dependenţe (//eng.// binding) între obiecte, exprimând relaţiile dintre acestea. Atunci când un obiect participă într-o relaţie de tip dependenţă,​ modificările asupra sa sunt imediat vizibile la nivelul obiectului cu care se află în legătură. Interfeţele de programare care oferă astfel de funcţionalităţi pot fi de nivel înalt, în care dependenţele se creează uşor şi de nivel scăzut, folosite mai ales în cazul în care se doreşte execuţie rapidă şi o utilizare redusă a memoriei. O astfel de funcţionalitate este extrem de utilă în dezvoltarea de interfeţe grafice cu utilizatorul întrucât informaţiile vizualizate sunt automat sincronizate cu sursa de date din care acestea sunt preluate. 
 + 
 +O proprietate într-o anumită clasă care respectă acest model corespunde unui atribut al acesteia: 
 + 
 +<code java> 
 +class MyClass { 
 + 
 +    private SomeTypeProperty myAttribute = new SomeTypeProperty();​ 
 +     
 +    // ... 
 +  
 +}
 </​code>​ </​code>​
  
-<note important>​Verificaţi faptul că au pornit corect prin inspectarea interfeţelor web de la adresele [[http://​localhost:​50070]], respectiv [[http://​localhost:​8088]].</​note>​+În situaţia în care clasa oferă suport pentru proprietăţi, ea va implementa metodele setter şi getter: ''​setMyAttribute()''​ respectiv ''​getMyAttribute()''​ pentru stabilirea respectiv obţinerea valorii propriu-zise a atributului respectiv, dar şi metoda ''​myAttributeProperty()''​ care va întoarce exact atributul în cauză. Pentru această valoare poate fi indicat un obiect de tip ascultător,​ ce monitorizează modificările realizate asupra acestuia.
  
-**3.** Într-un terminal, să se pornească o instanţă a bazei de date distribuită HBase.+Dependenţele dintre obiecte pot fi realizate fie prin clase specifice tipului de date respectiv ''​DataTypeBinding''​ (unde ''​DataType''​ reprezintă tipul de date respectiv) fie direct prin clasa ''​Bindings''​. 
  
-<​code ​bash> +De asemenea, sunt definite o serie de interfeţe care permit obiectelor să fie notificate atunci când se modifică o valoare sau se produce invalidarea unor valori (''​InvalidationListener'',​ ''​ChangeListener''​ primesc notificări produse de ''​Observable''​ şi ''​ObservableValue''​). Obiectul ''​ObservableValue''​ încapsulează şi valoarea propriu-zisă şi transmite modificările ei către orice obiect ''​ChangeListener''​ înregistrat în timp ce ''​Observable'',​ care nu conţine şi valoarea în sine transmite înregistrările către ''​InvalidationListener''​. 
-student@aipi2015:~$ start-hbase.sh+ 
 +Implementarea proprietăţilor şi a dependenţelor în JavaFX suportă evaluarea leneşă (//eng.// lazy evaluation),​ ceea ce înseamnă că la momentul în care se produce o modificare, valoarea nu este recalculată imediat, ci numai dacă şi atunci când valoarea în cauză este solicitată. Astfel, dependenţa este invalidă dacă s-au produs modificări şi recalcularea nu s-a produs încă, fiind validată când acest proces este declanşat de solicitarea valorii. 
 + 
 +<​note>​Numai clasa ''​InvalidationListener''​ suportă atât evaluarea lentă cât şi evaluarea rapidă, în timp ce clasa ''​ChangeListener''​ impune evaluarea rapidă (chiar dacă ''​ObservableValue''​ suportă şi evaluarea leneşă) pentru că nu este posibil să se ştie dacă valoarea a fost cu adevărat modificată până ce nu este recalculată.</​note>​ 
 + 
 +<​code ​java> 
 +MyClass myObject = new MyClass();​ 
 +myObject.myAttributeProperty().addListener(new ChangeListener() { 
 +    ​@Override 
 +    public void changed(Observable Value observableValue,​ Object oldValue, Object newValue) { 
 +        // ... 
 +    } 
 +});
 </​code>​ </​code>​
  
-<note important>Verificaţi starea bazei de date HBase prin intermediul interfeţei web disponibilă la adresa [[http://localhost:​60010]].</note>+<code java> 
 +MyClass myObject = new MyClass();​ 
 +myObject.myAttributeProperty().addListener( 
 +    (Observable Value observableValue,​ Object oldValue, Object newValue) -> { 
 +        ​// ... 
 +    } 
 +); 
 +</code>
  
-<note important>​Verificaţi faptul că rulează toate procesele Hadoop rulând comanda +În JavaFX sunt definite mai multe colecţii de date în cadrul pachetului ''​javafx.collections'',​ acesta conținând:​ 
-<​code ​bash> +  * interfeţe 
-student@aipi2015:​~$ ​/usr/local/java/jdk1.8.0_25/bin/jps+    * ''​ObservableList''​ – o listă care permite ascultătorilor să identifice modificările la momentul la care se produc; 
 +    * ''​ListChangeListener''​ – o interfaţă care primeşte notificările modificărilor realizate asupra unui obiect de tip ''​ObservableList'';​ 
 +    * ''​ObservableMap''​ – o listă de asocieri cheie unică-valoare ce permite ascultătorilor să identifice modificările atunci când se produc; 
 +    * ''​MapChangeListener''​ – o interfaţă care primeşte notificările modificărilor realizate asupra unui obiect de tip ''​ObservableMap''​. 
 +  * clase 
 +    * ''​FXCollections''​ – o clasă de utilitare ce pune la dispoziţia programatorilor aceleaşi metode din clasa ''​java.util.Collections'';​ 
 +    * ''​ListChangeListener.Change''​ – reprezintă o schimbare realizată asupra unui obiect ''​ObservableList'';​ 
 +    * ''​MapChangeListener.Change''​ – reprezintă o schimbare realizată asupra unui obiect ''​ObservableMap''​. 
 + 
 +Interfeţele ''​ObservableList''​ şi ''​ObservableMap''​ sunt ambele derivate din ''​javafx.beans.Observable''​ şi ''​java.util.List'',​ respectiv ''​java.util.Map'',​ definind metode ''​addListener()''​ primind parametri ''​ListChangeListener''​ / ''​MapChangeListener''​. 
 + 
 +Crearea unor astfel de obiecte se face prin metodele statice ale clasei ''​FXCollections'':​ ''​observableList()''​ şi ''​observableMap()'',​ ce primesc ca argumente obiecte din clasele ''​java.util.List'',​ respectiv ''​java.util.Map''​. 
 + 
 +<columns 100% 50%> 
 + 
 +<​code ​java> 
 +List<​String>​ list = new ArrayList<​String>​();​ 
 +ObservableList<​String>​ observableList = FXCollections.observableList(list);​ 
 +observableList.addListener(new ListChangeListener() { 
 +    ​@Override 
 +    public void onChanged(ListChangeListener.Change change) { 
 +        while (change.next()) { 
 +            if (change.wasAdded()) { 
 +                ​// ... 
 +            } 
 +            if (change.wasRemoved()) { 
 +                ​// ... 
 +            } 
 +            if (change.wasReplaced()) { 
 +                ​// ... 
 +            } 
 +            if (change.wasPermutated()) { 
 +                // ... 
 +            } 
 +        } 
 +    } 
 +});
 </​code>​ </​code>​
-</​note>​ 
  
-**4.** Să se ruleze script-urile HBase pentru crearea şi popularea bazei de date. Vor trebui rulate scripturile ''​Laborator10_DDLc.rb''​ şi ''​Laborator10_DML.rb''​.+<​newcolumn>​
  
-Va fi apelat utilitarul ''​hbase'' ​(cu parametrul ''​shell''​), indicându-se căile absolute către scripturile care trebuie rulate.+<code java> 
 +Map<​String,​String>​ map = new HashMap<​String,​String>​(); 
 +ObservableMap<​String,String> observableMap = FXCollections.observableMap(map);​ 
 +observableMap.addListener(new MapChangeListener() { 
 +    @Override 
 +    public void onChanged(MapChangeListener.Change change) { 
 +        // ... 
 +    } 
 +}); 
 +</​code>​
  
-<​code ​bash> +De remarcat faptul că obiectul de tip ''​ListChangeListener.Change''​ poate conţine informaţii despre mai multe modificări,​ motiv pentru care este necesar să se realizeze un interator pe acestea prin apelarea metodei ''​next()'',​ în timp ce ''​MapChangeListener.Change''​ conţine o singură schimbare, corespunzătoare operaţiei ''​put()''​ sau ''​remove()''​ care a fost realizată. 
-student@aipi2015:​~/​HBaseScripts$ hbase shell Laborator10_DDLc.rb + 
-student@aipi2015:​~/HBaseScripts$ hbase shell Laborator10_DML.rb+===== Gestiunea Concurenței în JavaFX ===== 
 + 
 +Pachetul ''​javafx.concurrent''​ pune la dispoziţie funcţionalităţi pentru dezvoltarea de aplicaţii ce rulează pe mai multe fire de execuţie, completând capabilităţile oferite de ''​java.util.concurrent''​ ţinând cont de firul de execuţie al aplicaţiei JavaFX şi de alte constrângeri specifice interfeţelor grafice. În acest caz, ideea este de a oferi o viteză de răspuns satisfăcătoare prin execuţia sarcinilor care consumă resurse către fire de execuţie care rulează în fundal. 
 + 
 +Graful de scene JavaFX nu poate fi accesat decât din firul de execuţie responsabil de interfaţa cu utilizatorul (firul de execuţie al aplicaţiei JavaFX). Implementarea de sarcini care consumă resurse pe acest fir de execuţie face ca interfaţa cu utilizatorul să fie neresponsivă motiv pentru care acestea trebuie alocate unuia sau mai multor fire de execuţie care rulează în fundal, lăsând firul de execuţie al aplicaţiei JavaFX să se ocupe de evenimentele rezultate din interacţiunea cu utilizatorul. 
 + 
 +Pachetul ''​javafx.concurrent''​ constă în interfaţa ''​Worker''​ şi două clase de bază ''​Task''​ şi ''​Service'',​ ambele implementând interfaţa ''​Worker''​. Aceasta oferă funcţionalităţi necesare unui fir de execuţie care rulează în fundal pentru a comunica cu interfaţa grafică. Clasa ''​Task'',​ implementare observabilă a clasei ''​java.util.concurrent.FutureTask'',​ permite specificarea de sarcini asincrone în timp ce clasa ''​Service''​ le execută.  
 + 
 +Clasa ''​WorkerStateEvent''​ generează evenimente de fiecare dată atunci când starea unui obiect ''​Worker''​ se modifică.  
 + 
 +Clasele ''​Task''​ şi ''​Service''​ implementează interfaţa ''​EventTarget''​ astfel încât suportă ascultarea evenimentelor legate de starea acestor fire de execuţie. 
 + 
 +Interfaţa ''​Worker''​ defineşte un obiect care realizează anumite sarcini pe unul sau mai multe fire de execuţie, starea sa fiind observabilă din contextul firului de execuţie al aplicaţiei JavaFX. Stările pe care le poate avea un obiect care implementează această interfaţă sunt: 
 +  * ''​READY''​ (imediat după ce a fost creat); 
 +  * ''​SCHEDULED''​ (atunci când este programat pentru o anumită sarcină) 
 +  * ''​RUNNING''​ (după ce a fost pornit) - în cazul în care firul de execuţie este pornit în mod direct, el va trece mai înainte prin starea ''​SCHEDULED''​ înainte de ''​RUNNING'',​ chiar dacă nu a fost programat propriu-zis;​ 
 +  * ''​SUCCEEDED''​ (dacă sarcina este executată cu succes, proprietatea ''​value''​ fiind transmisă rezultatului acestui obiect); 
 +  * ''​FAILED''​ (dacă sarcina nu a putut fi finalizată,​ proprietatea ''​exception''​ fiind transmisă excepţiei care s-a produs) 
 +  * ''​CANCELED''​ dacă sarcina este întreruptă de utilizator prin apelarea metodei ''​cancel()''​.  
 + 
 +Progresul realizat pe parcursul execuţiei se poate obţine prin diferite proprietăţi precum ''​totalWork'',​ ''​workDone''​ şi ''​progress''​. 
 + 
 +Clasa ''​Task''​ este folosită pentru a implementa logica sarcinii care trebuie executată pe un fir de execuţie în fundal. Implementările clasei ''​Task''​ trebuie să suprascrie metoda ''​call()''​ pentru a realiza operaţiile dorite şi pentru a furniza rezultatul. Fiind invocată pe un fir de execuţie în fundal, aceasta nu poate accesa decât proprietăţi publice din cadrul firului de execuţie al aplicaţiei JavaFX, prin intermediul metodelor ''​updateProgress'',​ ''​updateMessage''​ şi ''​updateTitle'',​ în caz contrar generându-se excepţii. În situaţia în care sarcina este întreruptă,​ rezultatul metodei ''​call()''​ e ignorat. Derivată din ''​java.util.concurrent.FutureTask''​ care implementează interfaţa ''​Runnable'',​ clasa ''​Task''​ permite ca obiectele sale să fie transmise unui fir de execuţie ca parametru sau să fie folosite din interfaţa de programare ''​Executor''​. De asemenea, obiectul de tip ''​Task''​ poate fi apelat prin metoda ''​FutureTask.run()''​ din contextul altui fir de execuţie ce rulează în fundal. 
 + 
 +<​code ​java> 
 +Thread thread = new Thread(task);​ 
 +thread.setDaemon(true);​ 
 +thread.start();​ 
 +// ... 
 +ExecutorService.submit(task);​
 </​code>​ </​code>​
  
-<​note ​tip>De asemenea, există un script ​''​Laborator10_DDLd.rb'' ​pentru ştergerea tabelelor ​din cadrul bazei de date, în cazul în care acestea ​se doresc ​a fi dezinstalate.</​note>​+Un obiect de tip ''​Task''​ trebuie să poată fi oprit de fiecare dată când se apelează metoda ​''​cancel()''​ din contextul său, de aceea, în metoda ''​call()'',​ acesta trebuie să verifice periodic dacă nu cumva s-a produs un astfel de eveniment, folosind metoda ''​isCanceled()''​. În cazul în care în metoda ''​call()''​ există apeluri blocante de tipul ''​Thread.sleep()'',​ şi metoda ''​cancel()''​ este apelată în timpul execuţiei acestei metode, ​se va genera o excepţie ''​InterruptedException''​ astfel încât ​  ​tratarea excepţiei trebuie să verifice şi motivul care a generat-o.
  
-Este instalată o bază de date care are următoarea structură:+Vizualizarea progresului unui obiect de tip ''​Task''​ în cadrul unui control aparţinând firului de execuţie al aplicaţiei JavaFX poate fi realizată prin operaţia de asociere (bind) între acestea, pe baza proprietăţii de progres, actualizată în cadrul metodei ''​call()''​ prin metoda ''​updateProgress()''​. Aceasta actualizează mai multe proprietăţi, cum ar fi ''​progress'',​ ''​totalWork''​ sau ''​workDone''​ astfel încât poate fi apelată metoda ''​progressProperty''​ pentru a obţine progresul sarcinii.
  
-<​html>​ +Întrucât clasa ''​Task''​ defineşte un obiect care nu poate fi reutilizat, pentru implementarea unei astfel de funcţionalităţi trebuie folosită clasa ''​Service''​. Aceasta este proiectată să execute un obiect de tip ''​Task''​ pe unul sau mai multe fire de execuţie care rulează în fundal. Obiectivul său este de a ajuta programatorul să implementeze interacţiunea corectă dintre firele de execuţie din fundal şi firul de execuţie al aplicaţiei JavaFX astfel încât metodele şi stările unei astfel de clase nu pot fi accesate decât din acest context. Un obiect ''​Service''​ poate fi pornit (prin metoda ''​Service.start()''​),​ anulat sau repornit, observându-se,​ pe parcursul rulării sale starea proceselor din fundal. Atunci când se implementează subclase ''​Service'',​ parametrii de intrare trebuie expuşi către obiectul de tip ''​Task''​ ca proprietăţi ale acesteia. Un obiect de tip ''​Service''​ poate fi executat printr-un obiect ''​Executor'',​ printr-un fir de execuţie de tip daemon sau printr-un anumit tip de executor cum ar fi ''​ThreadPoolExecutor''​.
-<​center>​ +
-</​html>​+
  
-^  Tabela ​ ^  Familia ​de Coloane ​ ^  Coloane ​ ^ +De fiecare dată când starea unui obiect ​de tip ''​Worker''​ se schimbă, se produce un eveniment corespunzător, definit de clasa ''​WorkerStateEvent''​: ''​ANY''​, ''​WORKER_STATE_CANCELLED''​, ''​WORKER_STATE_FAILED''​, ''​WORKER_STATE_READY''​, ''​WORKER_STATE_RUNNING''​, ''​WORKER_STATE_SCHEDULED''​, ''​WORKER_STATE_SUCCEEDED''​. Acestea apelează metodele de tratare aferente şi apoi mecanismele de oportunitate ''​cancelled()''​, ''​failled()''​, ''​ready()''​, ''​running()''​, ''​scheduled()''​, ''​succeeded()''​, acestea fiind invocate pentru tranziţiile în stările respective. Metodele pot fi suprascrise de subclasele derivate din ''​Task''​ şi ''​Service''​ pentru a implementa logica aplicaţiei conform cerinţelor funcţionale.
-| country | identification | name, code | +
-| ::: | detail | description | +
-| publishing_house | identification | name, registered_number | +
-| ::: | detail | description | +
-| ::: | address | postal_address, zip_code, country_id | +
-| ::: | miscellanea | internet_address | +
-| collection | identification | name, description | +
-| ::: | referrence | publishing_house_id | +
-| book | identification | title, subtitle | +
-| ::: | detail | description | +
-| ::: | version | edition, printing_year | +
-| ::: | group | collection_id | +
-| format | identification | value | +
-| ::: | detail | description | +
-| language | identification | name, code | +
-| ::: | detail | description | +
-| book_presentation | identification | isbn | +
-| ::: | referrence | book_id, format_id, language_id | +
-| ::: | inventory | stockpile, price | +
-| writer | appellation | first_name, last_name | +
-| ::: | biography | content | +
-| author | referrence | book_id, writer_id | +
-| category | identification | name | +
-| ::: | detail | description | +
-| category_content | referrence | book_id, category_id | +
-| supply_order_hdeader | identification | identification_number,​ issue_date | +
-| ::: | situation | state | +
-| ::: | producer | publishing_house_id | +
-| supply_order_line | referrence | supply_order_header_id | +
-| ::: | content | book_presentation_id,​ quantity | +
-| user | appellation | first_name, last_name | +
-| ::: | identification | personal_identifier | +
-| ::: | contact | address, phone_number,​ email | +
-| ::: | category | type | +
-| ::: | authentication | username, password | +
-| invoice_header | identification | identification_number,​ issue_date | +
-| ::: | situation | state | +
-| ::: | consumer | user_id | +
-| invoice_line | referrence | invoice_header_id | +
-| ::: | content | book_presentation_id,​ quantity | +
-| statistics | expense | value |+
  
-<​html>​ +===== Recomandări referitoare la Implementarea Aplicațiilor JavaFX =====
-</​center>​ +
-</​html>​+
  
-**5.** Se doreşte afişarea unei liste conţinând toţi utilizatorii (identificaţi prin nume şi prenume) precum şi sumele pe care aceştia le-au cheltuit prin achiziţia ​de cărţi din librăria virtuală.+Recomandările referitoare la implementarea aplicaţiilor JavaFX vizează atât nivelul de logică a aplicaţiei, cât şi nivelul ​de prezentare.
  
-În cazul unui sistem ​de gestiune pentru baze de date relaţionale, o astfel ​de problemă are o soluţie foarte simplă ce constă într-o operaţie de joncţiune între ​tabelele book, user, invoice ​şi invoice_detail. Pentru un volum foarte ​mare de informaţii,​ o astfel ​de operaţie poate dura o perioadă de timp inacceptabilă, motiv pentru ​care se doreşte ​ca procesarea ​să se realizeze în paralel, pe mai multe maşini, fiecare gestionând o parte dintre înregistrările tabelelor respective.+În privinţa nivelului ​de logică a aplicaţiei, cele mai frecvent uzitate tehnici sunt:  
 +  * folosirea ecranelor animate care să indice progresul acelor procese ​de lungă durată astfel încât aplicaţia să nu pară că nu răspunde la interacţiunea cu utilizatorul;​ 
 +  * folosirea unor denumiri simbolice pentru pachetele implementate pentru ca aplicaţia să fie mai organizată şi mai uşor de întreţinut; 
 +  * implementarea arhitecturii model-view-controller (MVC) prin intermediul fişierelor FXML pentru definirea scenelor, acestea reprezentând partea de vizualizare, în timp ce modelul este reprezentat de obiectele de domeniu specifice aplicaţiei,​ iar partea de control aparţine codului Java care defineşte comportamentul interfeţei grafice în interacţiunea cu utilizatorul;​ 
 +  * rularea sarcinilor care implică procesarea unui volum mare de date pe fire de execuţie separate, care rulează în fundal, pentru ​a evita ca utilizatorul ​să aştepte foarte mult până la terminarea metodei.
  
-Un sistem MapReduce poate împărţi datele ​de intrare (tabela invoice_detail ​pentru ​situaţia ​de faţă) în mai multe regiuni în mod automat, fiecare dintre acestea fiind prelucrate ​de un proces separat. Astfel, pentru fiecare detaliu din factură, reprezentând un produs al facturii ​se determină preţul total, obţinut prin înmulţirea preţului cărţii (obţinut printr-o interogare a tabelei cărţi) cu cantitatea precizată. Pentru o factură dată prin identificatorul său, se asociază preţul total al fiecărui produs pe care îl conţine. Ulterior, se creează o listă corespunzătoare fiecărei facturi conţinând toate preţurile totale ale produselor aferente. Acestea vor fi însumate, obţinându-se valoarea facturii.+Referitor la nivelul de prezentare, se recomandă următoarele practici: 
 +  * utilizarea panourilor de dispunere, astfel încât conţinutul să fie organizat şi să poată fi utilizat cu uşurinţă;​ 
 +  * asigurarea faptului că toate butoanele au aceeaşi dimensiune se poate realiza mai uşor prin încadrarea tuturor într-un panou de dispunere de tip ''​VBox''​ sau prin indicarea valorilor maxime ​pentru ​dimensiunile lor şi dispunerea într-un obiect ​de tip ''​TilePane'';​ 
 +  * menţinerea nodurilor la dimensiunile preferate (''​Control.USE_PREF_SIZE''​) astfel încât ​în cazul unor operaţii ​de redimensionare să nu se producă comportamente nedorite; 
 +  * prevenirea operaţiei de redimensionare ​prin specificarea dimensiunilor minime, maxime şi preferate la aceeaşi valoare; 
 +  * alinierea nodurilor şi panourilor folosind metoda ''​setAlignment()''​ care primeşte ca parametru constante din pachetul ''​javafx.geometry''​ precum ''​HPos''​ pentru alinierea orizontală, ''​VPos''​ pentru alinierea verticală sau ''​Pos''​ pentru alinierea verticală şi orizontală; această constantă are forma ''​Pos.VALIGN_HALIGN''​ unde ''​VALIGN''​ poate fi ''​TOP''​, ''​BOTTOM'',​ ''​CENTER'',​ iar ''​HALIGN''​ poate lua valorile ''​LEFT'',​ ''​RIGHT'',​ ''​CENTER''​. 
 +  * folosirea foilor de stil pentru definirea aspectului interfeţei grafice, aceasta putând fi modificată cu uşurinţă prin schimbarea foii de stil asociate.
  
-<​html>​ +===== Activitate de Laborator =====
-<​center>​ +
-</​html>​+
  
-^  MAP  ^ → ^  REDUCE ​ ^ +Se doreşte implementarea unei interfeţe grafice cu utilizatorul pentru gestiunea informaţiilor dintr-o bază de date, aceasta urmând a fi utilizată pentru un sistem ERP destinat unei librării care comercializează doar cărţi. 
-| (factura1, preţ_produs1) | → | (factura1, (preţ_produs1, preţ_produs2, ​..., preţ_produsm1))\\ =\\ (factura1, preţ_produs1 + preţ_produs2 + ... + preţ_produsm1) | +
-| (factura1, preţ_produs2) | ::: | ::: | +
-| ... | ::: | ::: | +
-| (factura1,​preţ_produsm1) | ::: | ::: | +
-| (factura2, preţ_produs1) | ::: | (factura2, (preţ_produs1,​ preţ_produs2,​ ..., preţ_produsm1))\\ =\\ (factura2, preţ_produs1 + preţ_produs2 + ... + preţ_produsm2) | +
-| (factura2, preţ_produs2) | ::: | ::: | +
-| ... | ::: | ::: | +
-| (factura2,​preţ_produsm2) | ::: | ::: | +
-| ... | ::: | ... |  +
-| (facturan, preţ_produs1) | ::: | (facturan, (preţ_produs1,​ preţ_produs2,​ ..., preţ_produsmn))\\ =\\ (facturan, preţ_produs1 + preţ_produs2 + ... + preţ_produsmn) | +
-| (facturan, preţ_produs2) | ::: | ::: | +
-| ... | ::: | ::: | +
-| (facturan,​preţ_produsmn) | ::: | ::: |+
  
-<​html>​ +Aplicaţia va avea două ferestre: 
-</​center>​ +  * un formular pentru autentificarea utilizatorilor în sistem; 
-</​html>​+  * o fereastră în care sunt implementate operaţiile pentru o tabelă dintr-o bază de date (adăugare, modificare, ştergere, căutare).
  
-Cum fiecare factură are asociat un identificator al utilizatorului care a achitat-o, acesta va conduce ​la obţinerea, prin interogarea bazei de date user, a numelui şi prenumelui clientului respectiv.+**0**. Să se cloneze în directorul de pe discul local conținutul depozitului ​la distanță ​de la [[https://​www.github.com/​aipi2015/​Laborator09]]. În urma acestei operații, directorul Laborator09 va trebui să conțină subdirectorul ''​labtasks''​, fișierele ''​README.md''​ și ''​LICENSE''​.
  
-Pentru a calcula totalurile pentru fiecare utilizator (un utilizator poate avea mai multe facturi asociate), din datele generate până acum, se vor realiza grupări în funcţie de utilizatori,​ astfel încât pentru fiecare dintre aceştia vor fi asociate una sau mai multe sume de bani corespunzătoare facturilor. Printr-un mecanism similar, acestea vor fi însumate în vederea determinării cheltuielilor totale, pentru fiecare utilizator în parte.+<​code>​ 
 +student@aipi2015:​~$ git clone https://www.github.com/​aipi2015/​Laborator09.git 
 +</​code>​
  
-<​html>​ +**1**. **a)** Să se ruleze, folosind MySQL Workbench (sau alt utilitar similar), scriptul ''​Laborator09l.sql'',​ localizat în directorul ''​scripts''​ din cadrul proiectului ''​09-BookStore-JavaFX''​. Acesta instalează baza de date ''​bookstore''​.
-<​center>​ +
-</​html>​+
  
-^  MAP  ^ → ^  REDUCE ​ ^ +<​note>​În cazul în care baza de date ''​bookstore''​ este deja instalată, nu mai este necesar să se ruleze acest script.</​note>​
-| (utilizator,​ preţ_factura1) | → | (utilizator,​ (preţ_factura1,​ preţ_factura2, ..., preţ_facturan))\\ =\\ (utilizator,​ preţ_factura1 + preţ_factura2 + ... + preţ_facturan) | +
-| (utilizator,​ preţ_factura2) | ::: | ::: | +
-| ... | ::: | ::: | +
-| (utilizator,​ preţ_facturan) | ::: | ::: |+
  
-<html> +<note important>Această operație poate dura o perioadă de timp îndelungată,​ în funcție de configurațiile mașinilor pe care se lucrează.</note>
-</center> +
-</​html>​ +
  
-Se observă faptul că structura coloanelor marcate este echivalentă, astfel încât ​aplicaţia va consta din 2 sarcini, din care una va avea atât partiţie de tip map cât şi partiţie de tip reduce, iar una va avea numai partiţie de tip reduce. De asemenea, ​se observă faptul că datele ​de ieşire ale unei sarcini reprezintă datele de intrare pentru cealaltă sarcină.+**b)** În interfața ''​Constants''​ din pachetul ''​ro.pub.cs.aipi.lab09.general'',​ să se modifice credențialele (nume de utilizator și parolă), astfel încât ​să se poată accesa informațiile din baza de date MySQL (proprietățile ''​DATABASE_USERNAME''​ respectiv ''​DATABASE_PASSWORD''​).
  
-În aplicaţia ​''​BookStoreMapReduce''​, cele două sarcini se numesc ​''​billValue'' ​şi ''​userExpenses''​, fiind definite (prin partiţiile map şi reduce corespunzătoare) în clasa cu acelaşi nume.+**2**. Să se acceseze fişierul ​''​authentication.fxml'' ​(localizat în directorul ​''​src''​, subdirectorul ​''​resources/​fxml''​) ​folosind utilitarul SceneBuilder sau cu orice alt editor de text – inclusiv din cadrul mediilor integrate de dezvoltare Eclipse / Eclipse. Acesta conține un formular pentru autentificarea utilizatorilor.
  
-**a)** în clasa ''​Map''​ a sarcinii ''​billValue''​ (clasa ''​BillValueMapper''​ din pachetul ''​ro.pub.cs.aipi.lab10.mapper''​),​ să se determine preţul cărţii analizate în mod curent (care se găseşte în detaliul de factură repartizat procesului curent);+{{ :​laboratoare:​laborator09:​activitate_de_laborator01.png?nolink }} 
 +⇓ 
 +{{ :​laboratoare:​laborator09:​activitate_de_laborator02.png?nolink }}
  
-Se va crea o instanţă a clasei ''​HTable''​ şi un obiect ​de tip ''​Get'' ​în care se va specifica atributul ce se doreşte obţinut (prin metoda ''​addColumn()''​, indicându-se atât familia coloanei cât şi denumirea propriu-zisă a coloanei), din aplicarea acestuia generându-se un obiect ​''​Result''​ pentru care se apelează metoda ''​getValue()''​ în scopul de a se obţine valoarea dorită.+**a)** Să se precizeze clasa controller pentru documentul FXML (având ca rădăcină un mecanism de gestiune a conținutului ​de tip ''​AnchorPane''​) ​ca fiind ''​ro.pub.cs.aipi.lab09.controller.Authentication''​.
  
-**b)** în clasa ''​Reduce''​ a sarcinii ''​billValue''​ (clasa ''​BillValueReducer''​ din pachetul ''​ro.pub.cs.aipi.lab10.reducer''​),​ să se calculeze preţul total pentru o factură, prin agregarea tuturor sumelor parţiale specificate în detaliile de factură;+{{ :​laboratoare:​laborator09:​activitate_de_laborator03.png?nolink }}
  
-**c)** în clasa ''​Reduce''​ a sarcinii ''​billValue''​ (clasa ''​BillValueReducer''​ din pachetul ''​ro.pub.cs.aipi.lab10.reducer''​),​ să se obţină, prin interogarea tabelei facturi, CNP-ul utilizatorului căruia i-a fost emisă factura analizată în mod curent;+<file xml authentication.xml> 
 +<!-- different imports ​-->
  
-**d)** în clasa ''​Reduce''​ a sarcinii ''​billValue''​ (clasa ''​BillValueReducer''​ din pachetul din pachetul ''​ro.pub.cs.aipi.lab10.reducer''​),​ să se obţină, prin interogarea tabelei utilizatori,​ numele şi prenumele clientului având CNP-ul determinat anterior;+<​AnchorPane fx:​id="​AnchorPane"​ maxHeight="​-Infinity"​ maxWidth="​-Infinity"​ minHeight="​-Infinity"​ minWidth="​-Infinity"​  
 +prefHeight="​128.0"​ prefWidth="​336.0000999999975"​  
 +style="​-fx-background-color:​ beige;"​ xmlns="​http://​javafx.com/​javafx/​8"​ xmlns:​fx="​http://​javafx.com/​fxml/​1"​ fx:​controller="​ro.pub.cs.aipi.lab09.controller.Authentication">​ 
 +   
 +  <!-- description of the graphic user interface --> 
 +   
 +</​AnchorPane>​ 
 +</​file>​
  
-**e)** în clasa ''​BookStoreMapReduce'' ​din pachetul ​''​ro.pub.cs.aipi.lab10.main'',​ pentru sarcina ''​userExpenses'',​ să se indice valorile claselor corespunzătoare cheii şi valorii datelor ​de ieşire;+**b)** Pentru butoanele ​''​Ok'' ​/ ''​Cancel'',​ să se specifice metodele care vor fi executate în cazul producerii unui eveniment ​de tipul ''​ActionEvent.ACTION''​ (proprietatea ''​onAction()''​) ca fiind: 
 +  * ''​okButtonHandler()''​; 
 +  * ''​cancelButtonHandler()''​.
  
-Întrucât datele de ieşire sunt reprezentate de tuplul (numeprenume,​ valoare), tipurile de date corespunzătoare vor fi ''​Text'',​ respectiv ''​LongWritable''​.+{{ :​laboratoare:​laborator09:​activitate_de_laborator04a.png?nolink }} ⇒ {{ :​laboratoare:​laborator09:​activitate_de_laborator04b.png?​nolink }}
  
-**f)** în clasa ''​Reduce''​ a sarcinii ''​userExpenses''​ (clasa ''​UserExpensesFileReducer''​ din pachetul ''​ro.pub.cs.aipi.lab10.reducer''​),​ să determine valoarea totală a facturilor achitate de client şi să se scrie această valoare în context (folosind metoda ''​write()'',​ cheia de rând fiind reprezentată de numele şi prenumele utilizatorului);​+<file xml authentication.xml> 
 +<​!-- ​... --> 
 +<Button mnemonicParsing="​false"​ onAction="#​okButtonHandler"​ text="​OK"​ /> 
 +<​!-- ​... --> 
 +</​file>​
  
-De remarcat faptul ​că pentru citirea datelor de intrare în cazul sarcinii ''​userExpenses'',​ a fost folosită o clasă specială, definită de utilizator ​(''​CustomFileInputFormat''​), în care datele au forma (cheie, valoare), iar separatorul dintre aceste entităţi este TAB-ul. Întrucât cheia este reprezentată de numele şi prenumele utilizatorilor, iar valoarea de suma unei facturi, tipurile de date procesate în clasa ''​CustomFileInputFormatRecordReader'' ​vor fi ''​Text'', ​respectiv ​''​LongWritable''​. O astfel de soluţie a fost adoptată datorită faptului că nu au fost definite tipuri de fişiere de intrare care să aibă această structură.+**c)** Să se specifice identificatori ​(proprietatea ​''​fx:id''​) ​pentru: 
 +  * cele două câmpuri text pentru specificarea parametrilor nume utilizator / parolă, având denumirile ​''​usernameTextField'' ​/ ''​passwordTextField''​; 
 +  * eticheta în care se va afișa un mesaj de eroare în situația în care operația de autentificare eșuează, având denumirea ​''​errorLabel''​.
  
-**6.** Să se rezolve problema anterioară,​ stocând rezultatele nu într-un fişier ci în tabela statistici a bazei de date HBase, care are o singură familie de coloane, cheltuieli, în care o posibilă coloană ar putea fi valoare.+{{ :​laboratoare:​laborator09:​activitate_de_laborator05a.png?nolink }} ⇒ {{ :​laboratoare:​laborator09:​activitate_de_laborator05b.png?nolink }}
  
-**a)** În clasa ''​BookStoreMapReduce''​ din pachetul ''​ro.pub.cs.aipi.lab10.main'',​ se va apela metoda statică ''​initTableReducerJob()''​ a clasei ''​TableMapReduceUtil''​ ce primeşte ca parametrii denumirea tabelei unde se doresc a fie redirectate datele de ieşire, numele clasei care implementează sarcina de tip ''​Reduce''​ şi numele obiectului de tip ''​Job''​. De asemenea, va trebui indicat şi numărul sarcinilor de tip ''​Reduce''​.+<file xml authentication.xml> 
 +<​!-- ​... --> 
 +<​TextField fx:​id="​usernameTextField"​ prefWidth="​200.0" GridPane.columnIndex="​1"​ GridPane.rowIndex="​0"​ /> 
 +<!-- ... --> 
 +</​file>​
  
-**b)** În clasa ''​UserExpensesTableReducer''​ din pachetul ​''​ro.pub.cs.aipi.lab10.reducer'', ​ulterior determinării sumei totale achitate de client, să se creeze un obiect de tip ''​Put'' ​având drept cheie numele şi prenumele utilizatorului,​ adăugându-se (prin metoda ​''​add()''​), ​ca valoare ​a celulei identificată de coordonatele ''​expense:​value'',​ suma tuturor facturilor, corespunzând produselor achiziţionate.+**d)** În clasa controller ​''​ro.pub.cs.aipi.lab09.controller.Authentication'', ​sa se implementeze metodele ​''​okButtonHandler()'' ​/ ''​cancelButtonHandler()'' ​ce gestionează accesul utilizatorului în aplicaţie. Vor avea dreptul de a accesa sistemul informatic doar utilizatorii al căror tip este administrator. În cazul în care combinaţia (utilizator,​ parolă) este incorectă sau utilizatorul nu are acces în sistem, se va afişa un mesaj corespunzător care va rămâne pe ecran maxim 5 secunde.
  
-**7.** [**0 puncte**] Înainte ​de a închide maşina virtuală, să se oprească instanţa bazei de date distribuită HBase precum şi a sistemului de gestiune a resurselor YARN, respectiv al sistemului de fişiere distribuite HDFS.+<​spoiler|Indicații ​de rezolvare>​ 
 +În cazul butonului ''​Ok''​, este necesar ​să se realizeze o interogare asupra tabelei ''​user''​ (accesibil prin proprietatea ''​Constants.USER_TABLE_NAME''​). Aceasta va prelua atributul ''​type''​ (disponibil în câmpul ''​Constants.USER_TYPE_ATRRIBUTE''​) pentru acele înregistrări care au câmpurile ''​username''​ și ''​password''​ egale cu valorile introduse prin intermediul interfeței grafice.
  
-<​code ​bash> +<​code ​java> 
-student@aipi2015:​~$ stop-hbase.sh +DatabaseOperations databaseOperations = DatabaseOperationsImplementation.getInstance();​ 
-student@aipi2015:​~$ stop-yarn.sh +List<​String>​ attributes = new ArrayList<>​();​ 
-student@aipi2015:​~$ stop-dfs.sh+attributes.add(Constants.USER_TYPE_ATTRIBUTE);​ 
 +List<​List<​String>>​ userTypes = databaseOperations.getTableContent( 
 +  Constants.USER_TABLE_NAME,​ 
 +  attributes,​ 
 +  "​username=\'"​ + usernameTextField.getText() + "​\'​ AND password=\'"​ + passwordTextField.getText() + "​\'",​ 
 +  null, 
 +  null, 
 +  null);
 </​code>​ </​code>​
 +
 +În urma execuției acestei interogări,​ se pot distinge următoarele situații:
 +  - interogarea nu întoarce nici o valoare, ceea ce înseamnă că perechea (nume de utilizator, parolă) este incorectă: în această situație se va afișa un mesaj de eroare corespunzător,​ conținut de proprietatea ''​Constants.ERROR_USERNAME_PASSWORD'';​ acesta va fi afișat timp de 5 secunde, iar conținutul câmpurilor nume de utilizator și parolă vor fi golite;
 +  - interogarea întoarce valori, situație în care se verifică tipul utilizatorului:​
 +    - utilizatorul are tipul ''​administrator''​ (reținut de ''​Constants.USER_TYPE_ADMINISTRATOR_VALUE''​);​ în această situație se deschide interfața grafică reprezentată de clasa ''​Container''​ și se închide interfața grafică reprezentată de clasa (''​Authentication''​) - aceasta trebuie accesată prin intermediul grafului de scene atașat evenimentului,​ întrucât procesarea se face prin intermediul firului de execuție JavaFX, responsabil cu gestiunea operațiilor cu utilizatorul:​ <code java>
 +new Container().start();​
 +((Node) event.getSource()).getScene().getWindow().hide();​
 +</​code>​
 +    - utilizatorul are tipul ''​client''​ (reținut de ''​Constants.USER_TYPE_CLIENT_VALUE''​):​ în această situație se va afișa un mesaj de eroare corespunzător,​ conținut de proprietatea ''​Constants.ERROR_ACCESS_NOT_ALLOWED'';​ acesta va fi afișat timp de 5 secunde, iar conținutul câmpurilor nume de utilizator și parolă vor fi golite.
 +
 +Afișarea unui mesaj de eroare pentru care se atașează o animație de tipul dispariție graduală, pe parcursul unui interval de timp este realizată prin intermediul unui obiect de tip [[https://​docs.oracle.com/​javafx/​2/​api/​javafx/​animation/​FadeTransition.html|FadeTransition]]:​ <code java>
 +errorLabel.setText(...);​
 +FadeTransition fadeTransition = new FadeTransition(Duration.seconds(5),​ errorLabel);​
 +fadeTransition.setFromValue(1.0);​
 +fadeTransition.setToValue(0.0);​
 +fadeTransition.play();​
 +usernameTextField.setText(""​);​
 +passwordTextField.setText(""​);​
 +</​code>​
 +
 +În cazul butonului ''​Cancel'',​ se va apela metoda ''​Platform.exit()''​
 +</​spoiler>​
 +
 +**3**. În clasa ''​TableManagement'',​ din pachetul ''​ro.pub.cs.aipi.lab09.controller''​ să se completeze metoda ''​initialize()'',​ astfel încât aceasta să populeze obiectul ''​attributesGridPane''​ (de tip ''​GridPane''​) care va avea pe două coloane obiectele de tip ''​ArrayList<​Label>''​ (''​attributeLabels''​),​ respectiv ''​ArrayList<​Control>''​ (''​attributeControls''​).
 +
 +{{ :​laboratoare:​laborator09:​activitate_de_laborator06.png?​nolink }}
 +
 +<note important>​Obictele ''​attributeLabels'',​ respectiv ''​attributesControls''​ au deja conținutul care trebuie vizualizat în cadrul acestora.</​note>​
 +
 +<​spoiler|Indicații de Rezolvare>​
 +Înainte de a adăuga obiectul propriu-zis,​ trebuie să îi specificaţi poziţia în cadrul obiectului de tip ''​GridPane'',​ prin intermediul metodei [[https://​docs.oracle.com/​javafx/​2/​api/​javafx/​scene/​layout/​GridPane.html#​setConstraints%28javafx.scene.Node,​%20int,​%20int%29|GridPane.setConstraints(Node,​ column ,row)]].
 +
 +Atașarea propriu-zisă a nodului se face prin intermediul metodei ''​add()''​ apelată pe lista observabilă a nodurilor (copil) a obiectului ''​attributesGridPane'',​ obținută prin invocarea metodei [[https://​docs.oracle.com/​javafx/​2/​api/​javafx/​scene/​layout/​Pane.html#​getChildren%28%29|getChildren()]].
 +
 +<code java>
 +GridPane.setConstraints(attributesLabels.get(attributesLabels.size() - 1), 0, currentIndex);​
 +attributesGridPane.getChildren().add(attributesLabels.get(attributesLabels.size() - 1));
 +
 +// ...
 +
 +GridPane.setConstraints(attributesControls.get(attributesControls.size() - 1), 1, currentIndex);​
 +attributesGridPane.getChildren().add(attributesControls.get(attributesControls.size() - 1));
 +</​code>​
 +
 +Toate aceste operații vor fi realizate repetitiv, pe o iterație care parcurge toate atributele din cadrul entității respective.
 +
 +</​spoiler>​
 +
 +Așa cum se poate observa, în interfaţa grafică se folosesc cinci butoane (adăugare, editare, ştergere, căutare, golire conținut) pentru a se realiza operaţiile de tip CRUD (Create, Read, Update, Delete).\\ În momentul când se produce o acţiune corespunzătoare unuia dintre aceste acestea, se vor apela metodele corespunzătoare evenimentului de tip ''​onAction()'',​ specificate în fișierul FXML.
 +
 +**4**. În clasa ''​TableManagement'',​ din pachetul ''​ro.pub.cs.aipi.lab09.controller'',​ să se implementeze metoda ''​updateButtonHandler()''​ corespunzătoare butonului care actualizează valorile din controale (câmpuri text și liste de selecție) în tabelă.
 +
 +<​spoiler|Indicații de Rezolvare>​
 +În cadrul metodei ''​updateButttonHandler()''​ trebuie realizate următoarele operații:
 +  - se obține indexul selectat în mod curent în cadrul tabelului (astfel încât selecția să poată fi refăcută ulterior operației de actualizare) <code java>
 +int tableViewSelectedIndex = tableContentTableView.getSelectionModel().getSelectedIndex();​
 +</​code>​
 +  - se obține o listă cu toate valorile selectate în mod curent (astfel încât operația de actualizare să fie realizată pe baza identificatorului care are rol de cheie primară în tabelă) <code java>
 +List<​String>​ tableViewCurrentRecord = ((Model) tableContentTableView.getSelectionModel().getSelectedItem()).getValues();​
 +</​code>​
 +  - se parcurge lista de etichete / controale, astfel încât să se construiască:​
 +    - lista de atribute, pe baza listei de etichete <code java>
 +attributes.add(attributesLabels.get(currentIndex).getText());​
 +</​code>​
 +    - lista de valori: se obține conținutul listei derulante și pe baza ei se determină identificatorul înregistrării din tabela referită, prin intermediul metodei ''​getForeignKeyValue()''​ care primește ca argumente denumirea tabelei, denumirea atributului precum și lista cu valori <code java>
 +if (attributeControl instanceof ComboBox) {
 +  try {
 +    String parentTableValues = ((ComboBox<​String>​) attributeControl).getValue();​
 +    if (parentTableValues != null && !parentTableValues.isEmpty()) {
 +      value = databaseOperations.getForeignKeyValue(tableName,​ attributesLabels.get(currentIndex).getText(),​ Utilities.decompress(parentTableValues));​
 +    }
 +  } catch (Exception sqlException) {
 +    System.out.println("​An exception had occured: " + sqlException.getMessage());​
 +    if (Constants.DEBUG) {
 +      sqlException.printStackTrace();​
 +    }
 +  }
 +} else {
 +  value = ((TextField) attributeControl).getText();​
 +}
 +if (value != null && !value.isEmpty()) {
 +  values.add(value);​
 +}
 +</​code>​
 +  - actualizarea propriu-zisă este realizată prin intermediul metodei ''​updateRecordsIntoTable()''​ care primește ca parametrii denumirea tabelei, lista de atribute, lista de valori precum și condiția pentru înregistrarea care este actualizată (pe baza valorii cheii primare, determinată anterior) <code java>
 +try {
 +  if (attributes != null && values != null && !attributes.isEmpty() && !values.isEmpty()) {
 +    databaseOperations.updateRecordsIntoTable(tableName, ​
 +      attributes, ​
 +      values,
 +      databaseOperations.getTablePrimaryKey(tableName) + "​=\'"​ + tableViewCurrentRecord.get(0) + "​\'"​);​
 +  }
 +} catch (SQLException | DatabaseException exception) {
 +  System.out.println("​An exception had occured: " + exception.getMessage());​
 +  if (Constants.DEBUG) {
 +    exception.printStackTrace();​
 +  }
 +}
 +</​code>​
 +  - popularea tabelei cu noul conținut implică:
 +    - apelarea metodei ''​populate'',​ fără nici un criteriu de selecție;
 +    - selectarea valorii care a fost actualizată:​ ''​tableContentTableView.getSelectionModel().select(tableViewSelectedIndex);'';​
 +  - valorile corespunzătoare selecției curente nu mai sunt vizualizate în cadrul listei de controale; în acest scop se poate invoca metoda de tratare a evenimentului de apăsare a butonului //Clear//, fără nici un argument ca eveniment propriu-zis:​ <code java>
 +clearButtonHandler(null);​
 +</​code>​
 +</​spoiler>​
 +
 +**5**. În clasa ''​TableManagement'',​ din pachetul ''​ro.pub.cs.aipi.lab09.controller'',​ să se implementeze metoda ''​clearButtonHandler()''​ care curăță conținutul câmpurilor text și al listelor de selecție, lăsând completată numai valoarea corespunzătoare cheii primare autoincrementale cu următoarea valoare din baza de date.
 +
 +<​spoiler|Indicații de Rezolvare>​
 +Se parcurge, în cadrul unei iterații, lista de controale, acestea putând avea tipul:
 +  - ''​ComboBox'':​ se folosește metoda ''​setValue()''​ primind ca argument șirul vid: ''​%%((ComboBox<​String>​) attributeControl).setValue(""​);​%%'';​
 +  - ''​TextField'':​ se utilizează metoda ''​setText()''​ primind ca argument:
 +    - valoarea maximă a cheii primare în cadrul tabelei (pentru indexul 0, corespunzător identificatorului),​ prin intermediul metodei ''​getTablePrimaryKeyMaximimValue()'',​ disponibilă în interfața ''​DatabaseOperations'':​ ''​%%((TextField) attributeControl).setText(Integer.toString(databaseOperations.getTablePrimaryKeyMaximumValue(tableName) + 1));​%%'';​
 +    - șirul vid, altfel: ''​%%((TextField) attributeControl).setText(""​);​%%''​.
 +</​spoiler>​
 +
 +**6**. Să se creeze un submeniu ''​About''​ al meniului ''​Help''​ care în momentul când este accesat deschide o fereastră în care sunt afişate pictograma (fișierul ''​icon.png''​ din directorul ''​resources/​images''​) și denumirea aplicaţiei,​ versiunea şi anul în care a fost realizată. Totodată, aceasta va conţine un buton care va închide fereastra atunci când este apăsat.\\ Se poate folosi clasa ''​Dialog''​ în acest sens.
 +
 +<​spoiler|Indicații de Rezolvare>​
 +În clasa ''​Container''​ din pachetul ''​ro.pub.cs.aipi.lab09.controller''​ se instanțiază un obiect de tip ''​Dialog''​ pentru care se specifică următoarele proprietăți:​
 +  * titlul este ''​Constants.ABOUT_WINDOW_TITLE'';​
 +  * locația de la care se va încărca pictograma este ''​Constants.ABOUT_ICON_LOCATION'';​
 +  * mesajul care va fi vizualizat este ''​Constants.ABOUT_MESSAGE_CONTENT''​.
 +Fereastra trebuie afișată prin invocarea metodei ''​start()''​.
 +
 +<code java>
 +Dialog dialog = new Dialog();
 +dialog.setProperties(Constants.ABOUT_WINDOW_TITLE,​ Constants.ABOUT_ICON_LOCATION,​ Constants.ABOUT_MESSAGE_CONTENT);​
 +dialog.start();​
 +</​code>​
 +</​spoiler>​
 +
 +**7**. Să se creeze un buton de căutare la apăsarea căruia vor fi afişate în tabel toate înregistrările care corespund unor anumite criterii (au anumite valori corespunzătoare unor anumite atribute, specificate de utilizator în câmpurile text şi listele derulante, ignorând cheia primară).
 +
 +<​spoiler|Indicații de Rezolvare>​
 +În clasa ''​TableManagement''​ din pachetul ''​ro.pub.cs.aipi.lab09.controller'',​ se va implementa metoda ''​searchButtonHandler()'',​ în cadrul căreia va fi parcursă, în cadrul unei iterații, lista de controale, pentru a se obține perechea de atribute și de valori pe baza cărora va fi realizată căutarea.
 +  - dacă controlul este de tip ''​ComboBox''​ se identifică valoarea din tabela referită corespunzătoare atributului,​ prin invocarea metodei ''​getForeignKeyValue()'':​ <code java>
 +if (attributeControl instanceof ComboBox) {
 +  try {
 +    String parentTableValues = ((ComboBox<​String>​) attributeControl).getValue();​
 +    if (parentTableValues != null && !parentTableValues.isEmpty()) {
 +      value = databaseOperations.getForeignKeyValue(tableName,​ attributesLabels.get(currentIndex).getText(),​ Utilities.decompress(parentTableValues));​
 +    }
 +  } catch (Exception exception) {
 +    System.out.println("​An exception had occured: " + exception.getMessage());​
 +    if (Constants.DEBUG) {
 +      exception.printStackTrace();​
 +    }
 +  }
 +}
 +</​code> ​
 +  - în situația în care controlul este de tip ''​TextField'',​ se identifică valoarea prin intermediul metodei ''​getText()'':​ ''​%%value = ((TextField) attributeControl).getText();​%%''​
 +
 +Se construiește clauza ''​WHERE''​ a interogării pe baza căreia este realizată căutarea folosind șablonul ''​atribut='​%valoare%''',​ aceasta fiind transmisă ca parametru al metodei ''​populateTableView()'':​ <code java>
 +for (Control attributeControl : attributesControls) {
 +  // ...
 +  if (value != null && !value.isEmpty() && currentIndex != 0) {
 +    whereClause += ((whereClause.isEmpty()) ? ""​ : " AND ") + attributesLabels.get(currentIndex).getText() + " LIKE \'​%"​ + Utilities.escape(value) + "​%\'";​
 +  }
 +  currentIndex++;​
 +  // ...
 +}
 +populateTableView(!whereClause.isEmpty() ? whereClause : null);
 +</​code>​
 +</​spoiler>​
 +
 +**8**. Să se creeze o animaţie asupra butonului deasupra căruia se găseşte mouse-ul astfel încât acesta să aibă un efect de tip umbră exterioară ([[https://​docs.oracle.com/​javafx/​2/​api/​javafx/​scene/​effect/​DropShadow.html|DropShadow]]) implementând şi o tranziţie care pe parcursul unei secunde modifică transparenţa de la 1.0 la 0.8 şi scalează dimensiunile cu 0.1. Animaţia trebuie cât timp mouse-ul se găseşte deasupra butonului având un caracter ciclic. Metoda se va implementa pentru toate butoanele ce realizează modificări asupra înregistrărilor din baza de date.
 +
 +<​spoiler|Indicații de Rezolvare>​
 +Se creează următoarele efecte:
 +  - o umbră care va fi aplicată butoanelor (un obiect de tip ''​DropShadow''​);​
 +  - o animație de tip dispariție având transparențele variabile între 1 și 0.8, cu durata de 1 secundă, care se va repeta nedefinit (un obiect de tip ''​FadeTransition''​);​
 +  - o animație de tip scalare, având valorile de 0.1 atât pe axa Ox cât și pe aza Oy, cu durata de 1 secundă, care va rula nedefinit (un obiect de tip ''​ScaleTransition''​);​
 +  - un efect paralel, care include animațiile de tip dispariție,​ respectiv scalare, care vor fi aplicate concomitent (un obiect de tip ''​ParallelTransition''​).
 +
 +<code java>
 +final DropShadow dropShadow = new DropShadow();​
 +final FadeTransition fadeTransition = new FadeTransition(Duration.seconds(1));​
 +fadeTransition.setFromValue(1.0f);​
 +fadeTransition.setToValue(0.8f);​
 +fadeTransition.setCycleCount(Timeline.INDEFINITE);​
 +fadeTransition.setAutoReverse(true);​
 +final ScaleTransition scaleTransition = new ScaleTransition(Duration.seconds(1));​
 +scaleTransition.setByX(0.1f);​
 +scaleTransition.setByY(0.1f);​
 +scaleTransition.setCycleCount(Timeline.INDEFINITE);​
 +scaleTransition.setAutoReverse(true);​
 +final ParallelTransition parallelTransition = new ParallelTransition(fadeTransition,​ scaleTransition);​
 +</​code>​
 +
 +Pentru fiecare buton în parte, se vor defini metodele ascultător pentru fiecare dintre cele două evenimente:
 +  - ''​MouseEvent.MOUSE_ENTERED''​ - se sta stabilește efectul de tip umbră, se transmite nodul ca obiect al animațiilor de tipul ''​Fade''​ și ''​Scale'',​ după care tranziția paralelă este începută , folosind metoda ''​play()'';​
 +  - ''​MouseEvent.MOUSE_EXITED''​ - se pierd efectele anterioare (metoda ''​setEfect()''​ primește argumentul null), durata animației devine 0, animațiile pierd referința de pe nod, iar tranziția paralelă este oprită, folosind metoda ''​stop()''​.
 +
 +<code java>
 +buttonList.stream().map((currentButton) -> {
 +  currentButton.addEventHandler(MouseEvent.MOUSE_ENTERED,​ (MouseEvent event) -> {
 +    currentButton.setEffect(dropShadow);​
 +    fadeTransition.setNode(currentButton);​
 +    scaleTransition.setNode(currentButton);​
 +    parallelTransition.play();​
 +  });
 +  return currentButton;​
 +}).forEach((currentButton) -> {
 +  currentButton.addEventHandler(MouseEvent.MOUSE_EXITED,​ (MouseEvent event) -> {
 +    currentButton.setEffect(null);​
 +    parallelTransition.jumpTo(Duration.ZERO);​
 +    fadeTransition.setNode(null);​
 +    scaleTransition.setNode(null);​
 +    parallelTransition.stop();​
 +    parallelTransition.setNode(null);​
 +  });
 +});
 +</​code>​
 +</​spoiler>​
  
 ===== Resurse ====== ===== Resurse ======
  
-[[http://hadoop.apache.org/docs/​current/​|Hadoop Documentation]]\\  +[[http://docs.oracle.com/javase/8/javase-clienttechnologies.htm|Java Platform, Standard ​Edition ​(Java SE) 8 - Client Technologies]] - secțiunile JavaFX, JavaFX Scene Builder 2\\  
-[[http://it-ebooks.info/​book/​635/​|Tom WHITE, Hadoop – The Definitive Guide, 3rd Edition, O’Reilly, 2012]]\\  +[[http://fxexperience.com/|FX Experience ​- JavaFX News, Demos & Insight]]
-[[http://www.coreservlets.com/hadoop-tutorial|Hadoop Tutorial: Developing Big-Data Applications with Apache Hadoop]]\\  +
-[[http://​hbase.apache.org/​book/​book.html|The Apache HBaseTM Reference Guide]]\\  +
-[[http://​books.google.ro/​books?​id=nUhiQxUXVpMC&printsec=frontcover&​source=gbs_ge_summary_r&​cad=0#​v=onepage&​q&​f=false|Lars GEORGE, HBase: The Definitive Guide, O’Reilly, 2011]]+
  
 ===== Soluții ===== ===== Soluții =====
  
-TODO+[[https://​github.com/​aipi2015/​Laborator09/​tree/​master/​solutions/​eclipse/​09-BookStore-JavaFX|Proiect Eclipse]]\\  
 +[[https://​github.com/​aipi2015/​Laborator09/​tree/​master/​solutions/​netbeans/​09-BookStore-JavaFX|Proiect NetBeans]]
laboratoare/laborator09.1449780747.txt.gz · Last modified: 2015/12/10 22:52 by Andrei Roșu-Cojocaru
CC Attribution-Share Alike 4.0 International
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0