1. Limbajul Java in aplicatii industriale


Evolutia tehnologica din ultima perioada, in mod evident datorata mediului atit economic cit si universitar puternic concurential din lumea capitalista, a dus la o fantastica explozie a industriei electronice, a tehnicii de calcul si informatice. Concurenta acerba impreuna cu cantitatea si nu in ultimul rind calitatea persoanelor implicate in activitatile de cercetare si productie atit in domeniul hardwarelui cit si a softwarelui au determinat salturi tehnologice regulate si la intervale scurte de timp, astfel cei care au fost de fata la nasterea calculatoarelor si la primi pasi in domeniul informatic vor recunoaste cu greu urmasi uriasilor, mari consumatoare de energie si lentelor calculatoare, si cu atit mai greu metodele de programare avansate pe acea vrem in stilurile si filozofiile programarii din ziua de azi.

Cu toate acestea, desi domeniul automatizarilor nu a fost neglijat, performantele dispozitivelor implicate in procesul de automatizare, dublindu-se in fiecare an, in domeniul programarii acestor dispozitive au intervenit foarte putine modificari, folosindu-se in continuare limbaje in cod masina sau asamblare, foarte modeste din punct de vedere a resurselor necesare, si foarte performante ca timpi de executie, dar foarte frustrate la utilizare si mari consumatoare de resurse umane. Unele imbunatatiri, au aparut pe parcursul timpului, cum ar fi compilatoarele de C, care generau codul masina pentru diverse platforme, dar la nivel de microdispoztive per ansamblu lucrurile se desfasoara in aceiasi maniera de o perioada lunga de vreme. La un nivel superior, si ma refer la cel al conducerii proceselor, lucrurile stau cu o idee mai bine, o serie de limbaje de mare calitate si continind tehnologiile de ultima ora au fost dezvoltate si utilizate, si a-si aminti aici ADA, un limbaj care desi conceput in anii 70, inca este viabil si la moda. Totusi, desi avind tangente cu limbajele utilizate in mod curent la dezvoltarea aplicatiilor comerciale, ele erau subseturi specializate pe diferite taskuri sau tipuri de taskuri, si diferite platforme. Ei, toate acestea incepind cu anul 1996 tind sa se schimbe, multumita companiei Sun, care desi nu era activa pe piata echipamentelor de automatizare a sprijinit cercetarile unui inginer in elaborarea unui limbaj de programare destinat echipamentelor de uz casnic. Recunoscind potentialul unui asemenea limbaj, echipa manageriala a companiei a hotarit ca e momentul sa se canalizeze mai multe resurse in aceasta directie, si impreuna cu o strategie de marketing briliant sa i-l impuna in timp scurt pe piata. Piata sesizind potentialul imens al, limbajului de programare propus de Sun, limbaj care intre timp a fost extins in directii deosebite (ma refer la orientarea puternica citre Internet si retele de calculatoare in special, precum si la faptul ca este printre foarte putinele limbaje de programare care au fost gindite in vederea portabilitati totale a codului generat pe diferite platforme) l-a adoptat cu frenezie, ajungind ca firme de renume precum IBM Novel sau Havlet-Packard sa puna o mare baza pe el in planurile lor de viitor.

Obiectul proiectului de fata, este prezentarea limbajului Java si in special a acelor facilitati ale limbajului, care au o importanta mai mare pentru domeniul Informatici Industriale si a Automatici in general. Pentru a demonstra adecvarea limbajului, acestui mediu de problematici, proiectul i-si propune demonstrarea avantajului tehnicilor moderne de programare, programarea orientata pe obiecte, avantaje pe care le aduce din punct de vedere al structurari aplicatiei, al reutilizari codului, si al flexibilitati si extensibilitatii codului astfel scris. Totodata, proiectul i-si mai propune, demonstrarea facilitatilor aduse de limbajul Java, cum ar fi tratarea exceptiilor, faptul ca este interpretat, si multitasking, facilitatile sale legate de Internet si comunicatia de date in general. Toate acesta, prin implementarea unor instrumente virtuale, capabile de comunicatie prin medii eterogene, bazate pe retele de calculatoare si deci capabile de a distribui semnalul. Bazat pe aceste instrumente virtuale se prezinta un simulator de proces, simulatie care tocmai din cauza ca foloseste instrumentele virtuale este foarte aproape de o implementare realista a procesului. Totodata se prezinta o metoda, deosebit de usoara, bazata pe metode vizuale, a de implementa o interfata, a procesului, si de a face procesul public, utilizind o retea locala de calculatore (Internet) sau internetul. Gradul de noutate al temei proiectului precum si al ideilor expuse in el este destul de mare. Metode de monitorizare a unui proces utilizind Internetul, s-au realizat pina in momentul de fata, numai de catre NASA, care este un sistem proprietar, si de doua companii americane, ambele proiecte fiind in stadii incipiente, si toate trei avind ca limbaj principal de implementare limbajul Java.


1.1. Prezentarea generala a limbajului Java


1.1.1. Istoria limbajului Java

 

Java a fost denumit initial Oak, si dezvoltat pentru a fi folosit in aplicati care tinteau de piata bunurilor electronice de larg consum de catre James Gosling. Dupa o perioada de citiva ani de experimentari cu noul limbaj si dupa ce si-au adus contributia o serie de persoane, din care-i amintim pe: Ed Frank, Patrick Naughton, Jonathan Payne si pe Chris Warth, limbjul a fost reorientat catre Internet, redenumit Java si revizuit substantial. Forma final a limbajului a fost definita de catre James Gosling, Bill Joy, Guy Steele, Richard Tuck, Frank Yellin si Artur van Hoff ajutat de catre Graham Hamilton, Tim Lindholm si alti. Aceasta a fost povestea pe scurt, in realitate totul a pornit in anul 1994 cind James Gosling facea parte dintr-o echipa de cercetare izolata in cadrul companiei Sun, echipa care avea ca scop determinarea unor metode de a introduce informatica si calculatoarele in dispozitivele de larga folosinta. Echipa dorea sa realizeze dispozitive cu un grad mai ridicat de interactiune cu utilizatorul uman dar care sa fie capabile sa interactioneze si intre ele. Pentru a-si crea o idee realista despre cum ar trebui sa functioneze si sa comunice aceste dispozitive Green a construit un dispozitiv prototip numit Star7. Acest dispozitiv era o telecomanda operata prin atingerea unor obiecte animate de pe ecranul acesteia. Un utilizator a lui Star7 putea naviga prin atingeri printr-un univers de camere si obiecte, de altfel eroul principal al universului era un omulet (Duke) imortalizat mai tirziu ca mascota limbajului.

Facilitatea cea mai remarcabila a lui Star7 a fost capacitatea lui de a comunica cu alte dispozitive Star7. Un obiect de pe displayul unui Star7 putea fi pasat de la un dispozitiv la altul. Prototipul era un sistem de operare distribuit in care fiecare dispozitiv facea parte dintr-un tot unitar, exact genul de sistem necesar pentru ca un frigider sa-I comunice, de exemplu, aspiratorului ca acesta sa-I comunice operatorului uman ca daca nu este decongelat si curatat nu i-si va mai putea exersa functiile de congelare.

Planul initial a fost ca sistemul de operare pentru Star7 sa fie dezvoltat in C++. Dar dupa cum a afirmat Goshling la conferinta JavaOne din May 1996:


“The tools kept breaking. It was at a fairy early breaking point when I was so disgusted that I went to my office and started typing.”

Asadar, astfel s-a inceput scrierea unui limbaj nou de programare care era mai adaptat acestui tel decit C++, limbajul primind numele de Oak, in cinstea copacului din fata ferestrei sale.

Din start acest limbaj de programare a fost conceput in asa fel incit sa permita crearea de programele mici, fara erori si cu facilitati de comunicare prin retele de dispozitive si calculatoare. Asemanator C++, Oak era orientat pe obiecte, o metoda deosebit de puternica de a crea programe de calculator, si care ofera o multime de avantaje fata de metodele conventionale, dar si impedimentul ca este mult mai dificil de stapinit, dar spre deosebire de acesta a fost conceput tocmai in a facilita o invatare mai usoara fata de restul limbajelor orientate pe obiecte.

Programele Oak, trebuiau de asemenea sa ruleze de o maniera independenta de platforma, deoarece producatori dispozitivelor de larg consum care urmau sa-l foloseasca trebuiau sa aiba abilitatea de a modifica un procesor sau microcontroler mai scump cu unul mai ieftin de cite ori piata le cere sa reduca costul produselor. Iar in contrast cu un posesor de calculator personal, un utilizator al unui produs casnic va fi mai putin dispus sa cumpere un coprocesor pentru a mari puterea de calcul, sa zicem a unei risnite. Pe de alta parte un astfel de consumator va fi mai putin tolerant cu erorile de programare, care ar putea sa-I faca prajitorul de piine inutilizabil. In aceiasi perioada Marc Andersen, un student care lucra la National Center for Supercomputing Applications, crea primul browser pentru World Wide Web, Mosaic 1.0. Pe la mijlocul anului 1994, au gasit World Wide Webul ca fiind foarte promitator din punctul de vedere al limbajului pe care i-l dezvoltau, desi era un servicii mai cunoscut doar in restrinsa comunitate a fizicienilor, oricum browserul grafic a lui Andersen a stirnit un fenomen international, iar Web-ul a devenit rapid un mediu mas-media . Tehnologia dezvoltata de Oak, era perfect pregatita pentru acest mediu, in special datorita capacitatilor sale de a rula pe mai multe platforme si facilitatilor de comunicare prin retele, dar cel mai important a introdus ceva ce nu mai fusese posibil pina atuncea, posibilitatea de a rula aplicatii de pe serverele Web pe calculatoarele utilizatorilor in siguranta.

Patrick Naughton si Jonathan Payne, au terminat WebRunner, un browser de Web care a adus din nou la lumina vedeta proiectului Star7, Duke. Sun realizind ca are ceva promitator in minã se pregãteste de lansarea produsului, doar cã numele de Oak era deja patentat. Astfel dupã o sedintã de brainstorming din Januarie 1995 de a inlocui numele de Oak, numele de Java a fost votat in locul lui Oak si HotJava in locul lui WebRunner, iar in Noiembrie 1995 prima versiune de Java (beta) a fost facuta disponibila pentru oricine pe site-urile, firmei, fiind cautat de zeci de mii de persoane si sute de firme.

E adevarat ca cuptoarele cu microunde nu au devenit mai destepte, dar partea de control nu a fost neglijata cu toate ca versiunea principala nu este conceputa pentru uz industrial sau in dispozitive cu capacitati restrinse, Sun a lansat doua linii paralele de Java, PersonalJava, pentru dispozitive limitate ca si capacitati dar cu posibilitati de afisare, si Embedded Java pentru dispozitive limitate ca si capacitati sau resurse si fara nici un mijloc de afisare.


1.1.2. Descrierea limbajului Java

Limbajul Java a fost conceput pentru a rezolva o parte din problemele informaticii aplicate, astfel caracteristicile lui sint :
Asa cum am mai amintit, unul din dezideratele echipei de ingineri care au proiectat si implementat acest limbaj a fost simplitatea. Analizind cum lucreaza programatorii in general au ajuns la concluzia ca cel mai utilizat limbaj de programare in ziua de azi este limbajul C, iar pentru cei care lucreaza in tehnologie orientata pe obiecte utilizeaza limbajul C++. Desi au pornit de la premiza ca limbajul C++ nu asigura suport suficient pentru nevoile lor, au incercat sa aduca limbajul Java cit mai aproape de sintaxa limbajului C++, tocmai pentru a fi mai usor de invatat, si pentru a reduce timpul de adaptare al utilizatorului la noul limbaj. Mai mult, au fost eliminate acele facilitati care in opinia expertilor produceau mai multa confuzie, decit sa aduca beneficii, astfel printre elementele eliminate din Java si care subzista in limbajul C++, se pot enumara:
S-au adaugat facilitãti de ultima ora, dintre care putem aminti, managmentul automat al memoriei, (“ automatic garbage collection”) , simpificind imens munca programatorului, in schimbul complexitati mai ridicate a sistemului. O sursa comuna generatoare de complexitate si probleme, este gestionarea memoriei, alocarea si eliberarea ei, la momente bine specificate de timp. Prin facilitatea oferita de un mechanism automat de gestionare a memoriei a carui functie primara s-ar putea descrie prin dealocarea resurselor nefolosite in mod automat. Prin aceasta s-a reusit nu numai inlesnirea muncii programatorului, dar si reducerea imensa a timpului necesar finalizarii unui proiect, deoarece eliminind problema gestionarii memoriei se elimina automat cea mai mare sursa generatore de scame, bug-ri.

Un alt aspect al faptului de a fi simplu este de a fi mic, conceput special penru dispozitive cu capacitati reduse (microcontrolere, etc), deci capabil de a rula in astfel de dispozitive, interpetorul limbajului cit si librariile acestia au dimensiuni foarte reduse.

Orientat pe obiecte inseamna destul de mult pentru lumea programatorului, dar din pacate aceasta functionalitate nu a fost oferita programatorului automatist, nu pina acum. S-a facut destul de multa vilva in jurul acestei notuni in ultima perioada, dar adevarul este ca folosind modelul programarii orientat pe obiecte se pot elabora programe mult mai clare, mai curate si mai apropiate de modul de gindire uman, ca sa nu mai amintim de reutilizare codului. Descris foarte pe scurt, tehnica pune accentul pe date (obiecte), si pe metodele de a le acesa. O analogie larg folosita in literatura de specialitate este cea a timplarului. In tehnologia orientata pe obiecte un tinplar ar fi concentrat in special pe scaunul pe care-l construieste, si abia pe urma cu uneltele cu care sa-l contruiasca. In metodologiile neorientate pe obiecte, motivul principal de ingrijorare al tinplarului ar fi uneltele cu care sa construiasca scaunul si abia pe urma cu scaunul. De asemenea modelul orientat pe obiecte, ofera mecanismul pentru a defini cum modulele se interconecteaza intre ele. In esenta facilitatle din puncul de vedere al orientarii pe obiecte, sunt cele oferite de limbajul C++, extinse cu facilitatile oferite de Objective C pentru a oferi o dinamica mult mai mare metodelor sale.

Suportul oferit pentru retele de calculatoare este deosebit, este adevarat ca nu este singurul limbaj de programare care ofera acest tip de suport, dar modul in care este integrat in limbaj, si usurinta cu care se implementeaza mecanisme deosebit de complexe il face unic in acest domeniu. Librariile si rutinele implementate asigura suport pentru protocoale TCP/IP precum HTTP si FTP. Se poate afirma ca este mult mai simplu si usor de a realiza o conexiune in retea utlilizind limbajul Java decit limbajele C sau C++, programatorul reusind sa aceseze obiecte din retea aproape la fel de simplu si usor de parca s-ar lucra cu sistemul local de fisiere.

Robustetea limbajului este asigurata de o serie de mecanisme de inalta performanta, cum ar fi verificarea timpurie a programelor pentru posibile probleme, verificare dinamica tirzie (runtime), si fortarea programatorului sa elimine situatiile care sunt presupuse ca ar putea genera probleme la rulare. Unul dintre avantajele limbajelor puternic tipizate (cum ar fi C++) este ca asigura un puternic suport pentru verificarea programelor in timpul compilari in idea de a elemina un numar cit Mai mare de errori, din pacate limbajul C++ mosteneste o serie de probleme la verificarea in timpul compilarii tocmai din C, si acesta doar pentru a pastra compatibilitatea in jos. Deoarece Java nu are ce cobatibilitate in jos ce sa mentina, nu este nevoit sa suporte consecintele unor implementari sau specificatii vechi proaste sau incomplet facute. Un exemplu, declaratiile, pe cind in C++, se permit declaratii implicite ale variabilelor, functiilor sau procedurilor (tocmai mostenite din C), Java este foarte sever in declararea exacta a lor. Chiar si linkeditorul mai repeta aceleasi verificari pentru a fi sigur ca nu apar probleme de incompatibilitati intre tipuri de date folosite.

Cu toate acestea cea mai mare diferenta intre limbajul Java si C, este ca din Java sau eliminat complet pointerii. Motivul pentru acesta actiune radicala este ca, pointerii reprezinta un mecanism deosebit de priculos din punctul de vedere al posibilelor probleme pe care le pot genera (errori foarte dificil de gasit si corectat), si o potentiala problema de securitate, data de nerestrictionarea accesului lor (este deosebit de usor sa scriem/citim dintr-o zona de date interzisa, respectiv sa corupem date, in mod intentionat sau nu). Mecanismul folosit in schimb este cel al handlerelor si al tablourilor reale de date, nefiind permisa modificarea unui tip intreg de date intr-un handler, si astfel accesarea necontrolata a unei zone de memorie. Prin aceste modificari (inbunatatiri) problemele de asigurarea calitatii (QA) din pacate nu dispar, munca devenind insa incomparabil de simpla.

