Un alt tip de aplicaţie creată folosind standardul CGI este un program gateway, care este un script folosit pentru a accesa informaţia care nu este direct accesibilă clientului: de pildă informaţia dintr-o bază de date. Scripturile de acest fel se scriu în limbaje ce posedă extensii pentru a formula interogări SQL şi pentru a citi informaţia conţinută în bazele de date (vezia nexa 3).
O a treia aplicaţie care se poate dezvolta prin programare CGI o reprezintă documentele virtuale, care sunt create ca răspuns la cererea clientului. Se poate crea astfel un document HTML oricît de complex conţinînd text, imagine, fişiere de sunet sau video.
Totuşi programele CGI prezintă şi o serie de dezavantaje:
Serioase probleme de scalabilitate şi performanţă: fiecare cerere CGI lansează un nou proces pe server, iar dacă mai mulţi utilizatori fac acest lucru simultan, mare parte din resursele serverului Web sunt astfel epuizate, efectul imediat fiind că se încetineşte aplicaţia – cu efecte neplăcute pentru utilizator.
Probleme de securitate: datorită uşurinţei cu care sunt concepute şi scrise programele CGI, programatorii le tratează cu aceeaşi uşurinţă ca pe nişte programe obişnuite, neglijînd faptul că scriptul respectiv poate afecta starea serverului Internet. Un atacator poate aşadar specula bug-urile (deficienţele) din scripturile CGI stocate pe server pentru a obţine acces neautorizat la fişierele sistem, sau chiar pentru a obţine controlul întregului sistem. Programele CGI sunt scrise deseori pentru a accepta date într-un anume format, dar spre program, pot fi trimise date arbitrare de lungime nelimitată. Asta înseamnă că aceste programe trbuie scrise robust, astfel încît să fie capabile să refuze datele de intrare atunci cînd acestea sunt rău-intenţionate sau bizare. Posibilitatea de a adăuga funcţii unui server Web prin scripturile CGI complică foarte mult politica de securitate ce trebuie adoptată – atît timp cît un script CGI poate adăuga elemente la un server Web, pot fi şi trebuie, introduse noi probleme de securitate (de exemplu un server Web poate fi configurat astfel încît să poată fi accesate numai fişiere dintr-un anume director, dar un utilizator poate instala neintenţionat un script CGI care permite intruşilor să poată citi fişiere din alte directoare). Este posibil chiar ca scripturile CGI locale care conţin bug-uri să permită unui intrus să execute comenzi arbitrare pe sistemul în cauză (ţinînd cont de faptul că nu toţi utilizatorii au experienţă în a scrie programe de securitate. În concluzie orice script CGI care rulează pe server trebuie să se aştepte la atacuri dese şi să poată stăpîni orice încercare de intrare rău intenţionată, furnizînd întotdeauna în aceste cazuri mesaje de eroare.
Programele CGI sunt lente şi mai ales dacă sunt scrise într-un limbaj interpretat, lent, precum Perl şi nu în cod compilat C.
Accesul direct la memorie: pointerii pot permite accesul direct la locaţiile de memorie, iar dacă scriptul foloseşte pointeri atunci o eroare poate provoca blocarea sistemului deci şi a serverului.
Probleme la portabilitate : pogramele CGI nu fac parte din categoria celor care ,,scrise odată, rulează oriunde”, adică nu sunt portabile – pentru a fi distribuite trebuie rescris codul pentru fiecare platformă Unix, Widows, Mac, etc.
Specificaţia completă pentru CGI o puteţi găsi la adresa http://hoohoo.ncsa/uiuc.edu/cgi
Servlet-uri
Servelet-urile sunt componente software independente de platforma aplicaţiilor server, care extind dinamic serverele care au suport Java integrat. Ele sunt independente şi de protocol, asigurînd un cadru general pentru servicii pe baza modelului cerere-răspuns. Cu ajutorul servlet-urilor extindem deci funcţionalitatea unei aplicaţii de tip server informaţional – FTP, Telnet, SMTP,servere de ştiri,etc. (nu neapărat server HTTP) - un prim domeniu de aplicare (de altfel cel care ne interesează pe noi) fiind binenţeles, extinderea serverelor Web. De exemplu cînd un browser trimite o cerere către un server, serverul o trimite mai departe către servlet. Servlet-ul procesează cererea (accesînd eventual o bază de date) şi construieşte un răspuns convenabil (de obicei în HTML) care este returnat clientului. Pentru ca un servlet să poată rula pe un server Web este nevoie ca serverul să aibă integrată o maşină virtuală Java (JVM – Java Virtual Machine), să dispună de o interfaţă de comunicare cu servlet-uri şi să gestioneze servlet-urile aflate în execuţie. Prima părere pe care ne-o putem face (numai după cele expuse mai sus) este că un servlet nu diferă cu nimic faţă de un script CGI – asigură acces prin Web la informaţii prezentate ca pagini HTML şi nu numai, oferindu-ne posibilitatea de a vizualiza şi de a modifica interactiv aceste date folosind tehnici de generare dinamică a paginilor Web. Pe parcurs însă vom face o diferenţă clară între cele două tipuri de programe sub multe aspecte. Dar iată pentru început care ar fi posibilităţile oferite de servlet-uri (o parte din acestea se regăseau şi în cazul CGI –urilor):
Construiesc dinamic şi returnează un fişier HTML pe baza cererii clientului.
Procesează datele completate de utilizatori printr-un formular HTML şi returnează un răspuns, dacă este cazul.
Facilitează comunicaţiile între mai multe grupuri de oameni prin publicarea de informaţii trimise de mai mulţi clienţi.
Furnizează suport pentru autentificarea utilizatorului şi alte mecanisme de securitate.
Interacţionează cu resursele server-ului, cum ar fi bazele de date, fişiere cu informaţii utile pentru client.
Procesează intrările de la mai mulţi clienţi pentru aplicaţii cum ar fi jocurile în reţea.
Permite server-ului să comunice cu un applet client printr-un protocol specific şi păstrează conexiunea în timpul ,,conversaţiei”.
Ataşează automat elemente de design pentru pagini Web, cum ar fi antete, note de subsol, casete cu citate, etc., pentru toate paginile returnate de server (similar cu mecanismul oferit de SSI).
Forward-ează cereri de la un server la altul în scop de echilibrare al încărcării (load– balancing). De asemenea un server poate conecta între ele mai multe servlet-uri într-un lanţ de filtre, fiecare servlet din lanţ putînd face o modificare sau procesare individuală a datelor de intrare. Servlet-urile pot fi o componentă intemediară a unei aplicaţii distribuite, putînd fi la rîndul lor clienţi ai unor alte servici scrise în alt limbaj. Putem construi deci cu ajutorul servlet-urilor aplicaţii client-server (vezi Anexa1). Bazate pe modelul de trei nivele (three tier arhitecture). Primul nivel poate fi un applet, servlet-ul fiind componenta de mijloc (middle tier), iar componenta a treia o bază de date. În acest caz servlet-ul folosind interfaţa JDBC (Java DataBase Conectivity), accesează o bază de date relaţională.
Plecînd de la ideea că servlet-urile sunt folosite pentru extindere dinamică, le putem folosi ca pe nişte componente auxiliare de tip plug-in, de exemplu în cazul unor motoare de căutare.
Se poate spune că servlet-urile sunt un hibrid între CGI şi interfeţele de programare de nivel inferior ca NSAPI sau ISAPI . Un servlet se comportă ca un script CGI, dar are o durată de viaţă lungă şi se încarcă dinamic (ca şi modulele NSAPI/ISAPI), eliminîndu-se astfel întîrzierile de la pornire specifice CGI-urilor. După încărcare, la o nouă cerere, nu mai este necesar să fie creat un nou servlet – serverul doar apelează o metodă care deserveşte cererea, astfel încît este nevoie doar de o schimbare de context uşoară (light-weight) pentru alt fir de execuţie (vom detalia pe parcurs). Fiind scrise în Java, servlet-urile ,,moştenesc” o mare parte din caracteristicile şi punctele tari ale limbajului:
Portabilitatea – poate rula pe diverse platforme fără a necesita o rescriere sau o recompilare a codului.
Încărcarea dinamică – poate fi încărcat şi invocat de pe discul local sau de la distanţă, prin reţea.
Configurabilitatea – instalarea, pornirea, oprirea, specificarea parametrilor de start şi a caracteristicilor unui servlet sunt realizate într-un mod simplu şi sugestiv, prin intermediul unui sistem de administrare ce dispune de o interfaţă grafică (GUI – based Administration Tool).
Siguranţă în funcţionare – modelul de securitate şi încapsularea (sandbox) protejează servlet-ul de atacuri, chiar şi în momentul cînd este apelat de la distanţă. Deoarece încărcarea în memorie a servlet-urilor se face prin mecanismul standard Java (folosit de orice altă maşină virtuală Java), care permite încărcarea claselor Java din reţea, apar anumite probleme de securitate. Aceste probleme se referă în primul rând la servlet-urile aduse din reţea, de pe alte servere. În API –ul Servlet există suport integrat pentru securitate. Acest lucru se datorează de fapt mediului Java standard care are un Security Manager ce poate controla accesul la toate resursele, cum ar fi fişierele locale, alte fire care rulează pe acelaşi server, informaţii administrative ale serverului (utilizatori, grupuri) sau accesul la alte servere din reţea. Prin acest mecanism se poate asigura un mediu de execuţie controlat (Sandbox) pentru servlet-uri similar cu cel folosit de navigatoarele Web pentru controlul applet-urilor. Administratorul serverului poate specifica deci, prin intermediul Security Manager-ului, cărui servlet să i se acorde drepturi de accesare a reţelei sau a fişierelor locale. Dacă luăm în considerare recent apărută posibilitate de a semna digital fişiere Java Archive (JAR), care conţin clase Java arhivate, am putea considera următoarea politică de securitate:
Din moment ce sunt instalate local de către administratorii serverului, servlet-urile locale au acces deplin la toate resursele.
Toate servlet-urile din reţea se execută în interiorul sandbox-ului. Servlet-urile care sunt semnate digital şi sunt pe o listă de semnături în care administratorul are încredere, au acces deplin la toate resursele. Servlet-urile semnate, dar care nu sunt pe listă, sunt considerate ca fiind fără semnătură.
Servlet-urile care nu sunt semnate digital se execută în sandbox şi nu au acces la nici o resursă
Binenţeles această soluţie poate fi extinsă, putînd fi adoptată o politică mai flexibilă. De exemplu pentru servlet-uri cu o anumită semnătură putem permite accesul doar la reţea sau la anumite fişiere.
Posibilitatea de înlănţuire – un servlet poate invoca unul sau mai multe servlet-uri într-o secvenţă.
Execuţia dinamică – poate fi apelat direct din paginile Web utilizînd tag-uri recunoscute de server.
Existenţa unui API (Interfeţe de proiectare a aplicaţiilor) standard – utilizează Servlet API, care este o extensie a API-ului standard Java; astfel un servlet este independent de protocolul de reţea utilizat, de modul în care este încărcat sau de serverul care-l rulează. Odată cu lansarea limbajului java, firma Sun a oferit programatorului şi un pachet complet de API-uri pentru principalele funcţii de care are nevoie o aplicaţie completă: interfaţă grafică, multithreading, operaţii matematice, comunicare în reţea, acces hardware,etc. Majoritatea acestor API-uri sunt complet implementate în Java, dar există şi o serie de API-uri direct legate de hardware, din această cauză ele fiind scrise în limbaje compatibile în cod nativ şi care trebuiau reimplementate pentru fiecare platformă. Totuşi în ultimii ani Sun a făcut eforturi foarte mari ca să poată oferi o nouă generaţie de API-uri care să dea aplicaţiilor Java posibilitatea de a accesa plăci de sunet, să comunice pe linii seriale, să acceseze cît mai mult dintre facilităţile plăcilor video, etc. În afară de aceste API-uri Sun a dezvoltat şi restul API-urilor standard şi a introdus altele noi , pentru a oferi proiectanţilor şi programatorilor Java cît mai multă funcţionalitate prefabricată. Facem în continuare o trecere în revistă acelor mai importante Api-uri oferite proiectanţilor de servlet-uri:
AWT (Abstract Window Toolkit) – a fost prima generaţie de API-uri destinate construcţiei de interfeţe grafice utilizator. Acest API a fost ulterior înlocuit cu un altul, mai elaborat, numit Swing , care de fapt este o rescriere a vechiului standard pe principii profund îmbunătăţite şi care oferă funcţionalităţile necesare unei interfeţe moderne. Din păcate Swing rămîne încă foarte lent şi de aceea se pot găsi încă foarte multe aplicaţii Java care continuă să folosească vechiul AWT;
specificaţia Java Beans - care a definit începînd cu JDK v1.1 modul în care pot fi create componentele software pentru mediile de dezvoltare Java şi cum se pot defini evenimente, metode şi proprietăţi ale acestora (vezi lucrarea [2]). În majoritatea cazurilor, când este realizată o aplicaţie, ceea ce se doreşte cu adevărat este obţinerea de componente care să îndeplinească anumite funcţii. În continuare, ar fi interesant ca aceste module să poată fi asamblate după o schemă, aşa cum un electronist montează chip-uri pe o placă (sau, în cazul Java, într-o pagină Web). Pentru a rezolva această problemă, a fost introdus conceptul de programare vizuală, în care componentele sunt prezentate grafic, într-o formă asemănătoare cu cea pe care o vor avea în program. Astfel, procesul de programare se transformă într-un proces de alegere de componente dintr-o paletă şi asamblarea lor utilizând un editor vizual. Sistemul de dezvoltare va genera cod pentru aceste componente şi astfel ele vor apărea în programul final.
Simpla punere împreună a componentelor nu este în mod normal suficientă pentru a obţine un program. Cel mai adesea, va fi nevoie ca anumite atribute ale componentei să poată fi schimbate (de exemplu, culoarea, textul afişat, baza de date la care trebuie să se conecteze etc.). Caracteristicile care pot fi modificate în momentul proiectării poartă numele de proprietăţi. Pe lângă acestea, o componentă are şi un set de comportamente, reprezentate prin evenimente (specifică modul în care trebuie să reacţioneze). Partea cea mai dificilă în realizarea unui mediu de programare vizuală îi revine uneltei de dezvoltare care trebuie să fie capabilă să interogheze dinamic o componentă pentru a afla proprietăţile şi evenimentele pe care le suportă (procedeul se numeşte introspecţie). Proprietăţile pot fi modificate (vor fi salvate la compilare), iar unui eveniment i se poate asocia o secvenţă de cod ce va fi executată când acesta se produce.
În această idee, au fost create medii de dezvoltare vizuale precum VisualBasic (VB) de la Microsoft, urmat de Delphi de la Borland (care a fost prima inspiraţie la proiectarea JavaBeans).
Pentru a crea o componentă VB, trebuie scris însă un cod destul de complicat, care urmează anumite convenţii pentru găsirea proprietăţilor şi evenimentelor. Delphi, care face parte din a doua generaţie de instrumente de programare vizuală, este proiectat pentru dezvoltarea vizuală uşurând procesul de manipulare al componentelor. Java reuşeşte să desăvârşească procesul de creare al componentelor vizuale prin JavaBeans.
JavaBeans este o facilitate introdusă de JDK 1.1, şi face posibilă scrierea de componente software reutilizabile (pe scurt beans), care pot fi manipulate vizual. Pentru a realiza un bean, nu trebuie scris cod suplimentar şi nu sunt necesare extensii speciale ale limbajului. De fapt, un bean (bob) este o clasă normală Java care foloseşte o convenţie de numire a metodelor. Pe baza numelui metodei, un editor vizual îşi poate da seama dacă are de-a face cu o proprietate, un eveniment sau o metodă normală. Crearea de servlet-uri care sunt în acelaşi timp şi bean-uri oferă două avantaje distincte:
• - orice modificare a configuraţiei servlet-ului este efectuată imediat;
• - persistenţa stării, precum şi configuraţia unui servlet de tip bean pot fi salvate într-un fişier prin serializare (de exemplu, în cazul unui contor, valoarea sa poate fi salvată şi apoi refăcută la oprirea şi, respectiv, pornirea server-ului prin folosirea mecanismului Java de serializare ).
Implicit, server-ul Java consideră orice servlet ca fiind bean şi-i iniţializează (prin introspecţie) toate proprietăţile primite ca argumente. De exemplu, un contor ar putea primi ca argument valoarea iniţială ("initial=0") sau un servlet cu numele "CGI" ar putea avea nevoie de directorul de start ("bindir=cgi-bin"). Servlet-urile de tip bean pot fi distribuite sub formă de clase sau/şi fişiere serializate ("nume_servlet.ser"). Un fişier serializat poate fi privit ca o instanţă a unei clase. Împreună cu clasa, el poate fi pus într-o arhivă de tip JAR (poartă numele de fişiere instalate) sau poate fi lăsat separat (neinstalat). În ambele cazuri, server-ul este responsabil cu încărcarea şi deserializarea servlet-urilor.
În continuare, urmează un exemplu de servlet bean HTTP care formează o pagină HTML ce conţine un mesaj (implicit este "Salut!"). Acest mesaj poate fi modificat-fără a recompila clasa-cu ajutorul utilitarului de administrare al server-ului Java sau prin trimiterea unui argument de iniţializare către servlet (printr-un fişier SayHi.initArgs, ce conţine o pereche parametru-valoare - de exemplu, "message=La revedere!").
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
Cuprins
Introducere 1
CGI (Common Gateway Interface) 2
Servlet-uri 6
Servlet-uri şi baze de date. JDBC - ODBC 16
Prezentarea aplicaţiei 25
Anexe 33
Anexa1. Arhitectura client-server 33
Anexa 2.Formulare HTML 34
Anexa 3. Script CGI - Perl (pentru accesarea şi actualizarea unei baze de date) 36
Bibliografie 41
Cuprins 42