Firmele profesioniste de software folosesc, de obicei, limbaje foarte dinamice cum ar fi: TCL; Lisp; Smaltalk, in fazele de elaborare a prototipului de aplicatie tocmai din aceste cauza ca aceste limbaje sunt foarte robuste, nefiind nevoiti sa-si faca griji din pricina eliberarii memoriei sau coruperea datelor. Programatorii Java putind fi relativ fara griji, din pricina lucrului cu memoria, tocmai din cauza ca nu trebuie sa lucreze direct cu ea. Din cauza ca nu sunt pointeri nu trebuie sa-si faca griji ca ar putea depasi, limitele vectorului cu care lucreaza si sa suprascrie accidental alte date, sau sa capate acces neutorizat la zone de memorie care nu-I apartin, fenomene care, din pacate, se pot intinpla in C sau C++.

Un motiv pentru care limbajele dinamice sunt bune pentru elaborarea prototipurilor este ca ele nu te oblica sa iei decizii explicite de implementare prea devreme. Java se apropie de acesta problema dintr-o alta directie, te obliga sa implementezi stratregiile explicit deoarace la baza are o legare dinamica fortata de compilator, dar odata cu aceste implementari sunt insotite o serie de ajutoare sau Mai degraba asistenta, deoarece de exemplu la invocarea unei metode, daca se obtine ceva gresit programatorul este instiintat in timpul compilarii si nu in timpul executiei, cind invocarea respectiva se intinpla efectiv.

Securitatea a fost deasemenea un punct vizat pe parcusul elaborarii limbajului, si aceasta cu atit mai mult cu cit a fost vizat sa atinga mediile orientate pe retele si programare disribuita, permitindu-se construirea de medii eliberate de virusi sau programe cu intentii obscure, impelemntand de asemenea si librarii de functii avansate de criptografie, majoritateta bazate pe tehnologii de ultima ora (chei publice). Exista o puternica interdependenta intre robustete si securitate, eliminindu-se pointerii se elimina practic orice metoda de a forta accesul la structurile de date al altor aplicatii sau la accesarea membrilor protejati sau privati la care in mod normal nu au acces, din cadrul programului, aceasta inchizind usa in fata majoritati cailor de acces a virusilor.

Neutralitatea fata de aritecturile calculatoarelor pe care se ruleaza, a este cerinta principala a unui limbaj puternic orientat catre alicatii distribuite, deoarece o aplicatie distribuita presupune existenta unui mediu, de obicei neomogen de sisteme, interconectate intr-un anume fel, in mod uzual prin retele de calculatoare. Pentru a permite unui program sa se execute pe o varietate de procesoare si pe o varietate de sisteme de operare, compilatorul generaza un fisier intr-un frmat ce contine obiecte neutre din punct de vedere arhitectural (“ architecture-neutral object file-format”) , fisier ce contine codul compilat, in acest fel capabil sã se execute pe o diversitate de arhitecturi. Acesta este folositor nu numai pentru aplicatii distribuite, dar si pentru programele normale (generale), deoarece nu mai este nevoie de a scrie versiuni diferite sau customizate pentru anumite medii, fiind suficienta elaborarea unei singure versiuni care nici macar nu trebuie recompilata pentru a rula pe diferite platforme, rulind instant. Acest fapt este un progres semnificativ avind in vedere tendintele actuale din domeniul industriei producatoare de sisteme de calcul, si ma refer la piata calculatoarelor care incepe sa se diversifice (prin Windows/NT) pe din ce in ce Mai multe arhitecturi de procesoare, si la tranzitia firmei Apple dinspre arhitecturile bazate pe microprocesoarele 680x0 inspre PowerPC-uri. Java atingind acest deziderat atit prin generarea unui cod obiect indebendent de platforma, cod binar, care a fost optimizat tocmai in vederea obtinerea independentei de platforma cit si in vederea executiei usoare sau a transformari, din zbor, in cod masina specific platformei respective.

A fi independent de platforma este doar primul pas spre a fi complet portabil, si contrar de exemplu limbajelor C sau C++, nu exista specificatii, librarii, tipuri de date dependente de platforma implementate in Java. Tipurile primitive de date, la fel ca si operatiile asupra lor sunt specificate si implementate in mod unitar, indiferent de tipul procesoarelor pe care vor rula (8, 16, 32 sau 64 de biti). De exemplu un intreg int va insemna intotdeauna un intreg cu semn reprezentat in complement de doi pe 32 de biti, iar tipul float va insemna intotdeauna un numar in virgula flotanta conform specificatiilor standardului IEEE754. Librariile care sunt parti ale sistemlui definesc interfete portabile, de exemplu exista o class fereastra abstracta si implicit implementarile ei pentru sistemele de operare: Unix, Windows 95, Windows NT si Machintosh.

Insusi Java ca atare este destul de usor portabil, compilatorul fiind scris in Java, si deci implicit portabil, iar mediul interpretor este scris in ANSI C, cu un comportament curat si destul de portabil fiind bazate pe un subset al POSIX-ului.

Codul binar Java este translatat din zbor in cod masina nativ, nefiind deci nevoie de vre-o metoda de stocare, precum si datorita faptului ca procesul de linkeditare este unul incremental si nu foarte costisitor ca resurse, procesul de dezvoltare este mult Mai rapid si ofera mult Mai multe grade de libertate de experimentare, Deasemenea tot datorita fluxului de cod binar proprietar sistemului Java, Mai multa informatie este stocata in formatul binar, facind astfel operatia de debuging mult nmai facila, ne Mai vorbind de faptul ca un dezansamblor, este in masura sa restabileasca codul in procent de aproape 100% la forma sa initiala, lucru care la alte limbaje este practic imposibil. La conceperea formatului byte-codeului s-a tinut cont de faptul ca acesta uremaza a fi intrepretat si transformat direct in cod masina specific platformei pe care se lucreza si deci este putenic optimizat, realizind in timpul conversiei si optimizarile necesare. Din studiile de performata realizate de catre firma Sun, a rezultat un numar de 300.000 de apeluri de metode pe secunda, rezultat obtinut pe un calculator Sun Microsystems SPARCStation 10, performantele conversiei codului binar in cod masina, fiind la aproape la fel de bune ca si a rulari unui program C, nativ.

Bineinteles, nu se putea concepe un limbaj nou in ziua de azi fara a asigura suport pentru multithreading. La fel ca in lumea care ne inconjoara, unde Mai multe lucruri se intinpla simultan, acelasi lucru se poate face, sau simula si pe calculatoarele noastre, numai ca a scrie un program multithreding nu este chiar atit de simplu nici macar in limbaje ca C sau C++. Java are insa un puternic set de mecanisme care sa asigure sincronizarea primitivelor, mecanisme bazate pe raspinditele metode de monitorizare si conditionare introduse de C.A.R.Hoare. Integrind toate aceste mecanisme in nucleul limbajului ele devin mult Mai simplu, robust si Mai usor de folosit. Un alt avantaj al multithreadingului sunt un raspuns mult mai interactiv si comortament in timp real. Bineinteles, acesta este limitat de platforma care aigura tot suportul pentru aplicatie, mediul, ca atare Java avind un bun raspuns in timp real, dar rulind deasupra unor sisteme de operare, precum: Unix, Windows95, Windows NT, Machintos, raspunsul sistemului si modul de tratare al taskurilor este cel care determina raspunsul in timp real al aplicatiei scrise in Java.

Dinamicitatea limbajului o depaseste de asemenea pe cea limbajelor conventionale, bunaoara daca o companie oarecare A, produce o librarie, sau o componenta activa, si o companie B o cumpara si foloseste, si compania A produce o noua veriune a aceleiasi componente atunci pentru a o integra compania B trebuie Mai mult ca sigur sa-si recompileze intreaga aplicatie si sa o redistribuie din nou clientilor sai.

Facind conexiunile intremodule de abia la rulare, Java elimina cu succes si total acest tip de probleme, indiferent cite modificari ar fi intervenit in libraria producatorului A (cu pastrarea compatibilitatii, totusi), Java se va executa fara recompilari si probleme.

Acest mecanism este sprijinit de modul cum sunt concepute aplicatiile Java, o interfata specifica un set de metode si de obiecte pe care le poate executa, dar nuspecifica si cum trebuie executate O clasa implementeaza o interfata implementind toate obiectele si metodele interfetei. De asemenea mostenirea paseaza atit metodele cit si implementarea lor de la superclasa la subclasa. O clasa este capabila sa mosteneasca numai o singura clasa, dar poate implementa cite interfete doreste. Deci se poate observa ca interfetele promoveaza reutilizarea codului, si conecteaza elementele intre ele specificind Mai degraba ce se conecteaza si nu cum se face. Un alt avantaj este identificarea in timpul rulari al tipului de data, si acesta printr-un mecanism foarte ingenios. Fiecare instanta de obiect are o metoda numita getClass prin care se poate determina din ce clasa sa instantiat metoda respectiva, si in acest mod se poate determina foarte elegant tipul obiectului respectiv. Acesta facilitate este, de exemplu inexistenta in C sou C++. Tot prin aceasta metda se executa si verificarile de rigoare din timpul rularii, si aceasta deoarece in Java programele sunt verificate atit in timpul compilari cit si in timpul rulari. Astfel, se poate avea deplina incredere in conversiile de date executate in Java, deoarece sunt verificate de doua ori, pe cind bunaoara in C sau C++, limbajul merge pe incredere, se bazeaza pe faptul ca programatorul a executat o conversie de date (cast) corecta, cea ce nu intotdeauna este adavarat, din pacate. Ba chiar ca o facilitate in plus, se poate cauta (in timpul rulari), o clasa specificindui numai nuele intr-un sir de charactere, si chiar Mia mult odata gasita, clasa se poate incarca si instantia, oferind un dinamism complet aplicatiilor (acesta tehnica este dealtfel folosita si in cadrul acestui proiect, si va fi exmplificata pe larg in capitolele urmatoare.

Ca o prima concluzie putem desprinde, ca limbajul Java se dovedeste a fi o puternica unealta de dezvoltare, dotata cu facilitati de ultima ora, care se afla la dispozitia programatorului. Java, face programarea mult Mia usoara, deoarece este orientat pe obiecte, si are management automat al memoriei, aditional deoarece codul compilat este neutru din punct de vedere arhitectural, limbajul este ideal pentru diverse aplicatii orientate pe Internet.



1.1.2.1. Principii de implementare


Java prezinta un nou punct de vedere, in evoutia limbajelor de programare, crearea unui limbaj simplu, mic si familiar care este totusi suficient de comprehesiv pentru a se adresa unei varietati largi de problematici, in cadrul procesului de ezvoltare de programe. Pe cind Java arata la suprafata ca si C sau C++, el si-a cistigat simplitatea prin eliminarea unor facilitati care produceau confuzie, sau impuneau o compatibilitate in jos care nu i-si Mia avea sensul. In acest subcapitol se vor discuta doua dintre faciltatile primoridiale reentate de Java, si anume, simplu (prin eliminarea anumitor facilitati) si familiar (deoarece arata ca si limbajul C si C++).

Simplitatea a fost principalul obiectiv impus de catre echipa de programatori care au implementat si specificat acest limbaj. Simplitatea si eliminarea sistematica a multor facilitati de o valoare “dubioasa” din familia de limbajele C si C++, sau din predecesori lor, au mentinut Java la o dimensiune mica, si au redus efortul programatorrilor de a produce aplicatii reliabile. Pina al finaliza echipa care a conceput Java au analizat toate facilitatile pe care le au lmbajele de programare “moderne ” din familia limbajelor C si C++, pentru a determina facilitatile care trebuie introduse sau eliminate in contextul unei limbaj de programare orientat pe obiecte modern.

Un alt deziderat major, a fost familiaritatea, pentru majoritatea programatorilor atit din sfera calculatoarelor personale cit si din cea a statiilor puternice de lucru, unde marea majoritate a programatorilor atit din sfera programatorilor sistem cit si a celor de aplicatii cunosc limbajul C sau C++. Astfel programatori, care sunt familiarizati cu unul sau Mia multe din limbajele urmatoare: C, Objective C, C++, Eiffel, Ada, si alte limbaje aferente, ar trebui sa observe ca curba de invatare a limbajului Java este foarte scurta, de ordinul saptaminilor.

Pentru a demonstra simplitatea limbajului, vom continua traditia de a prezenta vesncul exemplu al cartilor de programare, cu care se incepe, teoretic orice curs de programare, si anume “Hello world” :


class HelloWorld {
static public void main (String args[]) {
System.out.println(“Hello World !”);
}
}

Acest exemplu nu face altceva decit sa afiseze, un simplu text “Hello World!” la consola, si o face aceasta declarind o clasa HelloWorld. Din cite se poate vedea clasa noastra are numai o singura metoda, numita main. Aceasta metoda are din cite se poate observa numai o singura linie, linie care nu face altceva decit sa tipareasca, textul din ghilimele la consola. Aceasta se face prin metoda println, din obiectul out care face parte din clasa System, clasa care opereaza diverse operatii de intrare-iesire pe fisiere.

1.1.2.2. Tipuri de date

Absoulut totul exceptind, tipurile de date discutate aici sunt obiecte. Fiecare din aceste tipuri de date primordiale pot fi “infasurate”, utilizind anumite metode din librariile standard ale limbajului, in obiecte. Deci la nevoie si aceste tipuri primitive de date pot fi transformate in obiecte, beneficiind astfel de toate avantajele obiectelor in limbajul Java.
1.1.2.2.1 Tipuri numerice
 
Tipurile de date intreg sunt: 8-biti byte , 16-biti short , 32-biti int, si 64-biti long Tipul pe 8 biti byte a inlocuit vechiul tip de data din C si C++ char, si asta deoarece in Java s-a implementat un tip specific de character, char, dupa cum se va veda Mia jos. Nu Mia exista tipuri de date fara semn.
Tipurile reale de intregi sunt: 32-biti float , si 64-biti double . Tipurile reale de date din Java precum si operatiile aritmetice aupra lor au fost implementate conform standardului IEEE 754.
1.1.2.2.2 Tipul Character
 
Tipul standard de character din Java, este puternic delimitat de cel din implementarea pe care o furnizeaza C. Tipul de data character, char este implementat pe 16 biti in contradictie cu implementarile marii majoritati a limbajelor de programare care asigura o baza de numai 8 biti. De ce aceasta diferenta. Acesta este reprezentarea impusa de modul de codificare UNICODE al caracterelor, care a urmat modului ASCII folosit in majoritatea programelor, aplicatiilor si sistemelor de operare. Codurile UNICODE sunt valori vara semn, cuprinse in domeniul 0 - 65.535 , deci stocate pe 16 biti. Adoptind standardul UNICODE limbajul Java devine un limbaj ideal pentru a asigura suport deoasebit de larg pentru aplicati internationalizate.
1.1.2.2.3 Tipul Logic
 
Java a mai adaugat si tipul de data logic, ca tip de data fundamental, astfel o variabila booleana poate avea valorile true sau false. Acest tip de data este distinct si bine fundamentat, si nu poate fi convertit la voia intinplari, ca si valorile similare din C si C++, in orice valoare numerica.
1.1.2.2.4 Operatori logici si aritmetici
Operatorii logici si cei aritmetici sunt cei tipici limbajului C de exemplu, si tocmai din acest motiv nu vor fi discutati aicea. Totusi din cauza inexistentei tipurilor de date fara semn, s-a introdus un operator aritmetic nou “>>>” care satisface operatia de rotirea la dreapta a unei variabile de fãrã semn (tip de data logic). Un alt operator la care I sa adãugat o semnificatie noua este “+” care implementeaza, in cazul sirurilor de caractere operatia de concatenare.
1.1.2.2.5 Tablouri
 
Spre deosebire de C, tablourile sunt in Java tipuri de date primare. Tablorile sunt obiecte reale cu o reprezentare bine specificata in timpul rularii, ele se pot aplica oricarui tip de data, si se pot aloca tablouri de tablouri pentru a obtine tablouri multidimensionale. Declararea unui tablou se face de exemplu:
Point myPoints[];

In acest fel am declarat un tablou de obiecte de tip Point, clasa care am definit-o in alta parte. Dar in acest moment avem numai un tablou neinitializat, la care singura locatie de memorie alocata este cea a handlerului tabloului (un handler este un fel de poiter, cu deosebirea ca asupra lui nu se pot efectua operatii). In continuare trebuie alocat spatiu suficient de stocare pentru tablou conform necesitatilor. Acesta se poate face, simpu precum se poate vedea in exemplul urmator:
MyPoints = new Point[10]
Astfel sau alocat un spatiu de zece elemente, de tipul Point, dar care in acest moment toate au valoare nula. Deci, deoarece avem alocat numai spatiu pentru obiectele noastre trebuie create si obiectele, aceasta se poate face in modul urmator:
int i;
for (i = 0 ; i < 10 ; i++) {
myPoints[i] = new Point();
}
 
Accesul la elementele tabloului se face in mod identic cu accesul din limbajul C, dar spre deosebire de C, tobloul este continu verificat pentru a nu depasi dimensiunea maxima declarata si astfel sa corupa spatiul de memorie al altor variabile sau date. In caz ca totusi sa depasit dimensiunea declarata, o exceptie este generata, despre excepti, modul cum sunt tratate si declarate, vom vedea in capitolele urmatoare. Faptul ca un tablou este un obiect de sine statator, ii permite sa aiba propriile metode, astfel o metoda pe care o putem aplica oricarui tablou este length() , metoda care permite determinarea numarului de lemente dintr-un tablou. Metoda de implementare a tablourilor din C a disparut, si odata cu ea si pointerii la tablou, cu ajutorul carora se putea face o parcurgere a tabloului, pina la ultimul element si, din pacate chiar si dupa, el ducind la unul dintr cele mai groaznice tipuri de erori, cele intirziate, si care se pot manifesta dupa spatamini sau luni de rulare, si a coror sursa este deosebit de greu de depistat, erori si tipuri de erori pe care Java le-a eliminat coplet, prin mtodele de verificare si de constringeri (in sens constructiv) pe care le impune.

1.1.2.2.6 Siruri de caractere

Sirurile de character sunt de asemena elemnte primitive ale limbajului, tip de obiect de sine statator, si nu un simplu tablou de charactere ca si in limbajul C sau C++. De fapt, Java are chiar doua tipuri de siruri de caractere, unul fiind “ String” care reprezinta siruri de caractere dar care sunt imuabile, pot fi numai citite, (adica la orice operatie executata asupra sirului, de fapt se creaza un sir de caractere nou, lasindu-se nemodificat cel vechi), iar celalat obiect care reprezinta siruri de charactere fiind “ StrinBuffer”, acesta opereaza direct asupra sirului initial, modificindu-l.

1.1.2.3. Managementul memoriei si colectarea reziduurilor


In aproape toate limbajsele de programare, managementul memoriei, alocarea, gestionarea si eliberarea memoriei, revenea in sarcina programatorului, acesta activitate ocupind timp si necesitind atentie sporita. Munca nu era usoara, a tine minte tot timpul cind se poate elibra o anumita resursa, cind si mai ales cum sa se gestioneze aceste resurse, pentru a nu se ajunge la situatia in care programul, are nevoie de resurse, dar din pacate sunt ocupate, si nu intotdeauna ar trebui sa fie. Pe linga sursa continua de stres pe care o consituie, mai reprezinta sursa unui rau mult mai mare, scame de programare, blocaje, scurgeri de memorie, si nu in ultimul rind performante slabe. Limbajul Java preia complet presiunea acestei munci de pe umeri programatorului. Pointeri in stilul limbajului C, aritmetica cu pointeri, malloc, si free nu mai exista. Recuperarea automata a memoriei, “Garbage colection”, ia preluat locul, facind parte integranta din mecanismul de rulare a programelor Java. Desi exista o functie new pentru alocarea memoriei pentru diverse obiecte, Java nu are o functie free explicita. Obiectul odata creat de catre utilizator, mecanismul de management al memoriei, preia controlul, urmarind tot timpul evolutia obiectului, in momentul in care nu se mai face referire la obiectul respectiv, pe tot restul programului, memoria ocupata de obiect este eliberata, permitind crearea a noi obiecte in schimb.
Problema care se pune in mod natural, este care sunt sacrificiile de performante pe care le determina acest, sistem, care aduce avantaje in primul rind dezvoltatorilor de aplicatii si nu neaparat clientilor. Ei pierderile de perforanta sunt minore daca nu chiar nesemnificative, si toate acesta deoarece, sistemul Java executiv, ruleaza managerul de memorie intr-un task separat, in fundal avind prioritate foarte mica. Aceasta inseamna, deobicei atunci cind aplicatia nu ruleaza in mod intens, cind se asteapta o reactie din partea utilizatorului, deci deobicei cind procesorul nu este in cursul unei actiuni sau operatii. Managerul de memorie mai resolva si un alt tip de probleme care de obicei necesita, scheme de programe deosebit decomplexe. Prin alocarea succesiva, si eliberarea de resurse de memorie, se produce un fenomen numit fragmentarea memorie, fenomen care are ca efect negativ, imposibilitatea alocarii unei anumite cantitati de memorie, pe care sistemul o raporteaza ca disponibila, dar care din cauza ca, memoria disponibila nu se regaseste intr-o zona continua nu o poate aloca. Managerul de memorie realizeaza si defragmentarea memoriei, defragmentare care nu ar fi posibila, daca de exmplu s-ar di pastrat mecanismul de pointeri atit de larg utilizati in limbajul C de exemplu. Prin mecanismul de accesare a obiectelor implementat de Java, aceasta nu mai constituie o problema, obiectele putind fi mutate dintr-o zona de memorie in alta, modificindu-se adresa spre care directioneza handlerul obiectului.

1.1.2.4. Mecanisme de Multithreading si sincronizarea lor


Implementind mecanismele de multithreading direct in limbaj, si nu numai la nivel de librari, facilitatile oferite de diverse obiecte Thread precum si suportul oferit de catre executivul Java, ofera o usurinta, performanta si simplitate greu de gasit la alte limbaje. Deasemena chiar daca nu se construiesc aplicati cu mai multe fire de executie, simplitatea mecanismelor de sincronizare permit implementarea aplicatilor de asa natura incit trecerea lor la o aplicatie cu mai multe fire de excutie sa fie o banalitate si sa prezinte un grad de securitate foarte mare .

1.1.2.5. Elemente eliminate din Limbaj


Printre primele lucruri, avute in vedere in a nu fi implementate, a fost redundantele. Este cunoscut modul in care mai multe functii si proceduri C sau C++, se incaleca, existind prea multe metode de a raliza aceiasi functionalitate, care in sine nu este neaparat negativ ci mai degraba inutil, si nerezolvare, sau neoferirea de soluti pentru unele clase de probleme.
Un alt element forte este eliminarea totala a elementelor de context si preprocesare. Eliminind acestea sursele Java devin foarte simplu si facil e inteles. Impatimitii limbajului C sau C++, i-si vor pune in mod natural intrebarea, de ce, si cum se implementeaza in acest caz, anumite mecanisme.
Raspunzind pe rind la intrebari, pentru a mentine simplitatea si claritatea codului. Avind sursele unui program C sau C++, primul lucru care trebuie facut este studierea headerelor, intelegera defines –urilor, si a typedef –urilor. Inainte de a parcurge aceste etape, programatorul nu are nici o sansa de a intelege ce se intinpla in cadrul acelor surse. Si fiindca raul nu vine nicioda singur, nu exista stiluri impuse pentru standardizarea acestor sectiuni, fiecare programator avind propriul stil de a implementa aceste elemente, cea ce contravine flagrant cu principiile unei programari de calitate. Raspunzind la a doua intrebare, s-ar putea spune ca aceste mecanisme nu se mai justifica. In Java efectul unui #define se poate obtine, folosind constate. Efectul unui # typedef, se optine creind, pur si simplu o clasa noua, dealtfel, orice clasa in Java reprezinta un nou tip de data. Existenta fisierelor de header nu mai este justificata pe de o parte de introducerea notiunii de pachete, pe de alta parte din cauza stocarii a suficiente informatii in formatul binar la compilare pentru toate tipurile de date folosite, pina la rulare cind se efectueaza si operattia de linkeditare. Astfel programatorii pot citi si intelege codurile mult mai usor nemaivorbind de partea mult mai importanta, modificarea surselor de programe existente facilitind astfel refolosirea codului.
De asemenea sau eliminat structurile sau multimile, deoarece o clasa asigura aceiasi functionalitate. Pentru a demonstra acesta putem considera urmatorul exemplu:

public class Point extends Object {
double x;
double y;
// urmeaza metodele de accesare a variabilelor
// de instanta
}
 
Aceasta bucata de cod defineste o clasa care reprezinta modelul unui punct in spatiu bidimensional. Avind definitia unui punct putem defini structuri de date mai complexe, cum ar fi un patrat. Definitia unei clase care sa surprinda proprietatile unui patrat ar fi:

class Rectangle extends Object {
Point stingaSus;
Point dreaptaJos;
// metode de accesare a variabilelor de instanta
}


Acesta s-ar reprezenta intr-un limbaj neorientat pe obiecte printr-o structura, in Java ea este simplu definita ca o clasa. Un avantaj al clasei fata de structuta este ca se pot specifica modificatori de acces la aceste variabile. Astfel, fiecare din variabile de instanta pot fi facute private, publice sau protejate dupa dorinta si necesitati permitind ascunderea sau afisarea dataliilor de implementare a obiectelor instantiate din aceste clase.
Un element care intentionat nu s-a inclus in limbajul Java au fost functiile. Un model orientat pe obiecte, este mult superior functional unui model procedural. Combinarea celor doua stiluri, nu ar duce decit la confuzie si ar dilua puritatea unui limbaj orientat pe obiecte. Toata functionalitatea obtinuta printr-o functie poate fi la fel de bine obttinuta definind o clasa si construindui metodele necesare. Considerind exemplul anterior, ne propunem sa construim metodele de acces la variabilele de instanta.

public class Point extends Object {
private double x;
private double y;

public void setX (double x) {
this.x = x;
}

public void setY (double y) {
this.y = y;
}

public double x() {
return this.x;
}

public double y() {
return this.y;
}

}


Se poate observa ca variabile x si y, sunt declarate ca fiind private, acesta permite ascundera detaliilor de implementare, ele putind fi accesate numai prin intermediul metodelor de acces. In acest mod, modul de implementare intern pe parcursul timpului poate fi modificat, programatorul care utilizeaza aceasta nu poate face apel la nimic ce este declarat privat, el comunicind cu clasa prin cele patru metode puse la dispozitie, aplicindu-le modificatorul public.
Un alt mecanism care nu se regaseste in Java, si care de acesta data, este de domeniul programarii orientate pe obiecte este mostenirea multipla. Un mecanism similar fiind intrrodus, pentru a permite numai avantajele mostenirii multiple sa se implice in Java nu si dezavantajele ei. Mecanismul este similar cu cel inplementat in Objective C, si poarta denumirea de interfete.
O interfata nu este o definitie a unui obiect, ci mai degraba o definitie a unui set de metode pe care acel obiect urmeaza sa le implementeze. Un aspect interesant al interfetelor este ca ele pot declara numai metode sau constante si nici intr-un caz variabile.
Concluziile par a fi clare, Java este:
 
Simplu – deoarece numarul structurilor care trebuie invatat si intelese pentru a realiza ce ne-am propus este minim
Familiar - deoarece Java arata ca si C sau C++, exceptind bineinteles partile confuze ale acestor limbaje care au fost eliminate.

Tehnologii avansate de programare, implementate de Java cu potential in automatizari


1.2.1. Programarea orientata pe obiecte


Pentru a rezista in fata limbajelor de programare din ziua de azi, Java este construit de la baza in ideea programarii orientate pe obiecte. Paradigma orientari pe obiecte, acopera foarte bine necesitatile programelor client-server sau aplicatiilor distribuite. Din pacate , termenul de orientat pe obiecte ramine putin inteles, fiind de obicei considerat leacul minune care rezolva orice problema, si transforma aplicatiile prost concepute in aplicatii bune. Versiunea cinica asupra orientarii pe obiecte afirma ca este numai o alta metoda de a organiza datele, si desi este o portiune de adevar in aceasta afirmatie, ea nu acopera totul, realitatea fiind ca sunt lucruri care folosind metodologia programarii pe obiecte pot fi implementate si care prin metodele standard, procedurale, sunt imposibil de realizat.
Pentru a putea vorbi de programare orientata pe obiecte trebuie amintite elementele sau facilitatile care stau la baza ei. Deci caracteristicile de baza a orientarii pe obiecte sunt:

Ideea de baza, este organizarea programelor de asa maniera, incit sa reflecte, obiectele din lumea reala.

1.2.1.1. Definitia obiectelor


Exprimat simplist, tehnologia orientata pe obiecte este o colectie de metodologii de analiza, proiectare si programare care se concentreaza pe modelarea caracteristicilor si comportamentului obiectelor din lumea reala. Definitia data pare a fi una tautologica, asa ca o descriere mai naturala poate fi formulata in felul urmator: sunt modele software de programare.
In viata de zi cu zi suntem inconjurati in permanenta de obiecte: masini, copaci, tot felul de automate, etc. Aplicatiile software contin de asemenea obiecte cum ar fi: butoane pe interfata cu utilizatorul, tabele, celule de tabele, meniu, si multe altele. Aceste obiecte se pot caracteriza prin o stare si un comportament. Toate acestea se pot modela prin componente software, care la rindul lor se pot caracteriza prin stare si comportament.
Orice element din lumea care ne inconjoara, fie element natural, fie artificial poate fi modelat ca un obiect. De exemplu, o turbina poate fi modelata ca un obiect avind ca elemente de stare, dimensiunea, numarul de palete, turatia cu care se invirt, iar ca comportament, se poate spune, ca o turbina poate fi pusa in functionare, poate fi oprita, se poate defecta, si asa mai departe. Un alt exemplu am putea pe care putem sa-l consideram, ar fi un regulator, atit de folosit in automatizari, astfel se poate spune ca are ca stare, valoare semnalului curent, iar ca si comportament, genereaza un semnal, preia un semnal, eventual porneste o alarma.

1.2.1.2. Fundamentele obiectelor

 
In implementarea practica a unui obiect, starea unui obiect se poate traduce prin variabilele de instanta. Aceste variabile de instanta sunt definitorii pentru un obiect. Comportamentul unui obiect se poate implementa prin intermediul metodelor. Metodele actioneaza asupra variabilelor de instanta modificind in acest fel starea obiectului, de asemenea metodele unui obiect pot crea la rindul lor alte obiecte.
 



Fig. 1.2.1.2.1 Reprezentarea unui obiect

In figura 1.2.1.2.1 se poate observa reprezentarea schematica a unui obiect. Diagrama reprezinta structura conceptuala a unui obiect, ca o remarca, se poate face analogie cu o celula, cu membrana exterioara, re4prezentata in exemplul nostru de catre metode, si cu un nucleu inconjurat de catre membrana care il protejeaza. Variabilele de instanta, reprezentind datele, starile obiectului, sunt impachetate, incapsulate, in interiorul obiectului fiind inconjurate de metode. In mod normal, metodele sunt singurele mijloace prin care se poate modifica continutul variabilelor de instanta, a datelor. Dar in interiorul clasei se poate declara o anumita variabila de instanta ca fiind publica si atunci, continutul ei poate fi modificat si in mod direct.

1.2.1.3. Clasele


O clasa este o componenta software care defineste variabilele de instanta si metodele obiectului respectiv. O clasa in sinea ei nu este un obiect ci poate fi privit mai degraba, ca un model pentru creare obiectelor. Obiectele se pot obtine prin operatia de instantiere a unei clase gata definite. Nu exista restrictii privitor la numarul de obiecte care pot fi instantiate dintr-o clasa.
O declaratie foarte simplista a unei clase generice care modeleaza un regulator ar putea fi:

public class Regulator extends Object {
double valoareSemnal;
public double valoareReferinta;
// metode de acces la variabilel de instanta
}

Avind definita clasa care modeleaza un regulator, orice obiect din cadrul programului nostru i-si poate crea o instanta sau mai multe din Regulator (deci i-si poate crea mai multe obiecte Regulator).
Modul cum s-ar realiza aceasta este exemplificat mai jos:

Regulator regulatorulPentruPresiune1;
// sa declarat o variabila prin care se va face
// referire la regulatorul nostru

regulatorulPentruPresiune1 = new Regulator();
// se aloca memorie si se instantiaza obiectul
// nostru.

Acum se poate accesa obiectul definit si instantiat prin specificarea variabilei de instanta pe care dorim sa o accesam, sau metoda daca nu dorim variabila, precedate de numele instantei (obiectului) nostru, proaspat alocat.

ReghulatorulPentruPresiune1.valoareReferinta = 1;

Am putut sa accesam direct, variabila de instanta, valoareReferinta tocai deoarece ea a fost definita in cadrul clasei Regulator, ca fiind publica. In schimb valoare variabilei valoareSemnal nu poate di accesata decit in cadrul pachetului curent din care apartine si clasa Regulator.

1.2.1.4. Constructori


Cind se declara o clasa, exista posibilitatea sa se declare optional un constructor, care sa efectueze o initializare la instantierea unui obiect din acea clasa. De asemenea se poate declara un finalizator, care este executat inainte de distrugerea obiectului. Aceasta ar fi o facilitate foarte utilizata in automatica, unde de obicei se lucreaza cu echipamente hard, care de obicei tot timpul trebuie initializate, inainte de a lucra efectiv cu ele. Aplicind cele discutate aicea se poate da un exemplu de construire a unui constructor, chiar pentru clasa noastra de Regulator.

Class Regulator extends Object {
double valoareSemnal;
public double valoareReferinta;

//constructorul care realizeaza initializarea valorilor

public Regulator() {
valoareSemnal= citesteSemnal();
valoareReferinta= 1;
}

//constructor care initializeaza la anumite valori

public Regulator(double referinta) {
valoareSemnal= citesteSemnal();
valoareReferinta= referinta;
}
}
Metode cu acelasi nume ca si clasele se numesc constructori. La instantierea unui obiect primul lucru care se executa este constructorul, de altfel noi nu suntem obligati sa furnizam obligatoriu un constructor, deoarece compilatorul, in caz ca nu gaseste nici un constructor, fabrica unul. Prin executarea constructorului, se da posibilitatea efectuari diverselor operatii de initializare, precum si operatia de initializare a variabilelor cu valorile dorite.
Astfel, un exemplu de instantierea a unui regulator, cu valoare de referinta, diferita de 1, se poate face acum, foarte usor:

Regulator regul1;
Regulator regul2;

regul1 = new Regulator(); /* primul constructor */
regul2 = new Regulator(0.5); /* cel dea-l doilea */

1.2.1.5. Metode si mesaje

 
Daca un obiect, doreste, sa-i comunice unui alt obiect ca e cazul sa-si modifice starea, atunci in jargonul programarii orientate pe obiecte, primul obiect ii trimite un mesaj celui de-al doilea obiect. Ca reactie cel de al doilea obiect selecteaza o metoda potrivita pe care sa o apeleze. Dealtfel invocarea metodelor seamana destul de mult cu a functiilor din C si C++.


Fig: 1.2.1.5.1 Modul de comunicatie intre obiecte

Folosind paradigma programarii orientate pe obiecte se pot construi, adevarate retele si pinze de obiecte schimbindu-si starea in urma comunicatiei intre ele prin mesaje. Aceasta tehnica de programare este una dintre cele mai propice pentru a crea modele care sa simuleze sisteme deosebit de complexe din lumea reala. Revenind la modelul nostru de regulator putem sa-cream metodele, pentru a permite altor obiecte sa comunice cu el:

public class Regulator extends Object {
double valoareSemnal;
double valoareReferinta;

public Regulator() {
valoareSemnal= 0;
valoareReferinta=1;
}

public void setValoareReferinta(double ref) {
valoareReferinta = ref;
}
public double getValoareReferinta() {
return valoareReferinta();
}
public void readSignal() {
}
public double getValoareSemnal() {
return valoareSemnal;
}
}
Acum variabilele de instanta nu mai sunt accesibile din exterior si deci singura metoda de a le accesa ramine prin intermediul metodelor puse la dispozitie de interfata obiectului. O comunicare cu obiectul poate avea urmatorul scenariu:

Regulator reg1 = new Regulator();
reg1.setValoareReferinta(0.5);
double valoarecitita= reg1.getValoareReferinta();

A face variabilele de instanta, publice sau private, este la latitudinea programatorului. Facind variabilele publice se descopera unele dintre detaliile de implementare, din aceasta cauza asigurind o eficienta si rapiditate mai mare, platind in schimb, pretul in viitor , la intretinerea clasei unde detaliile de implementare vor putea fi greu modificate tocmai din cauza ca au fost publice si folosite ca atare. Ascunzind detaliile de implementare al unei clase, transformindu-i toate variabilele de instanta in variabile de tip privat, se asigura pe viitor toate conditiile unor schimbari radicale, oarece utilatori nu au avut acces direct la acele variabile, ci numai prin intermediul unor metode de acces, care se pot pastra.

1.2.1.6. Finalizatori


De asemenea la fiecare clasa se poate defini un finalizator, acesta se face definind efectiv o metoda publica finalize(). Functionalitatea unui finalizator este de fapt explicata si de numele ei. In momentul, in care un obiect urmeaza a fi dealocat, distrus de catre managerul de memorie, acesta apeleaza, daca exista, pentru toate obiectele metoda finalize, deci acesta este locul propice pentru a elibera anumite resurse, sau a executa anumite operati de terminare. Astfel de exemplu, daca la nivel superior avem o clasa care defineste un obiect care controleaza un intreg proces, la terminare se poate opta pentru, oprirea fiecarui sub proces si oprirea in siguranta a intregului proces. Si toate aceste executindu-se in mod natural.

1.2.1.7. Mostenirea


Mostenirea este un mecanism, prin care noi obiecte, cu facilitati extinse se pot defini pe baza unor obiecte existente. Ideea este deosebit de frumoasa cu avantaje atit in modul de concepere al aplicatiilor, permitind o organizare frumoasa si eficace a datelor, precum si o metoda deosebit de utila de re utilizare a codului. Se poate scrie de exemplu o clasa generala, care sa implementeze marea majoritate a codului, cod care este independent de sunctionalitatile specifice ale obiectelor, iar pe urma, mostenind din aceasta clasa de baza,se pot realiza obiecte cu functii diverse, dar cu o cantitate de cod scrisa cu cel putin 50% mai putin. Un astfel de exemplu ar putea fi chiar un regulator, si metodologia ar putea fi urmatoarea: se realizeaza o clasa care sa implementeze un regulator de tip P, prin mostenire se poate crea o clasa noua care sa implementeze un regulator PI, singurul lucru pe care trebuie sa-l implementeze noua clasa este o metoda noua numita reglareI, si sa se suprascrie metoda generala care implementeaza reglare, sa spunem reglare, metoda care sa contina atit apelul de reglareP, pe care i-l avem, in noua noastra clasa, fiind cel mostenit din clasa RegulatorP, la care mai adaugam si apelul metodei noi implementate numite reglareI , si astfel avem, cu un efort minim un nou regulator, care stie sa implementeze legea de reglare PI. Se poate merge si mai departe, din clasa obtinuta, sa zicem RegulatorPI putem mosteni o noua clasa numita RegulatorPID care mai trebuie sa implementeze metoda care sa asigure reglarea de tip D. Deci cu un efort minim, am reusit sa cream trei tipuri de obiecte pe deplin functionale. Potentialul pe care-l prezinta aceasta metodologie nu se opreste aicea, asigurindu-se facilitati impresionante.

Fig: 1.2.1.7.1 O ierarhie de clase

Mostenirea deci permite folosirea codului existent, si cel mai important gata testat, pentru o diversitate de probleme. Prin definirea de metode sau variabile noi se adauga functionalitati noi, iar prin supradefinirea metodelor din clasa de baza se modifica comportamentul viitorului obiect, comportament mostenit de la parinte. Partea cea mai interesanta, este ca obiectul fiu, poate fi folosit in cadrul programelor de parca ar fi parinte. Aceasta tehnica se numeste downcasting, si se bazeaza pe faptul ca toate metodele pe care le are clasa de baza (parintele), prin mostenire le are si copilul, deci nu este gresit, sa-l folosim, ce se obtine de pe urma acestei metode poarta numele de polimorfism. Avantajele sunt imense, bunaoara, reluind exemplul cu regulatorul, noi nu trebuie sa stim exact, ce tip de regulator vom folosi la reglare, ci este suficient sa lucram cu clasa de baza. Iar la rulare putem sa instantiem orice tip de regulator, si sa-i atasam handlerului regulator, handlerul regulatorului pe care i-l dorim. In acest mod, de exemplu putem sa schimbam foarte simplu legile de reglare pe care le vom folosi, in functie de ce handler vom pasa, handlerul unui regulator P, PI sau PID.
Considerind exemplul, amintit, implementarea lui ar fi:

public Regulator extends Object {
// declararea variabilelor de instanta

// declararea constructorilor

public void regleaza() {
}
}

Acum implementam regulatoarele propriuzise, care mostenesc proprietatile clasei de baza Regulator.

public RegulatorP extends Regulator {
//declararea de variabile specifice regulatorului P
// restul fiind mostenite din clasa de baza

public void legeRelgareP() {
// implementarea legii;
}
//supradefinim, metoda regleaza, pentru a lua in evidenta
//legea de reglare
public void regleaza() {
legeReglareP();
}
}

Regulatorul PI, il mostenim din regulatorul P, pentru a nu mai fi nevoiti sa-l implementam

public RegulatorPI extends RegulatorP {
//declararea de variabile specifice regulatorului I
// restul fiind mostenite din clasa de baza

public void legeRelgareI() {
// implementarea legii;
}
//supradefinim, metoda regleaza, pentru a lua in evidenta
//legea de reglare
public void regleaza() {
legeReglareP();
legeReglareI();
}
}

Folosirea mostenirii si a polimorfismului se exemplifica mai, jos. Presupunem ca avem un proces, si avem o metoda regleazaProces(Regulator reg) care efectueaza reglarea procesului:

Regulator reg = new Regulator();
RegulatorP regP = new RegulatorP();
RegulatorPI regPI= new RegulatorPI();

// se lanseaza reglarea procesului cu un regulator P

regleazaProces(((Regulator)regP));

// se poate observa, ca se face o trensformare de tip, din
// RegulatorP in Regulator, acesta deoarece, am construit
// metoda regleazaProces, sa poata lucra generic cu orice
// tip de regulator

// se lanseaza reglarea procesului cu un regulator PI

regleazaProces(((Regulator)regPI));

Desi, sa facut un downcasting, metodele noi definite in clasa RegulatorP, nu se pierd, mecanismul executiv, sesizeaza ca e vorba de o clasa derivata, din clasa Regulator, si apeleaza metoda, corespunzatoare din clasa care trebuie si anume RegulatorP, sau RegulatorPI.

1.2.1.8. Controlul accesului


La declararea unui clase se poate specifica nivelul de acces permis la variabilele de instanta, sau metodele clasei respective. Java permite patru nivele de acces dintre care trei trebuie specificate explicit, unul fiind implicit. Acestea sunt: public, protected, si private. Cel de-al patrulea nivel nu are o denumire propriuzisa, folosindu-se de obicei denumirea de friendly, si este specificator de acces care este folosit in mod normal daca nu se specifica nici un specificator explicit. Drepturile pe care le garanteaza, sunt cele de acces nelimitat la variabilele de instanta si la metode, pentru toate clasele care fac parte din cadrul aceluiasi pachet, si total inaccesibile pentru restul claselor. Un pachet, fiind metoda implementata de limbajul Java pentru, gruparea mai multor clase. Specificatorul friendly, este deosebit de util, daca se lucreaza, la elaborarea unui pachet care contin clase (obiecte), interconectate functional. Un astfel de exemplu ar putea fi implementarea unui pachet de regulatoare, si din acest punct de vedere, variabila de instanta, semnalReferinta, ar putea fi accesata in mod direct de toate clasele din cadrul pachetului, cea ce este logic. [wp01] De asemenea in afara pachetului, care contine definitiile regulatoarelor, aceasta variabila de instanta va putea fi accesata numai prin intermediul metodelor speciale de acces concepute in acest sens. Aceasta abordare permite, printre altele, modificarea ulterioara a modului cum vor fi implementate ulterior aceste regulatoare, in ideea ca pe parcursul timpului, noi metodologii, si tehnici apar, iar clasele care implementeaza regulatoarele pot fi actualizate, si toate acestea fara a afecta programele care apeleaza, clasele din aceste pachete, deoarece interfata ramine neschimbata, modificind-se numai detaliile implementari. Avantajele fiind evidente. Specificatorul de acces public semnifica, ca metodele si / sau variabilele de instanta sunt accesibile de oriunde si pentru oricine, protected asigura accesul doar a elementelor din aceeasi clasa, sau din clasele derivate din acea clasa. In final specificatorul de acces private interzice accesul tuturor exceptind accesul din propria clasa .

1.2.1.9. Metode si variabile de clasa


Java urmeaza conventiile limbajelor orientate pe obiecte, asigurind astfel suport pentru variabile si metode de clasa. In mod normal toate variabilele sau metodele dintr-o clasa, sunt variabile de instanta, adica ele sunt distincte pentru fiecare obiect instantiat din clasa respectiva, pe de alta pare metodele si variabilele de clasa sunt unice pentru clasa respectiva, aceasta insemnind ca indiferent cite instante se creeaza din clasa respectiva, acele metode sau variabile vor fi unice pentru toate instantele, toate obiectele impartind aceleasi metode sau variabile. Pentru a declara variabilele in acest fel ele trebuie declarate static, ca in exemplul urmator:

Class Regulator extends Object {
...
static int semnalReferinta;
...
}

Prin aceasta manevra, bunaoara indiferent cite regulatoare am avea instantiate, modificind aceasta variabila, modificarea se propaga automat la toate. Daca am dori ca valoarea lor sa nu poata fi modificata, putem adauga modificatorul final. Ideea pentru care au fost implementate metodele de clasa, este frecventa cu care se obisnuieste sa se foloseasca instantierea unui clase in mai multe obiecte, care au toate aceiasi metoda, care satisface aceiasi functionalitate. Acest obicei are ca rezultat o risipa de resurse, care de multe ori trebuie dramuite cu multa atentie. In astfel de cazuri, metodele de clasa rezolva problema. Singurele restrictii care se impun metodelor de clasa este ca ele nu pot accesa variabile de instanta sau metode normale, ci numai variabile sau metode care la rindul lor sunt de clasa.

1.2.1.10. Metode abstracte


Metodele abstracte prezinta o facilitate puternica a programarii orientate pe obiecte. Pentru a intelege metodele abstracte, si functionalitatea lor, pornim de la ideea de superclasa abstracta. O superclasa abstracta este o clasa in care se definesc un numar de metode, dar care nu sunt implementate efectiv de catre clasa, ci au rolul de a sigura numarul, numele, parametri si alte aspecte, care pe urma vor fi suprascrise, de catre clasele care vor mosteni din acea clasa abstracta. Cu alte cuvinte o clasa abstracta are menirea de a simula un obiect abstract, obiect care reuseste sa generalizeze un set de proprietati si comportamente ale unei clase de obiecte. Dintr-o clasa abstracta nu se vor crea niciodata obiecte, ci se vor mosteni clase care pe urma vor fi instantiate. Un exemplu de implementare, ar fi reglarea unui proces. Orice proces care trebuie reglat se presupune ca contine un regulator, dar ideea optimala de implementare este de a nu ingloba regulatorul direct in aplicatie, (insemnind, efort considerabil, in caz ca modelul de regulator folosit nu asigura performantele necesare, si se impune schimbarea modelului). Ci de a sintetiza caracteristicile unui regulator, si de a folosi, imaginea abstracta a unui regulator in cadrul aplicatiei, imagine din care se pot crea implementari efective de regulatoare, implementari care vor putea fi folosite fara probleme, deoarece implementeaza toate caracteristicile modelului abstract. In acest mod se pot experimenta modele de regulatoare diferite, sau se poate modifica modelul de regulator, fara a modifica structura aplicatiei.

Fig: 1.2.1.10.1 Utilitatea unei clase abstracte

Utilizind aceasta functionalitate in cadrul clasei abstracte, se implementeaza, toate metodele care nu sunt direct conectate sau dependente de legea de reglare utilizata. In momentul in care se mosteneste un nou regulator, acesta va trebui sa supradefineasca doar metoda care realizeaza efectiv implementarea legii de reglare, restul metodelor fiind implementate in clasa abstracta, devin disponibile si functionale. Din cite se poate observa, pe linga faptul ca se asigura o interfata comuna si unitara regulatoarelor, se introduce o simplificare claritate si ordine in procesul de implementare a lor uimitoare.

1.2.1.11. Sumar


Acest subcapitol a prezentat aspectele esentiale ale tehnologiei orientate pe obiecte, aceste facilitati fiind:
Programarea orientata pe obiecte, lucreaza cu conceptul de obiect, concept folosit in mod natural de oameni, in viata, astfel se transpune un mod natural de gindire si in activitatea de programare, procesul fiind mult simplificat. In automatizari se lucreaza cu obiecte reale, fizic existente si astfel folosirea unui limbaj de programare orientat pe obiecte este cea mai naturala alegere posibila, si cea mai fidela in modelarea comportamentului diverselor obiecte, cu atit mai mult cu cit obiectele sunt fizic reale, si o analiza din acest punct de vere este mult usurata, rezultatele fiind mult mai fidele.

Multithreading in Java



Atit programatori cit si utilizatorii, au inceput in ultima perioada sa fie nemultumiti de maniera calculatoarelor personale de a face un singur lucru de odata. Observind ca in lumea reala din jur o multitudine de lucruri se intimpla simultan, apare dorinta fireasca ca si calculatoarele sa functioneze in acelasi mod. Din pacate a scrie programe care sa gestioneze mai multe lucruri care se intimpla simultan este mult mai dificil decit a scrie programe conventionale care lucreaza cu un singur fir de executie. Aplicatii cu mai multe fire de executie se pot scrie si in limbaje precum C, C++ sau ADA, dar complexitatea tehnica a unor implementari de genul acesta este mai mare cu cel putin un ordin de marime, si chiar daca se reuseste, nu este nici o garantie ca producatorii de componente software cu care eventual se lucreaza sau se intentioneaza a se lucra, au implementate acele componente astfel incit sa suporte, lucrul cu mai multe fire de executie adica sa manifeste afinitate multithreading. Termenul de afinitate multithreading, insemnind ca acele librarii sau functii sunt implementate de asa maniera, incit sa permita executia de simultana de catre mai multe fire de executie. Problema majora cu mediile care ofera suport explicit pentru programarea multi fir, este ca nu prezinta niciodata garantii ca s-au realizat lock-urile necesare, si ca s-au eliberat exact in momentul potrivit. De exemplu daca s-a iesit prematur dintr-o metoda, sau s-a generat o exceptie, si lock-ul nu a fost eliberat, rezultatul obisnuit obtinut in asemenea cazuri este interblocajul.

1.2.2.1. Threaduri la nivel de sintaxa


Suportul integrat in limbajul Java pentru multithreading, il transforma intr-o unealta deosebit de puternica pentru diverse operatii, incepind de la cele de natura tehnica, supraveghere mai multor procese sau parametri pina la imbunatatirea performantelor aplicatiilor grafice intensive. Ambele tipuri fiind puternic prezente in aplicatiile de automatizari. Threadurile au fost considerate o piatra de hotar deosebit de importanta pentru Java. Astfel librariile de baza asigura o clasa Thread care implementeaza o bogata colectie de metode pentru a porni, opri, rula, verifica un fir de executie. De asemenea sa inclus un mecanism sofisticat de sincronizare bazat pe paradigma larg folosita de monitorizare si variabile conditionate, introdus de catre C.A.R. Hoare si implementat pentru prima data de catre compania Xerox la sistemele Cedar/Mesa . Multe articole din domeniul informatici trateaza subiectul programarii concurente. Concurenta fiind subiect de cercetare de o lunga perioada de vreme, o multitudine de solutii au fost propuse si implementate. O parte din rezultatele acestor cercetarii sunt, urmatoarele metode:
Principiul dupa care functioneaza este cel al unui obiect specializat, denumit monitor, care aplica principiul excluderii mutuale aplicat pe grupuri de proceduri. Monitoarele Java forteaza excluderea mutuala a accesului la metode, mai specific se forteaza excluderea mutuala la metodele sincronizate. Unde cuvintul cheie synchronized este un modificator de metode optional [ju01].
Threadurile Java sunt pre-emptive, si depinde de platforma pe care masina Java ruleaza, astfel ele pot fi si de tip time-sharing. Pe cind celelalte limbaje asigura facilitati de multithreading de obicei prin intermediul unor librarii, de thread-uri, suportul inglobat chiar in miezul limbajului asigura programatorii cu unelte mult mai puternice si facile pentru crearea aplicatiilor cu afinitate pentru mai multe fire de executie sau chiar cu mai multe fire de executie. Un alt avantaj al multithreading-ului este un mai bun raspuns, sau o mai mare interactivitate si comportament de timp real bun.
Mecanismul implementat de catre Java, intern pentru gestionarea proceselor asigura in mod unic programelor Java rulind sub diferite platforme performantele de timp real native platformei respective.
Efectiv in interiorul masinii virtuale, multitasking-ul e implementat ierarhizat, organizat pe mai multe nivele. La nivelul cel mai ridicat se situeaza un set de metode abstracte independente de platforma, iar la nivelul cel mai inferior, un nucleu mic de rutine dependente de platforma [TJ01].

Fig: 1.2.2.1.1 Arhitectura threadurilor Java


1.2.3. Tratarea exceptiilor



Erorile sunt, din pacate parte a programelor. Unele dintre aceste erori sunt probleme de proiectare restul fiind de implementare, fiind denumite in limbajul curent scame, sau bug-uri. Un alt tip de erori, care nu sunt considerate same, se datoreaza unor situatii precum, memorie insuficienta sau nume de fisiere gresite. Modul cum sunt tratate ultimele tipuri de probleme determina daca acestea se transforma in scame sau nu. Din pacate daca telul este de a produce aplicatii robuste, cum este cazul de exemplu si in automatizari, unde aplicatiile nu au voie sa piarda controlul, altfel totul al putea sa se finalizeze intr-o catastrofa, vom descoperi ca vom petrece mai mult timp tratind erori decit efectiv scriind cod pentru aplicatiile noastre.
Mecanismele de tratare a erorilor implementate de limbajul Java, permite sa tratam erorile fara a forta programatorul sa-si epuizeze energiile tratindu-le sau facindu-si griji din cauza lor.

1.2.3.1. Ce sunt exceptiile


Asa cum sugereaza si numele o exceptie este o conditie exceptionala, ceva iesit din rutina obisnuita, sau ca un termen care se poate folosi in antiteza cu bine. Mecanismul exceptiilor asigura nu numai o modalitate de semnalizare a erorilor, dar si o metoda de a le trata. Aceasta noua structura permite sa se specifice exact unde sa se trateze anumite tipuri de erori.
Desi tratarea erorilor nu este o particularitate numai a limbajului Java, existind tratare de erori si in limbajele C, C++ sau Ada, cea ce diferentiaza, Java de restul limbajelor este ca pe cind tratarea erorilor in restul limbajelor e optionala, lasata la latitudinea programatorului, in Java ea este impusa. Daca o anumita metoda este susceptibila de a genera o anumita eroare, atunci daca nu este tratata, este considerata o eroare de catre compilator, si compilarea este oprita. De fapt functiile de nivel scazut (implementate de catre Java) detecteaza erorile pe cind, functiile situate pe nivele superioare (implementate de programator in cadrul aplicatiei) determina ce se va intimpla in cazul aparitiei erori, exceptiile asigurind o metoda de comunicatie a informatiilor legate de erorile aparute in sus pe lantul de metode, pina cind se gaseste o metoda care sa stie sa trateze eroarea respectiva (vezi [MM]). Exceptiile pot fi privite ca o structura de control nonlocala . Cind o metoda genereaza o exceptie, apelantul metodei trebuie sa determine daca este capabil sa capteze exceptia sau nu. Daca poate sa o capteze, atunci preia controlul executiei programului, daca nu este capabil atunci exceptia este data mai departe metodei apelante, si acest mecanism continua, pina cind una din metode este capabila sa prelucreze exceptia, sau in caz ca nu exista o astfel de metoda, executia programului se intrerupe, deoarece exceptia nu a fost prinsa. Toate exceptiile Java mostenesc clasa java.lang.Throwable, deoarece toate exceptiile sunt obiecte ele pot incapsula, atit date cit si metode, de altfel chiar clasa de baza implementeaza o metoda care returneaza un sir de caractere continind descrierea erori, care a generat exceptia, acesta fiind deosebit de util in operatia de depanare.
Captarea unei exceptii se face cu ajutorul unui bloc inceput cu cuvintul cheie try, si finalizat cu o succesiune de secvente de catch-uri structura reprezentata mai jos.

try{
...
//instructiuni susceptibile de a genera erori
...
} catch ([tip_exceptie1] ex) {
// secveta tratare acest tip exceptie
} catch ([tip_exceptie2] ex) }
// secventa tratare tip_exceptie 2
} catch (Throwable th) {
// deoarece toate exceptiile provin din aceasta
// clasa e bine, daca dorim sa prindem toate
// exceptiile ca la capat sa o folosim pe cea mai
// generala posibila
}

Din cite se poate observa se poate face o filtrare dupa, exceptii deci puntem trata selectiv exceptiile generate.
Nu toate metodele trebuie sa capteze erorile, ele avind optiunea sa le transmita mai departe, una dintre cele doua optiuni trebuie aleasa, aceasta din cauza ca limbajul impune tratarea tuturor exceptiilor. O metoda care nu trebuie sa fie incarcata cu tratare de exceptii poate opta sa le transmita mai departe, la ierarhul sau, faptul ca o metoda poate genera o exceptie se specifica prin intermediul modificatorului throws, astfel dupa declaratia throws-ului este neaparat necesar sa se enumere tipurile de exceptii pe care le poate genera, astfel prototipul unei metode care genereaza exceptii se poate defini:


void metoda_generatoare_de exceptii ([parametri])
hrows IOException, [alte_exceptii] {
...
// corpul metodei
...
}

Tipul de data returnat de metoda nu este neaparat nevoie sa fie void putind fi orice tip de data. Limbajul Java mai adauga o clauza tratarii exceptiolor, clauza, impusa de nevoile practice, si anume blocul finally, deci structura completa, de tratare a exceptiilor este:

try{
//secvente de instructiuni
} catch ([tip_exceptie])
// tratarea exceptiei
} finally {
//secvente de instructiuni
}

Ultimul bloc din structura de mai sus, are menirea de a asigura o structura care sa se execute tot timpul, chiar si cint sunt generate exceptii. Un astfel de loc, de exemplu este folosit pentru inchiderea conexiunilor deschise, sau a fisierelor.

In Java se poate face diferenta intre doua clase, exceptiile clasice si erori. Amindoua clasele sunt derivate din Throwable, dar semnificatiile lor sunt diferite, pe cind exceptiile sunt menite sa indice probleme care pot fi rezolvate pe cale software, erorile indica probleme din care programele nu se mai pot aduce pe o linie normala de executie, si oprirea programului este iminenta.

Avantajele, tratarii exceptiilor este evident, si in special aplicatiile cu profil de automatizari ar trebui toate sa implementeze aceasta functionalitate cu atit mai mult cu cit ea poate economisi o sumedenie de resurse financiare prin prevenirea si preintimpinarea unor eventuale defectiuni sau catastrofe, ne mai pomenind de eventualele vieti umane salvate.

Astfel structura ierarhiei de clase Java care caracterizeaza exceptiile este:
 




Fig 1.2.3.1.1. Ierarhia de clase de exceptii
Pe cind ierarhia de clase care caracterizeaza erorile sunt:


Fig 1.2.3.1.2. Ierarhia de clase de erori


1.2.4. Suportul de retele si programare distribuita


Suportul de retele implementat de Java se bazeaza pe protocolul TCP/IP (Transmission Control Protocol/Internet Protocol) dar si UDP/IP( User Datagram Protoco/Internet Protocol), acelasi protocole ca si cele folosite de Internet (a se vedea [PH] pentru detalii). TCP/IP-ul implementeaza un set de protocoale care asigura suportul pentru diferite servicii precum, transfer de fisiere, loginare la distanta si de asemenea citeva servicii care constituie sistemul de baza al comunicatiilor.
O retea conecteaza doua sau mai multe calculatoare in ideea de a desfasura activitati care de sine independente nu s-ar putea efectua. In afaceri, educatie, cercetare, retelele au fost mijlocul cel mai comun utilizat pentru extinderea facilitatilor unui calculator. O explicatie mai simplista ar fi ca retelele permit mai multor utilizatori sa partajeze si sa foloseasca in comun mai multe resurse, sau bunaoara sa conlucreze la indeplinirea unei sarcini. La un nivel mai tehnic o simpla explicatie ar fi, faptul ca un calculator poate sa partajeze sau sa foloseasca resursele unui alt calculator, un bun exemplu fiind doua calculatore unul dispunind de facilitati grafice deosebite si celalalt de calcul de numere reale iesit in comun, daca cele doua sisteme se unesc, atunci teoretic se pot executa aplicatii care in mod normal ar necesita cel putin un calculator care sa dispuna de ambele resurse.

1.2.4.1. Suportul pentru aplicatii Client-Server


In ultima decada, aplicatiile client-server au devenit cele mai raspindite tipuri de aplicatii folosite acolo unde deja exista retele de calculatoare functionale. Ideea care sta la baza tehnologiei client-server este ca un calculator specializat are functia de stocare a datelor, precum si de prelucrare a lor, iar unul sau mai multe calculatoare cu resurse mai mici, au rolul de a prezenta informatia procesata pe server. Cele mai multe aplicatii cunoscute si care sunt legate intr-un fel de la o retea de calculatoare au o arhitectura client-server, si anume ma refer la e-mail, ftp, telnet si asa mai departe.
Deci pentru a putea discuta despre o aplicatie client-server, in primul rind avem nevoie de un server, crearea unui server in limbajul Java este cea mai simpla metoda pusa la dispozitie posibile. Clasa de baza este denumita serverSocket si are functia de a crea un server care asculta la un port specificat si asteapta clienti care sa se conecteze. Metoda care realizeaza conectarea efectiva este accept()din cadrul clasei aceasta blocind blocul curent al aplicatiei pina cind un client nu se conecteaza. Datorita modului cum au fost concepute aceste metode in cadrul limbajului Java, operatiile executate de un client sau de un server sunt aproape identice. Diferente apar numai in cazul in care serverul are de tratat mai multi clienti iar clienti doar un singur server.
Motivul principal al vinzarilor puternice pe care le-a inregistrat limbajul Java, masina virtuala, este de asemenea motivul principal pentru care dezvoltatori de aplicatii client-server au investit imens in acest limbaj. Cu portabilitatea codului greu de atins in alte limbaje Java permite programatorilor sa scrie codul o singura data independent de platforma, si sa-l distribuie pe masinile client. Dar in afara independentei de arhitectura Java asigura de asemenea o puternica biblioteca care permit aplicatiilor sa acceseze in mod rapid resursele unei retele in maniera adresarii traditionale TCP si localizarii prin intermediul URL-urilor a resurselor. Un alt avantaj devastator fata de alte limbaje de programare este incarcarea de la distanta a aplicatiilor. Pe cind in mod conventional, aplicatiile client sunt nevoite sa fie instalate fizic local pe fiecare terminal client, limbajul Java permite pe linga incarcarea aplicatiei direct de pe retea permite si rularea ei pe alt calculator. Astfel pe linga economiile de resurse, atit umane cit si financiare datorate eliminarii necesitati instalarii fizice pe fiecare calculator, se obtine avantajul ca se va lucra tot timpul cu cea mai curenta versiune de aplicatie.
Pachetul de aplicatii Java apeleaza accesul la suportul de retea prin intermediul unui set de nivel superior, de functii si streamuri. O aplicatie poate folosi aceste streamuri pentru a permite datele de intrare si iesire din retea sa poata fi manipulata intr-o multitudine de moduri. Pachetul java.io , care defineste seturile de functii pentru lucrul cu canalele de comunicatie implementeaza un set de functii deosebit de utile, astfel DataInputStream, DataOutputStream sau PrintStream .
Pentru a demonstra capacitatile si simplitatea cu care se pot asigura functionalitati deosebite, mai jos se poate observa, un exemplu de realizare a unei conexiuni la un server.

Socket conexiune

try{
conexiune = new Socket( www.utcluj.ro, 1701);
} catch (Exception e) {
}

Se poate observa ca elementele de baza in construirea de programe client-server sunt socket-urile IP care realizeaza nivelul de comunicatie in cadrul retelei. In vreme ce programarea socket-urilor poate fi foarte dificila si mare consumatoare de timp, Java a asigurat o clasa de obiecte proiectate in mod special pentru a reduce timpul petrecut in scrierea acestor aplicatii. Astfel clasele Datagramsocket, ServerSocket si Socket asigura accesul la protocolul IP, insusi, clasele ca DataInputStream, DataOutputstream si PrintStream , asigura accesul la date, iar in final clasa StringTokenizer, asigura functii minime de manipulare a datelor.

1.2.4.2. Suportul pentru programarea distribuita


Metoda prin care se poate realiza programare distribuita in Java se numeste Java Remote Method Invocation (RMI), si permite scrierea de obiecte distribuite. Deoarece RMI este centrat in jurul limbajului Java, puterea siguranta si portabilitatea sunt in mod automat asigurate. Astfel se pot muta comportamente (executii de obiecte), in acea parte a retelei unde au cel mai mare sens.
La nivel de baza, RMI este mecanismul Java de a implementa apelul procedurilor de la distanta (Remote Procedure Call, RPC). RMI insa asigura o serie de avantaje deasupra RPC, in primul rind din cauza ca RMI face parte integranta din limbaj, pe cind RPC a fost conceput ca o structura independenta de limbaj, si ca atare implementeaza numai mecanismele ca re sunt comune in cazul sistemelor traditionale. RMI este orientat pe Java, cu optiuni complete de conectivitate cu alte platforme prin intermediul suportului pentru metode native pe care Java i-l pune la dispozitie, aceasta insemnind ca RMI poate aborda o implementare neutra, directa si asigurind performante maxime, pentru a asigura programatorului o tehnologie de programare distribuita de inalta performanta.
Avantajele RMI-ului ar fi:


Pentru a ilustra modul simplu in care functioneaza, se poate urmari diagrama de mai jos:

 


Fig: 1.2.4.2.1 Exemplu de apel RMI
In concluzie se poate afirma ca Java asigura un suport real pentru o adevarata programare orientata pe obiecte si pe deasupra distribuita. Metodele de genul RMI pot fi folosite pentru a conecta componentele existente cu componente scrise in alte limbaje de programare, de exemplu. Pentru detalii suplimentare se poate consulta [WP].


1.2.5. Suport pentru securitate avansata


Problemele de securitate in Java pot fi tratate din diferite aspecte, unul dintre ele sunt legate inerent de suportul pe care-l asigura pentru retele sau programare distribuita, aceste au ca punct de pornire securitatea utilizatorului care ruleaza programe culese de pe Internet, si in special se pune aici problema applet-urilor. Nu voi insista asupra acestor mecanisme acestea avind putine interferente cu domeniul automatizarilor. Securitatea din punctul de vedere al clientului, este rezolvata prin restrictionarea accesului si a posibilitatilor unui applet de a accesa sistemul local de fisiere, de a fi server de semnal pentru alte aplicatii, de a accesa alt server, decit cel de pa care a fost pornit. Bineinteles, este posibila eliminarea acestor restrictii, dar numai prin interventia explicita si in cunostinta de cauza a utilizatorului.
Celalalt aspect al securitatii se refera la mecanismele de criptare, codificare si alte asemenea tehnologii pe care le pune la dispozitie.
Pachetul de clase de securitate, asigura cinci servicii independente dar totusi corelate, acestea fiind:

1.2.5.1. Criptare de date


Folosind algoritmi de criptare cu chei publice, sau simetrice, programele Java pot folosi pachetul java.security, pentru a realiza criptarea sau decriptarea buferelor de date, sau a datelor folosind cheile specificate. Facilitatile de criptare sau decriptare pot fi folosite, de asemenea in combinatie cu streamurile standard de intrate sau iesire de date, astfel fisierele sau socket-urile de comunicatie in retea pot fi criptate sau decripatate in mod direct si transparent.


1.2.5.2. Semnaturi digitale


Semnaturile digitale sunt utilizate ca o metoda de asigurare ca datele comunicate provin de unde trebuie, si nu se intimpla un act de frauda. Se pot aplica semnaturi digitale pe orice tip de document electronic, indiferent daca sunt fisiere text, date in format binar sau chiar jetoane folosite pentru identificare. In multe cazuri semnaturile digitale asigura garantii mai puternice decit semnaturile conventionale, deoarece semnaturile digitale pot demonstra nu numai identitatea si provenienta unui document, dar si faptul ca documentul respectiv nu a fost modificat pe parcurs. Pachetul standard Java de securitate java.security, asigura toate facilitatile necesare pentru a aplica semnaturi digitale pe documente, si bineinteles pentru verificarea lor.

1.2.5.3. Canale securizate


Un canal securizat, este un canal de comunicatie care este atit criptat cit si autentificat. Autentificarea garanteaza ca la celalalt capat nu se afla un impostor ci sistemul cu care dorim sa comunicam, si criptat pentru a asigura ca un tert sistem, nedorit nu va putea intelege ce se comunica. Stabilirea unui canal de comunicatie securizat implica, declinarea identitatii fiecarui participant, (prin intermediul unor mici mesaje, semnate digital), urmata de o intelegere intre ambele parti asupra unei chei cu care sa se faca criptarea datelor transmise prin canalul de date. Dupa ce canalul a fost stabilit, comunicatia este automat criptata, transmisa, si decriptata la destinatie. Facilitatile acestea de a stabili canale de comunicare criptate, si sigure sunt inglobate in cadrul pachetului Java standard java.security.

1.2.5.4. Schimburile de chei


Folosirea efectiva, a facilitatilor mai sus amintite, presupune ca cele doua, parti participante, sa schimbe intre ele o cheie de criptare conventionala simetrica, folosita la criptarea datelor trimise prin canal, si care pe urma este distrusa, o data cu terminarea legaturi, si deci a canalului de comunicare. Problema majora in aceste cazuri este ca cheia se interschimba, prin intermediul unei conexiuni deschise, aceasta nefiind inca criptat. Tehnicile criptografice au dezvoltat insa mecanisme sigure pentru acest tip de schimb de chei, prin intermediul unui canal deschis. Aceste mecanisme sunt disponibile programatorilor prin intermediul pachetului Java standard java.security.

1.2.5.5. Managementul cheilor de criptare


In cazul precedent, dupa inchiderea unui canal de comunicare, cheile au fost distruse, odata cu canalul, insa in viata de toate zilele, sun cazuri cind cheile secrete sau cele publice ale unor grupuri de oameni, trebuie, stocate in ideea unei folosiri ulterioare. Aceste chei devin inutile, daca nu se stocheaza si sistemul de unde provin aceste chei, sau nu este asigurat, secretul lor. Astfel pachetul standard Java, contine mecanisme si metode pentru pastrarea corespunzatoare a unor astfel de chei, si mentinerea securitati lor.


1.2.6. Suport pentru baze de date


Bazele de date au inceput sa capete o importanta deosebita nu numai pentru aplicatiile generale, ci si pentru cele specializate pe automatizari. Astfel intr-o aplicatie de control industrial este nevoie sa fie monitorizat sistemul la fiecare pas, si salvat in acelasi timp, pentru posibile consultari ulterioare, de asemenea trebuie monitorizate si salvate comenzile care s-au dat pentru a se putea preciza exact in cazuri de catastrofa, care sunt motivele ei, pentru a putea fi evitate pe viitor. Pe linga facilitatile mai sus amintite Java mai asigura suport integrat si pentru baze de date relationale.
Suportul pentru baze de date este complet pentru toate structurile acestora, fie ca sunt single-tier, care este structurata ca in figura de mai jos:


Fig: 1.2.6.1 Structura unei aplicatii single-tier
Sau two-tier, a carei structura se poate observa mai jos:



Fig:1.2.6.2 Structura unei aplicatii two-tier



Setul de functii JDBC (Java Database Conectivity), a fost proiectat pentru a permite dezvoltatorilor de aplicatii sa dezvolte cit mai usor cu putinta interfete care sa lucreze cu baze de date, fara a fi nevoiti sa-si rescrie programele in permanenta. Pentru a obtine aceste deziderate, firma producatoare Sun impreuna cu divizia insarcinata cu limbajul Java, Java Soft, a conlucrat impreuna cu producatori de sisteme de gestiune a bazelor de date, pentru a reusi sa sintetizeze un set de librarii pentru lucrul cu bazele de date, care sa nu tina seama de tipul de baze de date cu care se lucreaza, creindu-se astfel o interfata comuna, pentru aplicati, indiferent de tipul de baze de date pentru care sunt scrise aplicatiile. Interogarile bazelor de date putindu-se face in limbajul standard SQL.

1.2.7. Personal Java


Personal Java este un nou mediu de dezvoltare a aplicatiilor Java pentru dispozitive conetabile in retea pentru dispozitive cu capacitati mai reduse decit calculatoarele personale, bunaoara dispozitive de uz casnic sau industrial. Deoarece PersonalJava include o numai o numita parte din functiile Java standard, aplicatiile scrise pentru PersonalJava sunt perfect compatibile in sus.
Motivele pentru care Java are viitor in acest domeniu sunt, mecanismele de incarcare si executie dinamica a codului, putindu-se in acest fel, sa se faca modificari foarte usor in codul aplicatiilor, totodata, dimensiunea redusa a codului generat, in special datorita faptului ca codul binar Java este mult mai compact, decit majoritatea codurilor, si in cele din urma, este printre primele limbaje care aduce tehnologia orientata pe obiecte in astfel de dispozitive. Java i-si mentine portabilitatea si in acest domeniu, tocmai datorita faptului ca el ruleaza in interiorul unei masini virtuale. Practic se poate scrie in sfirsit codul pentru implementarea unui regulator pentru un proces pentru un sistem bazat pe 8051, si fara modificari el va rula si pe un microcontroler, din familia PIC-urilor.
PersonalJava include o masina Java virtuala, un set de librarii de baza, si un set de librarii optionale, care pot fi folosite dupa preferinta. Pachetele sunt concepute modular si scalabile, permitind, de exemplu folosirea unor dispozitive diferite de afisare, sau protocoale diferite de retea.

1.2.8. Embedded Java


EmbeddedJava este in mod asemanator cu PersonalJava, o versiune de Java pentru dispozitive cu facilitati restrinse, cu deosebirea ca este mult mai putin pretentios decit personal Java, astfel a fost proiectat sa fie mult mai modular, scalabil si configurabil, rulind cu un minim posibil de memorie.
EmbeddedJava asigura o serie de nivele de functionalitate, bunaoara daca se doreste implementarea parti de programe pentru un dispozitiv in clasa pagerelor, deoarece acestea nu au nevoie, de exemplu de un sistem de fisiere, acesta poate fi exclus din pachetele, care vor fi implementate in microcontroler. Aceasta versiune, asigura suportul unor instrumente absolut necesare, cum ar fi, unelte de inserare a codului executabil in memoriile ROM, de asemenea pentru compilarea, compresia si plasarea imaginilor, si pentru estimarea resurselor de calcul necesare.

1.3. Controlul si monitorizarea proceselor prin intermediul retelelor, locale sau cu arie larga de raspindire.

Structura schematica a unei structuri de control a unui proces prin intermediul, retelelor de calculatoare si in speta prin intermediul Internetului, poate fi descrisa prin figura urmatoare:
Fig: 1.3.1 Structura de distribuire a unui proces, prin WWW
Elementele care apar in figura 1.3.1 sunt:


1.3.1. Structura de distributie a procesului



Principalele motive, sau avantaje pe care le prezinta conducerea si monitorizarea proceselor de la distanta pot fi prezentate sub doua aspecte:
  1. Distributia unui proces, in ideea de a fi monitorizat de oriunde (de a fi accesibil de oriunde), permitindu-se astfel existenta a mai multi clienti care urmaresc procesul in acelasi timp. Aceasta structura poate fi urmarita si in figura 1.3.1.
  2. Distributia unui proces, in ideea de a se permite o monitorizare centralizata. Acesta este cazul in care, procesul este format dintr-o multitudine de subprocese, situate la distante mari, intre ele (dispersate), si la cere controlul per ansamblul proceselor era greu de realizat. O posibila structura a acestui model poate di observata in figura de mai jos.


 
Fig:1.3.1.1 Monitorizarea centralizata a mai multor procese

Din punct de vedere functional, controlul de la distanta a unui proces se conformeaza, cu modelul tipic de aplicatie client-server. Astfel aplicatia se poate, separa in doua module.


Fig: 1.3.1.2 Structura client-server

Serverul de date poate coincide cu sistemul responsabil de achizitionarea semnalului de la proces si cu controlul acestuia, dar aceasta numai in cazul, in care procesul nu este puternic distribuit, altfel performantele si functionalitatea acestuia ca controlor de proces poate fi mult afectata, cea ce ar putea pereclita siguranta procesului. In cazul in care totusi, procesul este puternic distribuit, se poate folosi un mecanism de multiplexare a semnalului.


Fig: 1.3.1.3 Structura client-server cu multiplexor de semnal
Multiplexorul de semnal are sarcina de a degreva, controlerul de proces de sarcina de a deservi clienti multipli.


1.3.2. Serverul de semnal


Semnalele provenite de la proces, sunt achizitionate sau centralizate de catre calculatorul central al procesului, aceste semnale in cazul exportarii procesului trebuie facute “publice”. Deoarece aceste semnale sunt disponibile in totalitatea lor doar in calculatorul central, el este cel care are sarcina de a le duplica, si exporta, fiind in acelasi timp responsabil de ascultarea comenzilor provenite de la distanta, si de interpretarea lor.
Deoarece intr-un proces sunt de obicei disponibile mai multe semnale, provenite de la diverse dispozitive, (senzori, traductoare), acestea trebuie citite si prelucrate in mod continuu, deci in mod automat avem de a face cu o aplicatie multitasking, indiferent de modul cum a fost implementat acest multitasking. Astfel exista mai multe posibilitati de a distribui semnalul:
  1. individualizat pe dispozitiv
  2. global centralizat.
1. Individualizat pe dispozitiv, permite o mai buna structurare a controlului, o astfel de aplicatie avind structuri bine formate care sa reprezinte distinct dispozitivele pe care le conduce. Teoretic in acest caz, aplicatia de control se compune dintr-o multitudine de astfel de structuri functionale care sunt suficient de dezvoltate pentru a sti sa prelucreze si coordoneze singura dispozitivul pe care-l coordoneaza. In acest caz, elementul de servire a datelor se integreaza in aceasta structura.

Fig:1.3.2.1 Structura individualizata pe dispozitive

Pentru a fi capabila de a exporta semnalul, trebuie modificate doua blocuri functionale si anume, partea de citire a semnalului si partea de elaborarea a comenzi. Structura modificata a acestora poate fi urmarita mai jos.


Fig:1.3.2.2 Structura citeste semnal, modificata pentru exportul datelor



Fig:1.3.2.3 Structura elaboreaza comanda, extinsa pentru distribuirea procesului

  1. Global centralizat – presupune operatiile de colectare si distribuire a semnalelor centralizate intr-un singur loc, de unde se apeleaza pe rind sub forma de proceduri sau functii, elementele de control, afisare si prelucrare a semnalelor. In acest caz exportarea semnalelor, se face in cadrul blocului centralizator
Fiecare metoda prezinta avantaje si dezavantaje, mai mult sau mai putin obiective, legate de claritatea implementari, de performante si de facilitatile pe care le asigura unei dezvoltari ulterioare.

1.3.3. Clientul de semnal


Desi indeplinesc functii diferite, la baza ele nu difera foarte mult ca implementare, deoarece la fel ca si serverul de proces si clientul are nevoie de o sursa de semnal, genereaza o comanda, si efectueaza functii de prelucrare si afisare asupra semnalului. Se poate spune ca clientul este un server, fara facilitatile de distributie a semnalului. Aceasta remarca, nu-si are baza in teoria mecanismelor client-server, ci doar cind este vorba de servere si clienti de procese, deoarece si un server de proces, este la rindul lui un client, in toata puterea cuvintului al procesului.
Deci, asupra clientul de proces, se poate aplica aceiasi structura ca si a serverului. Daca se pastreaza si mecanismele de server, atunci acesta poate fi la rindul sau server de proces, permitindu-se realizare unor lanturi de semnal.

1.3.4. Structura de comunicatie


Din punctul de vedere al protocoalelor folosite pentru transmiterea datelor, se pot mentiona un numar de doua, mai importante:
  1. TCP
  2. UDP
Fiecare din aceste protocoale au avantajul si dezavantajul lor, sau mai degraba functionalitatea lor.

  1. TCP – este un protocol, foarte raspindit, si foarte utilizat, principalul punct forte este ca pe parcursul transmisie, pachetele de date transmise ajung in aceiasi ordine si fara pierderi de date.

  1. UDP – este un protocol, destinat transmisiilor, la care pierderea unor pachete de date nu este o catastrofa, ba chiar recuperarea lor ar fi. Se foloseste in special acolo, unde datele imbatrinesc foarte repede, si dina acest motiv, o eventuala recuperare a unui pachet pierdut, nu prezinta nici o importanta, deoarece data este oricum veche, si deci invalida.

Pentru mai multe detalii asupra protocoalelor se poate consulta [VALEAN97].
Din punct de vedere al incapsulari datelor acestea pot fi, de tip canal si dispozitiv, sau de tip singur canal.
Canal si dispozitiv presupunea asignarea unui canal individual, fiecarui, semnal individual din proces.
Un singur canal presupune, comprimarea si codificarea datelor tuturor dispozitivelor pe un singur canal de comunicatie, singurul dezavantaj, insa al acestei tehnici, este pierderile de timp, datorita, codificari – decodificari semnalelor la cele doua capete ale transmisie.


1.3.5. Instrumente virtuale

 
Folosirea calculatoarelor pe post de elemente indicatoare, si de interactiune cu clientul, a dus la aparitia unui nou tip de instrumente, denumite instrumente virtuale, instrumente deoarece asigura toate functionalitatea unui instrument real, si virtuale deoarece exista numai sub forma unui program rulat pe un calculator. Facilitatile unor astfel de instrumente sunt imense, in primul rind custurile de executie sunt reduse, ele fiind doar programe, pe de alta parte nu se defecteaza niciodata, si ofera o interfata, sugestiva pentru utilizator. Un astfel de instrument inglobeaza toate functiile unui instrument real, citeste semnalul, il prelucreaza, si afiseaza, preia comanda de la utilizator, o prelucreaza, si prin intermediul diverselor drivere, o trimite dispozitivului.

Descrierea pachetului JaRPE


Acronimul de JaRPE, provine de la JavA Remote Process Explorer si cuprinde un set de programe si librarii pentru demonstrarea facilitatilor limbajului Java, in construirea diverselor aplicatii si in speta pentru controlul de la distanta a proceselor industriale, precum si pentru realizarea unor instrumente virtuale.
Deci componenta pachetului se poate descrie in felul urmator:


2.1. Instrumente Virtuale Java (Javins)


Instrumentele Virtuale Java asigura toata functionalitatea unor instrumente virtuale, permitind receptionarea, prelucrarea, distribuirea semnalului, precum si preluarea comenzi de la utilizator sau de la un instrument virtual aflat la distanta si trimiterea ei la sursa semnalului.
Un Javins i-si poate prelua semnalul, fie dintr-o sursa locala de semnal, sursa locala reprezentata printr-o clasa sau un obiect al clasei respective care realizeaza operatia de citire a dispozitivului fizic si elaborarea unor streamuri de date (intrare si iesire) pe care Javins-ul sa poata sa le foloseasca. O alta optiune este sa preia aceleasi streamuri de date, dintr-o sursa de semnal situata la distanta, sursa de semnal fiind specificata printr-o adresa URL si un port de ascultare. Aceasta delimitare este insa doar, in interiorul metodei de initializare a conexiuni, dupa aceasta, Javins-ul trateaza in mod unitar streamurile de date, indiferent de provenienta lor.
Una din metodele fundamentale ale programari orientate pe obiecte, afirma separarea portiuni de cod care poate suferi modificari de partea de cod care este tot timpul stabila. Din acest motiv s-a optat pentru utilizarea unei alte clase pentru realizarea unei transfer de semnal, dintr-o sursa de semnal interna.
Din punctul de vedere al interfetei, un instrument virtual prezinta trei zone distincte, asa cum se poate urmari si in figura de mai jos:

Fig:2.1.1 Interfata unui Javins

Algoritmul de functionare, simplificat a unui Javins poate fi urmarit in diagrama de mai jos:


Fig: 2.1.2 Algoritmul de functionare simplificat al unui Javins


2.1.1. Comunicatia


Comunicatia prezinta aspectul cel mai important al instrumentelor virtuale, ele trebuie sa preia un semnal si de asemenea trebuie sa genereze o comanda.
Intern, sursele de semnal folosite sunt implementate sub forma unei clase denumite SignalPair , aceasta este o clasa fara metode si implementarea ei poate fi urmarita mai jos :

public class SignalPair {
/**
* signalIn-este streamul care asigura datele de intrare
*/
public DataInputStream signalIn;

/**
* signalIn - este streamul care asigura iesirea datelor
*/
public DataOutputStream signalOut;
}

DataInputStream si DataOutputStream reprezinta streamuri de intrare si iesire Java care ofera posibilitatea formatari datelor.
SignalIn si SignalOut reprezinta streamurile de intrare si de iesire de date, aceste streamuri sunt culese direct de la sursa, dar intern, in mod direct se lucreaza numai cu streamul de iesire al datelor SignalOut cel de intrare fiind folosit pentru a deriva un alt stream, SignalInputStream, care are particularitatea ca datele care sunt citite din el sunt modificate de catre un obiect modificator, permitindu-se in acest fel efectuarea unor operatii de prelucrare asupra datelor de intrare .
 

Se poate observa ca datele de la sursa receptionate de catre streamul de intrare SignalIn sunt prelucrate de catre modificatorul de semnal si apoi scrise in format SignalInputStream si folosite pentru afisare, in acest fel permitindu-se efectuarea diferitelor operatii simple sau complexe asupra lor.

 

Algoritmul de extragere a streamurilor de date, implementat de metoda initializeConection, poate fi urmarit mai jos:

 
Pentru a putea permite o implementare facila a acestor mecanisme de preluare a sursei de semnal, s-au implementat doua tipuri de interfete si anume L ocalSignalSource si RemoteSignalSource. Astfel se asigura uniformitatea implementarii lor. Definitiile acestor interfete sunt:

public interface LocalSignalSource {
/**
* Pastreaza numele clasei din care se instantiaza o sursa locala
*/
String localSignalSourceClass = "";
LocalSignalSource localSignalSource = null;

/**
* Asigura metodele standard pentru un Bean de setare si preluare
* a numelui clasei din care se va instantia obiectul
* @param localSignalSourceClass - numele clasei din care se va
* instantia obiectul
*/
public void setLocalSignalSourceClass(String localSignalSourceClass);

/**
* Asigura metodele standard pentru un Bean de setare si preluare
* a numelui clasei din care se va instantia obiectul
* @return localSignalSourceClass - numele clasei din care se va
* instantia obiectul
*/
public String getLocalSignalSourceClass();

public void setLocalSignalSource (LocalSignalSource localSignalSource);

public LocalSignalSource getLocalSignalSource ();
/**
* Realizeaza instantierea obiectului.
* Din numele clasei setat, se creaza clasa si se instantiaza
* @return LocalSignalSource - instanta generatorului de semnal local
*/
public LocalSignalSource getLocalSignalSourceInstance();

/**
* Din instanta de generator de semnal local, data initial ca si nume de
* clasa, se culege perechea de streamuri de data (DataInputStream,
* DataOutputStream), pentru comunicatia bidirectionala
* @return SignalPair - Cele doua streamuri (In/Out de date)
*/
public SignalPair getLocalSignalPair();
}

Definitia interfetei de conectare de la distanta este:

public interface RemoteSignalSource {
String sourceURL ="" ;
int sourcePort=3000;

/** Seteaza URL-ul la care se va conecta in vedera
* comunicatie, cu obiectul oglinda, generator de semnal
* @param sourceURL - URL-ul
*/
public void setSourceURL(String sourceURL);

/** Returneaza URL-ul la care se va conecta in vedera
* comunicatie, cu obiectul oglinda, generator de semnal
* @return - URL-ul
*/
public String getSourceURL();

/** Seteaza portul la care se va conecta in vedera
* comunicatie, cu obiectul oglinda, generator de semnal
* @param sourcePort - portul
*/
public void setSourcePort(int sourcePort);

/** Returneaza portul la care se va conecta in vedera
* comunicatie, cu obiectul oglinda, generator de semnal
* @return - portul
*/
public int getSourcePort();


/** Incearca conectarea la sursa de semnal, situata
* remote, prin intreemediul internetului sau a
*intranetului
*/
public void connectRemoteSignalSource();

/**
* Se culege perechea de streamuri de data DataInputStream,
* DataOutputStream), pentru comunicatia bidirectionala
*/
public SignalPair getRemoteSignalPair();
}

Cele mai importante metode din aceste interfete sunt :
connectRemoteSignalSource pentru conectarea la distanta si
getLocalSignalSourceInstance pentru o sursa de semnal locala, amindoua creind in acest fel legatura cu sursa de semnal. Aceste metode pot ramine nemodificate, pe parcursul creari altor Javins-uri, ele mentinindu-se .
Implementarea reala a celor doua metode se poate observa mai jos:

public void connectRemoteSignalSource() {
if ( sourceURL != null
&& sourceURL != ""
&& sourcePort != -1 ) {
try {
remoteSocket = new Socket (
InetAddress.getByName(sourceURL)
, sourcePort);
} catch (Exception ex) {
System.err.println("Problem Conection to host : "
+ sourceURL + " on port : "
+ sourcePort + " failed !");
ex.printStackTrace();
alertLabel.setMessage(true, "R.C. Failure");
System.err.println(“remoteSocket initialized to –“
+ “NULL -- !");
}
}
else remoteSocket = null;
}

Se poate observa crearea unei conexiuni, bazata pe protocolul TCP/IP, prin intermediul constructorului Socket(InetAddres, port) , de asemenea se poate observa, mecanismul de tratare a erorilor.
Pentru conectarea la sursa locala de semnal mecanismele, sunt mai complicate, deoarece singurul lucru pe care il avem este numele clasei care a fost implementata pentru a face semnalul fizic disponibil componentei software, fara a fi nevoiti sa o modificam, pentru a putea sa preia semnalul:
public LocalSignalSource getLocalSignalSourceInstance () {
String className = getLocalSignalSourceClass();
if (className != "" &&
className != null &&
localSignalSource == null) {
try {
Class localSignalSClass = Class.forName(className);
LocalSignalSourcelss =(LocalSignalSource)
localSignalSClass.newInstance();
setLocalSignalSource(lss);
return lss;
} catch (ClassNotFoundException ex) {
System.err.println("Problems in :" +
this.getClass().getName() +
" at getLocalSignalSource -> " +
className + " not found !");
ex.printStackTrace();
System.err.println("LocalSignalSourceinitializet to”
+ “ -> NULL <- !");
return null;
}
catch (Exception ex) {
System.err.println("Problems in :" +
this.getClass().getName() +
" at getLocalSignalSource -> " +
className + " can not be “
+ “initialized !");
ex.printStackTrace();
System.err.println("LocalSignalSource initialized “
+ “to -> NULL <- !");
return null;
}
}
else return null;
}

Se poate observa, cum dintr-un sir de caractere care reprezinta numele unei clase se creeaza un obiect nou. Aceasta presupune doua etape:
Crearea clasei se face prin intermediul metodei class.forName(String param) , dupa ce s-a creat (mult mai corect ar fi spus incarcat) clasa, se poate instantia obiectul prin intermediul metodei newInstance(), astfel pornind de la un sir de caractere, in final avem un obiect valid capabil sa capteze un semnal de la un dispozitiv fizic, prin intermediul driverelor sau al accesului direct prin porturi sau intreruperi.

2.1.2. Serverul de semnal


Orice instrument virtual, indiferent daca este la rindul ei client, de la distanta, poate fi server de semnal, facilitind astfel crearea lanturilor de instrumente virtuale distribuite. Un Javins poate deveni server de semnal prin setarea portului pe care se va instaura , noul serviciu si setarea unei variabile logice prin intermediul metode, setServer([valoare logica]), aceasta fiind o metoda pe care fiecare Javins o mosteneste si deci o are automat implementata.
In caz, ca se doreste ca un Javins sa fie server de semnal, atuncea acesta porneste un fir de executie separat, pentru a nu perturba functionalitatea de baza a componentei. In acest moment acest server de semnal este un server secvential , si nu unul multithreading. Implementarea unui server de semnal care sa poata suporta mai multi clienti in acelasi timp ar duce la scaderi nedorite ale performantei. Dar un asemenea mecanism, nu este dificil de realizat.
Clasa care implementeaza serverul de semnal se numeste JavinsDspecher si primeste ca parametru pe insusi Javins-ul care la creat. Aceasta este necesar pentru a putea folosi la trimiterea si receptionarea datelor, metodele corecte, dedicate acestui scop din cadrul Javins-ului.
Secventa de cod care porneste serverul este:

public void startServer() {
if (isServer()) {
javinsDispecher = new JavinsDispecher (this);
serverThread = new Thread (javinsDispecher);
System.out.println("Prepair to start server ");
serverThread.start();
}
}

Se poate urmari astfel usurinta cu care se poate porni un nou fir de executie.
Apelarea metodei start() de fapt porneste firul de executie, metoda care va fi rulata, va fi run().
Se poate urmari mai jos bucla principala care accepta o conexiune, si o deserveste:

public void run() {
while(true) {
System.out.println("Waiting for clients");
try {
socket = serverSocket.accept();
System.out.println("I have clients");
baseJavins.communicate("New Client:" +
socket.getInetAddress().getHostAddress());
rDataIn = new
DataInputStream(socket.getInputStream());
rDataOut= new
DataOutputStream(socket.getOutputStream());
for ( ; ;) {
(Thread.currentThread()).yield();
baseJavins.writeSignal2Server(rDataOut);
baseJavins.readSignalFServer(rDataIn);
}
}catch (SocketException ex) {
System.out.println("Client lost !");
baseJavins.communicate("Client Lost")
}
catch (Exception ex) {
System.out.println("Client lost !");
}
}
}

La crearea unui nou tip de componenta, este suficient sa se rescrie metodele writeSignal2Server si readSignaFServer si astfel metodele supradefinite vor fi apelate in acest ciclu.

2.1.3. JaviButton


Acesta este o componenta standard, reprezentind functional un buton cu doua stari, care pot fi codificate prin ON si OFF.
Imaginea unui astfel de Javins, poate fi urmarita in figura de mai jos:




Fig: 2.1.3.1 Instanta de JaviButton

Implementarea care difera de Javins-ul de baza sunt cele legate de interfata, precum si metodele de scriere semnal, citire semnal, scriere semnal la server, citire semnal de la server.
Implementarea metodei de citire semnal este:

public void readSignal(SignalInputStream mySignalIn) throws
IOException{
byte readValue = mySignalIn.readByte();
if ( readValue == 2 ) {
if (!value) {
b.setForeground(Color.red);
b.setLabel("ON");
synchronized(this) {
value = true;
}
ActionEvent ne = new ActionEvent(this, 1, "ON");
processActionEvent(ne);
}

}
else if (readValue == 1) {
if (value) {
b.setLabel("OFF");
b.setForeground(Color.green);
synchronized(this) {
value = false;
}
ActionEvent ne = new ActionEvent(this, 1, "OFF");
processActionEvent(ne);
}
}
}

Semnal trimis este totdeauna valoarea semnalului incrementata cu unu, pentru a putea face distinctie, la receptionare de valorile de confirmare receptie care este tot timpul zero.
De asemenea se pot observa, sectiunile de sincronizare, formatate in cadrul blocurilor synchronized(this), aceasta metoda protejind de alterarea valorilor, in cadrul contextelor de executie multifir.

Implementarea metodei de scriere semnal este:

public boolean writeSignal(DataOutputStream myDataOut) throws IOException{
if (getLocalSignalSource() == null) {
if (newValue) {
int byteValue = pip.read();
myDataOut.writeByte((byte)byteValue);

synchronized(this) {
newValue = false;
}
return true;
} else {
myDataOut.writeByte(0);
return true;
}
}
else if (newValue) {
myDataOut.writeByte(valueByte);
synchronized(this) {
newValue = false;
}
}
else myDataOut.writeByte(0);
return true;
}

Se poate observa, ca daca nu este, valoare noua a comenzi se trimite, valoare de confirmare a receptiei zero. Algoritmul de transmisie se poate spune ca face parte din clasa simplex, de tip send and wait, mai multe amanunte despre aceasta se poate studia in [VALEAN97]. Nu este cea mai eficace metoda de transmisie receptie, dar scopul proiectului este didactic.
Variabila newValue este folosita cu rol de semafor, semnalizind de fiecare data cind exista o noua valoare a semnalului de comanda, valoare care se transmite, in loc de semnalul de confirmare.

2.1.4. JaviMultiPos


Acesta este o componenta standard, reprezentind functional un buton cu mai multe stari (maxim posibile patru), care pot fi codificate prin intermediul unui sir de caractere, in are valorile individuale sunt separate prin virgula.
Imaginea unui astfel de Javins, poate fi urmarita in figura de mai jos:



Fig: 2.1.4.1 Instanta de JaviMultiPos, cu patru stari

Implementarea care difera de Javins-ul de baza sunt cele legate de interfata, precum si metodele de scriere semnal, citire semnal, scriere semnal la server, citire semnal de la server.
Implementarea metodei de citire semnal este:

public void readSignal(SignalInputStream mySignalIn) throws IOException{
byte readValue = mySignalIn.readByte();
if ( readValue != 0 ) {
b.setCurrent(readValue -1);
ActionEvent ne = new ActionEvent(this, 1, readValue-1 + "");
processActionEvent(ne);
}
}

Se poate observa, ca daca valoarea citita, este diferita de zero, acesta fiind semnal de confirmare a transmisiei, se seteaza valoare butonului multipozitional. Acest buton multipozitional, este o componenta scrisa special, care permite sa se discretizeze, anumite valori si sa se afiseze valoare cuantei curente.
Structura, de scriere a semnalului, este implementata ca si mai jos:

public boolean writeSignal(DataOutputStream myDataOut) throws IOException{
if (getLocalSignalSource() == null) {
if (newValue) {
int byteValue = pip.read();
myDataOut.writeByte((byte)byteValue);
synchronized(this) {
newValue = false;
}
return true;
} else {
myDataOut.writeByte(0);
return true;
}
}
else if (newValue) {
myDataOut.writeByte(valueByte);
synchronized(this) {
newValue = false;
}
}
else myDataOut.writeByte(0);
return true;
}
Se poate observa ca mecanismul de scriere este aproximativ identic cu cel al componentei JaviButton, folosindu-se acelasi semafor newValue, pentru semnalizarea unei valori noi.

Metodele speciale de scriere a semnalului catre server, este:

public boolean writeSignal2Server(DataOutputStream signalOut) throws
IOException{
signalOut.writeByte(b.getCurrent()+1);

return true;

}

Iar cel de citire de la serverul de semnal, pe care il implementeaza, daca il implementeaza, se poate observa mai jos:

public void readSignalFServer(DataInputStream signalIn) throws IOException{
int readValue;
readValue = signalIn.readByte();
if (readValue != 0) {
System.out.println(readValue);
pop.write(readValue);
valueByte = (byte)readValue;
pop.flush();
newValue = true;
communicate("new remote value");
}
}

Se poate observa, aceeasi delimitare, dintre semnal zero receptionat si alta valoare.


2.1.5. JaviDiagram


Acesta este o componenta standard, reprezentind functional un afisaj, stil osciloscop, pe care fiecare valoare a semnalului este afisat cu o diviziune mai mare pe scara timpului, axa X.
Imaginea unui astfel de Javins, poate fi urmarita in figura de mai jos:



Fig: 2.1.5.1 Instanta de JaviDiagram

Implementarea care difera de Javins-ul de baza sunt cele legate de interfata, precum si metodele de scriere semnal, citire semnal, scriere semnal la server, citire semnal de la server, totusi diferentele sunt ca acest Javins spre diferenta de cele prezentate anterior, nu poate trimite sau accepta comenzi, el putind doar citi date.

Implementarea metodei de citire semnal este:

public void readSignal(SignalInputStream mySignalIn) throws IOException{
byte readValue = mySignalIn.readByte();
if ( readValue != 0 ) {
b.draw(readValue -1);
valueByte = readValue;
synchronized (this) {
newValue = true;
}
}
}

Diferentele, fata de implementarile anterioare, sunt minore.
Implementarea, metodei de scriere semnal, la serverul de semnal este :

public boolean writeSignal2Server(DataOutputStream signalOut) throws IOException{
if (newValue) {
signalOut.writeByte(valueByte);
synchronized(this) {
newValue = false;
}
}
else signalOut.writeByte(0);

return true;
}

Metoda de scriere fiind aproape identica, cu cea de la alte componente.

2.2. Editorul vizual de interfete (JaRPEdit)


Pentru a demonstra facilitatile, programari orientate pe obiecte, precum si a programari pe componente, sa construit un editor de interfete, care sa exploateze facilitatile oferite de Javins-uri.
Editorul este compus din trei parti:
  1. Fereastra principala
  2. Fereastra cu unelete
  3. Fereastra de lucru

Cele trei ferestre pot fi urmarite in figurile de mai jos:


 
Fig: 2.2.1 Fereastra principala



Fig: 2.2.2 Fereastra cu unelte




Fig: 2.2.2 Fereastra de lucru

Principalele functionalitati ale editorului de interfete sunt:

2.2.1. Incarcarea componentelor


La pornire programul cauta, directorul Jars, din cadrul directorului de start, acest director contine fisiere, cu extensia jar. Java ofera o metoda standard de a livra pachetele de programe, acestea sunt arhivate sub format ZIP sau GZIP, si plasate in cadrul unui fisier cu extensia jar. Avantajul pe linga, reducerea spatiului de stocare, este ca fisierul contine un declarator, care este un fisier inglobat, care contine numele tuturor claselor, din cadrul pachetului, precum si daca clasa respectiva reprezinta o componenta sau nu.
Deci programul scaneaza, toate fisierele cu extensia jar din directorul respectiv, si acolo unde gaseste componenta, o incarca ti mai apoi o instantiaza. Mecanismul de instantiere este descris, la capitolul de Javins-uri, la descrierea metodei l ocalSignalSourceInstance.

2.2.2. Plasarea componentelor


Aceste componente, in momentul in care se lucreaza cu ele, sunt active, deci ruleaza, pentru a face publice proprietatile componentelor, si aceasta doar, in cadrul editorului vizual de interfete si nu in cadrul aplicatiilor, unde un astfel de comportament nu este de dorit, sa folosit o clasa care sa invaluie componenta si la anumite operatii ale utilizatorului s-i dezvalui proprietatile pentru modificare. Aceasta clasa, se numeste Wrapper, si rolul ei poate fi oarecum vizualizat in figura urmatoare:
 



Fig: 2.2.2.1 Functionalitatea wrapperului

Procedura de adaugare a unei componente in cadrul unui wrapper poate fi vazuta mai jos:

public Wrapper(Object bean, String beanName, String beanLabel) {
System.out.println(beanName + " : " + beanLabel);
this.bean = bean;
this.beanLabel = beanLabel;
if (beanName == null) {
beanName = bean.getClass().getName();
}
this.beanName = beanName;
setLayout(null);
if (Beans.isInstanceOf(bean, Component.class)) {
child = (Component)Beans.getInstanceOf(bean, Component.class);
}
popmen= new WrapperPopupMenu(beanName, beanLabel);
this.add(child);
this.add(popmen);
this.addMouseListener(this);
this.addMouseMotionListener(this);
child.setLocation(borderWidth, borderWidth);
initialize();
doLayout();
}

Acest wrapper dupa ce a inglobat componenta se poate plasa pe suprafata activa de lucru ca o componenta normata.

2.2.3. Modificarea proprietatilor componentelor


Motivul existentei unui asemenea mediu de dezvoltare vizual, nu este justificat, daca nu se lucreaza, cu componente care pot fi modificate, intr-un mod intuitiv si vizual. Java asigura o tehnica foarte performanta, care se numeste reflectie si care permite determinarea exacta a metodelor, a variabilelor de instanta si a constructorilor unui obiect. Astfel unui obiect, activ, care ruleaza i se poate determina in mod activ, metodele pe care le pune la dispozitie, sau cu alte cuvinte un obiect permite sa i se cunoasca ce obiecte ii determina starea si ce comportamente pune la dispozitie pentru a i se modifica starea. In cazul componentelor standard Java, descrise ca Java Beans, se merge mai departe, existind o clasa implementata in cadrul pachetului Java standard denumita PropertiesDescriptor care identifica, conform unei conventii exact care proprietate a componentei se doreste a fi publica, si prin intermediul caror metode se scrie si se citeste acea proprietate.
Implementarea acestei functionalitati este miezul, acestei interactiuni dintre utilizator si componenta. Implementarea ei poate fi urmarita mai jos:

...
try {
BeanInfo bi = Introspector.getBeanInfo(target.getClass());
properties = bi.getPropertyDescriptors();
} catch (IntrospectionException ex) {
error("PropertySheet: Nu se poate inspecta componenta", ex);
return;
}

editors = new PropertyEditor[properties.length];
values = new Object[properties.length];
views = new Component[properties.length];
labels = new Label[properties.length];

EditedAdaptor adaptor = new EditedAdaptor(frame);

for (int i = 0; i < properties.length; i++) {


String name = properties[i].getDisplayName();
Class type = properties[i].getPropertyType();
Method getter = properties[i].getReadMethod();
Method setter = properties[i].getWriteMethod();
...

Se poate observa cum se creeaza un obiect care sa interogheze obiectul

properties = bi.getPropertyDescriptors();

Dupa cate cum se determina proprietatile, tipul lor, si metodele de scriere si citire a lor:

String name = properties[i].getDisplayName();
Class type = properties[i].getPropertyType();
Method getter = properties[i].getReadMethod();
Method setter = properties[i].getWriteMethod();

Obiectul setter contine, metodele de setare a proprietatilor, iar obiectul getter contine metodele de citire a proprietatilor.
O imagine a modificari proprietatilor unui Javins, mai exact a unui JaviButton, se pot urmari in figura de mai jos:



Fig: 2.2.3.1 Modificarea proprietatilor unui Javins


2.2.4. Salvarea interfetei


Metoda pe care se bazeaza salvarea interfetei este serializarea, mai corect este o implementare a metodelor de persistenta. Prin intermdiul persistentei starea unui obiect se poate ingheta, astfel durata de viata a obiectului poate depasi cu mult durata de viata a programului care la creat.
Aceasta metoda este folosita si pentru transmitea interfetelor, unei aplicatii care ii realizeaza infatisarea, si porneste functionalitatea obiectelor.
Ideea de baza este sa se initializeze componentele cu valorile dorite, adresa sursei de semnal, portul pe care se va constitui ca server de semnal, numele, culoarea, dimensiunea, pozitia si multe altele, si sa se inghete componenta prin serializare, pastrindu-si astfel, valorile setate de noi in editorul de interfete. La rulare, aceste componente vor fi dezghetate, continind in continuare obiectele setate de noi, si pe urma puse in functionare.

Metoda care realizeaza salvarea este prezentata in listingul de mai jos:
protected void saveInterface(String type) {
if (workframe == null) {
new Message (this, "Error", "Nothing to Save");
return;
}
if (savePathFileName == null || type == "Save As") {
FileDialog fd = new FileDialog( this
,"Save Interface As"
, FileDialog.SAVE);
fd.setFile(saveFileName);
fd.setDirectory(".");
fd.show();
if ((saveFileName = fd.getFile()) == null) return;
savePathFileName = fd.getDirectory() + fd.getFile();
}

Vector vect = new Vector();
JavinstWrapper jwr;
Component [] cop = workframe.getComponents();

jwr = new JavinstWrapper(workframe.getSmartPanelProp().getSmartProp(), "SmartProp");
vect.addElement(jwr);

for (int i = 0; i < cop.length; i++) {
if (cop[i] instanceof Wrapper) {
((Wrapper)cop[i]).prepareSaveBean();
jwr = new JavinstWrapper(((Wrapper)cop[i]).getBean(),
((Wrapper)cop[i]).getBeanName());
vect.addElement(jwr);
}
}
(new InterfaceSaver(vect, savePathFileName)).saveInterface();
for (int i = 0; i < cop.length; i++)
if (cop[i] instanceof Wrapper)
((Wrapper)cop[i]).restoreSaveBean();

}
Se poate observa ca la salvare pentru fiecare componenta se apeleaza metoda din wrapperul ei prepareSaveBean, aceasta metoda realizeaza, serializarea componentei, pe care o inglobeaza.


2.3. Incarcatorul de interfete



Are menirea de a incarca, afisa si pune in functionare o interfata.
Numele clasei, care realizeaza aceasta este SmartApplet.java
Poate functiona in doua moduri:
  1. Ca aplicatie de sine statatoare, caz in care la rulare se specifica, numele fisierului de interfata pe care sa-l foloseasca.
  2. Ca applet, caz in care se specifica, sub forma de tag parametru, numele interfetei, pe care sa-l foloseasca.
Functionalitatea lui descrisa pe scurt, este sa incarce componentele, serializate in cadrul fisierului de interfete, sa le pozitioneze, respectiv afiseze, si in caz ca sunt componente capabile de a rula intr-un fir de executie, sa le creeze un fir de executi, si sa-l lanseze.

Un fisier de interfata are urmatoare structura:


Fig: 2.3.1 Structura unui fisier de interfete


Codul de incarcare a componentelor se poate urmari mai jos:

private void loadJavinst() {
try{
ObjectInputStream ois;
if (!file) {
remoteTargetLocation = getCodeBase().toString() + getParameter("InterfaceFile");
URL where = new URL(remoteTargetLocation);
ois = new ObjectInputStream(where.openStream());
}
else {
File where = new File(remoteTargetLocation);
ois = new ObjectInputStream(new FileInputStream(where));
}
int dim = ois.readInt();
comp = new Vector(dim);
for (int j = 0; j < dim; j++) {
JavinstWrapper wrp = (JavinstWrapper) ois.readObject();
comp.addElement(wrp);
}
JavinstWrapper wr = (JavinstWrapper) comp.elementAt(0);
obj = (SmartProp)wr.getJavinstObject();
setBounds(0,0,obj.getInterfaceWidth()+10, obj.getInterfaceHeight()+10);
resize(new Dimension(obj.getInterfaceWidth()+10, obj.getInterfaceHeight()+10));
} catch(Exception e){
e.printStackTrace();
}
}

Se poate observa diferenta, intre rularea ca aplicatie si rularea ca applet, functional este vorba de locatia de unde se incarca fisierul de interfete, un applet, desi se executa local, are resursele situate la distanta, si deci fisierul trebuie, incarcat prin specificarea, si cu folosirea unei resurse URL. In cazul rulari ca aplicatie de sine statatoare, el se cauta pe sistemul de fisiere local.
Codul sursa pentru pornirea, componentelor se poate urmari mai jos:

for (int i = 1; i< components.size(); i++) {
jwr = (JavinstWrapper)javinst.elementAt(i);
Component com = (Component)jwr.getJavinstObject();
add(com);
if (com instanceof Runnable ) {
System.out.println("E runable");
if (com instanceof BaseJavins) {
System.out.println("Startimg thread for class: " + com.getClass().getName());
Thread runthread = new Thread((Runnable)com);
runthread.start();
}
else {
Method met[] = com.getClass().getDeclaredMethods();
for (int j = 0; j < met.length ; j++){
if (met[j].getName().equals("run") || com instanceof BaseJavins) {
System.out.println("Startimg thread for class: " + com.getClass().getName());
Thread runthread = new Thread((Runnable)com);
runthread.start();
}
}
}
}

Verificarea daca este o componenta multifir de executie se face prin doua moduri. Primul verifica, daca la baza implementeaza, interfata de Runnable, interfata, pe care trebuie sa o implementeze orice fir de executie. Cea de a doua metoda, verifica, utilizind reflectia daca componenta are o metoda denumita, run.

2.4. Generatorul de semnal


Pentru a demonstra functionarea, pachetului JaRPE, s-a implementat un generator de semnal, care poate fi considerat un proces. Acesta distribuie semnalele si comenzile sale facind astfel posibil, controlul lui de la distanta.
Pentru a demonstra facilitatile instrumentelor virtuale, se folosesc aceleasi componente care sunt folosite la elaborarea interfetei procesului si anume
Modul cum arata generatorul se poate vedea in figura de mai jos:





Fig: 2.4.1 Interfata generatorului de semnal

Semnalul este generat de catre o clasa numita generator, care in functie de o comanda primita este capabila sa genereze un stream de date care sa reflecte un semnal sinusoidal, dreptunghiular sau triunghiular. Implementarea acestui generator se poate urmari mai jos:

public int getNextValue() {
switch (type) {
case 1: if (cnt > amplit) desc = true;
if (cnt < amplit*-1) desc= false;
if (desc) cnt--;
else cnt++;
break;
case 2: cnt++;
if (cnt > perio) cnt = 0 ;
if (cnt == 0) return 0;
if (cnt < perio/2 && cnt != 0) return amplit;
if (cnt == perio/2 ) return 0;
if (cnt > perio/2 && cnt < perio) return amplit*-1;
if (cnt == perio) { cnt = 0; return 0; }

break;
case 3: ++cnt;
return ((new Double(Math.sin(cnt*Math.PI/70)*
amplit)).intValue());

}
return cnt;
}

Acesta ruleaza ca un thread separat, pentru a se permite generarea continua a semnalului. De asemenea el implementeaza, localSignalSource pentru a asigura semnal direct Javins-ului care se ocupa de afisarea semnalului.
Un exemplu de implementare a unui controler de proces, realizat cu instrumente virtuale, si facilitatile Javins-urilor se pot urmari prin modul de implementare a acestui simulator:

// JaviButton
javiButtonThread = new Thread(javiButton);
javiButton.setActionDisplayer(actdis);
javiButton.addActionListener(this);
javiButton.setServerPort(3000);
javiButton.setServer(true);
javiButton.setLocalSignalSource(javiButton);
javiButton.initializeConections();
javiButton.setConected(true);
javiButtonThread.start();

Aceasta este sectiunea de creare a butonului de retea. Se poate observa, ca se seteaza a fi server, prin metoda setServer(true), urmind a receptiona clienti la portul 3000.

// JaviMultiPos
javiMultiPosThread = new Thread(javiMultiPos);
javiMultiPos.setActionDisplayer(actdis);
javiMultiPos.addActionListener(this);
javiMultiPos.setServerPort(3001);
javiMultiPos.setServer(true);
javiMultiPos.setLocalSignalSource(javiMultiPos);
javiMultiPos.initializeConections();
javiMultiPos.setConected(true);
javiMultiPosThread.start();

Aceasta este sectiunea de creare a butonului multipozitional. Se poate observa, ca se seteaza a fi server, prin metoda setServer(true), urmind a receptiona clienti la portul 3001.

// JaviDiagram
javiDiagramThread= new Thread(javiDiagram);
javiDiagram.setLocalSignalSource(generator);
javiDiagram.setActionDisplayer(actdis);
javiDiagram.setServerPort(3002);
javiDiagram.setServer(true);
javiDiagram.initializeConections();
javiDiagram.setConected(true);
javiDiagramThread.start();

}

Aceasta este sectiunea de creare a elementului care afiseaza semnalul. Se poate observa, ca se seteaza a fi server, prin metoda setServer(true), urmind a receptiona clienti la portul 3002. Tot aici se poate observa cum se seteaza, sursa de semnal al instrumentului virtual, ca fiind obiectul generator.


2.5. Concluzie


Un programator bun este capabil sa implementeze o specificatie in orice limbaj de programare. Problema se pune insa, cu cite resurse irosite, timp, bani, nervi. Astfel un limbaj de programare trebuie sa ajute programatorul in munca sa, oferindu-i metodologii, tehnici si librarii de functii bine organizate si acoperitoare pentru o multitudine de domenii. Limbajul Java, face parte din acele limbaje de programare care sa asigure suport puternic pentru implementarea aplicatilor din cele mai diverse domenii, asigurind in acelasi timp o serie de tehnologii de ultima ora, printre care putem aminti: programarea orientata pe obiecte, independenta de platforma, suport pentru programarea distribuita si pentru multitasking, mecanisme deosebite de tratare a exceptiilor, suport pentru aplicati multilingve, suport pentru baze de date, mecanisme de securitate si criptografie puternice, si multe, multe altele.
Controlul proceselor de la distanta si instrumentatia virtuala sunt doua dintre domeniile automatici in curs de dezvoltare, si care vor avea un impact destul de puternic asupra ei si in speta asupra informaticii industriale, de acea sa decis, ca partea practica a acestui proiect, sa demonstreze beneficiile pe care le aduc aceste tehnologii. Prin intermediul instrumentelor virtuale, dezvoltate sa reusit implementarea unui simulator de proces in doar citeva sute de lini, si citeva ore de munca. Bineinteles proiectul poate fi dezvoltat in continuare, el reprezentind momentan mai degraba un proiect pedagogic decit o implementare orientata spre performante. Ca o prima directie de dezvoltare se poate implementa mecanisme de securitate si autorizari, canale de comunicatie criptate si suport pentru baze de date.
In momentul de fata, in urma cercetarilor facute de autor, asemenea proiecte de aplicatii sunt in curs de dezvoltare doar in cadrul a doua organizatii sau companii, este vorba de NASA si de Wizcon, ambele din Statele Unite ale Americi.