Java i Internet programiranje

Size: px
Start display at page:

Download "Java i Internet programiranje"

Transcription

1 Univerzitet u Novom Sadu Fakultet tehničkih nauka Katedra za računarske nauke i informatiku Branko Milosavljević Milan Vidaković Java i Internet programiranje Materijal za predmet Sintetski praktikum iz računarstva Novi Sad, 2001.

2 Sadržaj 0. Namena i program kursa Potrebno predznanje Program kursa 2 1. Uvod u programski jezik Java Java virtuelna mašina Programski jezik Java Osnovni koncepti Tipovi podataka Klase i objekti Prevođenje i pokretanje programa Reference na objekte Operatori Kontrola toka programa Inicijalizacija objekata Uništavanje objekata Metode i njihovi parametri Ključna reč final Ključna reč static Nizovi Višedimenzionalni nizovi Paketi, CLASSPATH i JAR arhive Paketi CLASSPATH JAR arhive Podrazumevane komponente u CLASSPATH-u Zadatak: klasa Matrix Nasleđivanje Modifikatori pristupa Redefinisanje metoda Apstraktne klase Interfejsi Unutrašnje klase Polimorfizam 25

3 1.25 Izuzeci Klasa Object Klasa String Primeri nekih klasa iz standardne biblioteke Klasa java.util.vector Klasa java.util.hashtable Klasa java.util.stringtokenizer Konvencije davanja imena Generisanje programske dokumentacije i javadoc Zadaci: modifikacije klase Matrix Konkurentno programiranje u Javi Kreiranje programskih niti Daemon i non-daemon niti Primer programa sa više niti Sinhronizacija niti Dodatne metode za sinhronizaciju Primer programa sa sinhronizacijom niti Zadatak: problem pet filozofa GUI aplikacije i JavaBeans AWT i Swing Event-driven model Osnovna struktura GUI aplikacije Razlika u konstrukciji GUI-ja za Windows i Java aplikacije Dodavanje komponenti na prozor Prostorni raspored komponenti Rukovanje događajima Događaji, osluškivači i komponente Osluškivači kao unutrašnje klase Primeri korišćenja standardnih komponenti Apleti Pojam apleta Web čitači i Java Plug-In Apleti i komponente korisničkog interfejsa Aplet i aplikacija istovremeno Korisnički definisane komponente JavaBeans Mrežno programiranje u Javi Osnovne karakteristike Pojam socket-a Identifikacija čvorova mreže Klasa Socket Tipičan tok komunikacije klijent strana Klasa ServerSocket Tipičan tok komunikacije server strana Server koji opslužuje više klijenata Primer klijent/server komunikacije 70

4 4.9. Zadatak: klijent i server za listanje sadržaja direktorijuma Vežba: chat aplikacija Uvodna razmatranja Funkcije klijenta Funkcije servera Rad sa bazama podataka JDBC Osnovne odrednice JDBC drajveri Uspostavljanje veze sa bazom podataka Postavljanje upita DML operacije Uzastopno izvršavanje istih SQL naredbi Pozivanje uskladištenih procedura Upravljanje transakcijama Dodatak: inicijalizacija drajvera Uvod u višeslojne klijent/server sisteme Klasični klijent/server sistemi WWW i Java kao platforma za klijente Troslojni klijent/server sistemi Dinamičko generisanje HTML-a i servleti HTTP protokol Statički i dinamički Web sadržaji Servleti Metoda init Metoda destroy Metoda doget Primer: elementarni servlet Analiza zaglavlja HTTP zahteva Konkurentni pristup servletu Praćenje sesije korisnika Preuzimanje podataka sa HTML formi GET i POST zahtevi Pristup bazama podataka iz servleta Java Server Pages JSP koncept Vrste dinamičkih elemenata Izrazi Skriptleti Deklaracije Direktive Predefinisane promenljive Skladištenje podataka i JavaBeans Opseg vidljivosti JavaBean komponenti Definisanje sopstvenih tagova 121

5 10. Tehnologije distribuiranih objekata Osnovni koncepti RMI Faze u pisanju RMI programa RMI interfejs RMI serverski objekat RMI registry RMI klijent Primer RMI programa RMI i multithreading CORBA Osnovne odrednice IDL CORBA Naming Service Proces pisanja CORBA programa CORBA izuzeci Pozivi unatrag RMI i CORBA Enterprise JavaBeans Session Beans Entity Beans Komunikacija klijenata sa EJB komponentama Struktura EJB komponente Vežba: Web shop aplikacija Model podataka Struktura Web sajta Softverske komponente Dodatna razmatranja Rukovanje konekcijama sa bazom podataka 147 Literatura Prilozi...154

6 Poglavlje 0 Namena i program kursa Kurs Java i Internet programiranje ima za cilj upoznavanje polaznika sa programskim jezikom Java i arhitekturom višeslojnih Internet/intranet sistema i odgovarajućim Java tehnologijama za njihovu implementaciju. Nakon završenog kursa polaznici su osposobljeni da samostalno produbljuju znanja iz prikazanih oblasti i da učestvuju u razvoju softerskih sistema koji su predmet kursa. Kurs je predviđen za izvođenje u laboratorijskim uslovima, na odgovarajućoj računarskoj opremi. Materijal za kurs čine slajdovi koji se prikazuju u toku izlaganja, Web sajt koji sadrži primere prikazane tokom izlaganja, zadatke za vežbu, literaturu koja se preporučuje za detaljnije proučavanje materije i potreban softver koji je u javnom vlasništvu. Ovaj praktikum je, takođe, sastavni deo tog materijala. 0.1 Potrebno predznanje Za polaznike kursa je neophodno da poseduju znanja iz sledećih oblasti: objektno-orijentisano programiranje: poznavanje osnovnih pojmova i koncepata (klasa, objekat, apstrakcija, nasleđivanje, polimorfizam); konkurentno programiranje: pojmovi procesa i niti; raspoređivanje procesa, sinhronizacija procesa, nedeljive operacije; relacione baze podataka i SQL: poznavanje relacionog modela podataka, njegova implementacija u okviru sistema za upravljanje relacionim bazama podataka, upotreba jezika SQL za operacije nad bazom podataka; HTML: osnovni elementi strukture HTML dokumenata, rukovanje Web čitačima; Za polaznike je poželjno, ali ne i obavezno, poznavanje jezika C++. Polaznici koji poznaju ovaj jezik mogu daleko brže usvajati materiju koja se izlaže na početku kursa. 0.2 Program kursa Kurs se sastoji iz više tema koje obuhvataju obradu nove materije i vežbanja. U ovom odeljku dat je sažet pregled sadržaja kursa po odgovarajućim temama. 1

7 U prvom poglavlju, Uvod u programski jezik Java, govori se o osnovnim karakteristikama Jave, kao programskog jezika, i kao platforme za izvršavanje programa. Upoznaje se koncept Java virtuelne mašine (JVM) i prenosivosti prevedenog Java koda. Zatim se vrši pregled osobina Jave kao programskog jezika, i obrađuju se jezičke konstrukcije. Drugo poglavlje nosi naziv Konkurentno programiranje u Javi i donosi pregled jezičkih koncepata koji omogućavaju pisanje konkurentnih programa. Treće poglavlje, GUI aplikacije i JavaBeans, predstavlja sažeti prikaz pisanja aplikacija i apleta sa grafičkim korisničkim interfejsom. Definiše se struktura ovakvih aplikacija, način reagovanja na događaje koje izaziva korisnik i navode primeri korišćenja brojnih komponenti za izgradnju korisničkog interfejsa. Četvrto poglavlje, Mrežno programiranje u Javi, definiše pojmove koji se koriste prilikom pisanja programa koji komuniciraju preko mreže, a zatim opisuje elemente jezika koji se koriste za pisanje ovakvih programa. Podrazumeva se rad preko TCP/IP mreže. Peto poglavlje sadrži vežbu, čiji je cilj konstrukcija mrežne klijent/server aplikacije za chat preko TCP/IP mreže. Konstrukcija ovakvog sistema obuhvata sve prethodno obrađene teme. U šestom poglavlju Rad sa bazama podataka JDBC dat je uvod u metode pristupa i korišćenja relacionih baza podataka iz Java programa. Podrazumeva se korišćenje sistema za upravljanje relacionim bazama podataka sa kojima se komunicira preko jezika SQL. Sedmo poglavlje, Uvod u višeslojne klijent/server sisteme, definiše okvire u kojima se nalazi materija izložena u narednim poglavljima. Osmo poglavlje Dinamičko generisanje HTML-a i servleti prikazuje servlete, osnovnu Java tehnologiju za dinamičko generisanje Web sadržaja i izgradnju Web sajtova. U narednom poglavlju, Java Server Pages, predstavljena je tehnologija za pisanje dinamičkih Web stranica koja omogućava razdvajanje zadataka Web dizajnera i programera, pojednostavljujući tako razvoj Web-orijentisanih informacionih sistema. Deseto poglavlje, Tehnologije distribuiranih objekata, donosi sažet prikaz tehnologija namenjenih za pisanje distribuiranih objektno-orijentisanih aplikacija dostupnih iz programskog jezika Java. Poslednje poglavlje sadrži vežbu čiji je cilj konstrukcija Web aplikacije za elektronsko poslovanje. Zadatak je napisati softver za Web sajt koji omogućava kupovinu putem Web-a. 2

8 Poglavlje 1 Uvod u programski jezik Java 1.1 Java virtuelna mašina Specifikacija Jave obuhvata dve relativno nezavisne celine: specifikaciju programskog jezika Java i specifikaciju Java virtuelne mašine (JVM). Specifikacija programskog jezika Java se ne razlikuje mnogo od sličnih specifikacija za druge jezike slične namene. Međutim, JVM specifikacija predstavlja novinu u odnosu na druge raširene objektno-orijentisane programske jezike opšte namene. Naime, JVM specifikacija predstavlja, zapravo, specifikaciju platforme za izvršavanje Java programa u čijoj osnovi se nalazi programski model izmišljenog procesora. Programi napisani u programskom jeziku Java se prevode za ovakvu platformu za izvršavanje. Samim tim, prevedeni programi se ne mogu pokretati direktno na nekoj konkretnoj računarskoj platformi; potreban je poseban softver koji će takav prevedeni program da prilagodi konkretnoj mašini i operativnom sistemu. Zapravo, potreban je odgovarajući interpreter. Kompanija koja je vlasnik jezika Java, Sun Microsystems, je stavila u javno vlasništvo JVM interpreter, kompajler i skup drugih razvojnih alata grupisanih u paket pod nazivom Java Development Kit (JDK). U pitanju su alati koji se pokreću iz komandne linije i nude samo osnovni set funkcija za razvoj softvera. Sun je izdao JDK paket za nekoliko različitih platformi: Windows, Solaris/ SPARC, Solaris/Intel i Linux/Intel. Kako je Java specifikacija (i sam jezik i JVM) javno dostupna, drugi proizvođači su proizveli svoje implementacije Jave za različite platforme. Na primer, IBM nudi svoje verzije implementacije za većinu svojih hardversko/softverskih platformi, ali i za Linux na Intel mašinama. Iako se najčešće programski jezik Java i Java virtuelna mašina pominju u paru, kao dve komplementarne specifikacije, nema prepreka da se Java kod prevodi i za izvršavanje na nekoj drugoj platformi (na primer, TowerJ paket generiše Windows izvršni kod). Takođe, nema prepreka da se neki drugi jezici prevode za izvršavanje u okviru Java virtuelne mašine. 3

9 Kao posledica prethodno rečenog, može se reći da je Java kombinacija programskog jezika i platforme za izvršavanje programa koja ima nekoliko važnih osobina: Projektovana je tako da što manje zavisi od karakteristika konkretnog računarskog sistema na kome se izvršava. Jednom napisan i preveden program se može pokretati na bilo kojoj platformi za koju postoji odgovarajući JVM interpreter. Dakle, prenosivost programa je garantovana na nivou izvršnog (prevedenog) koda. Java je interpretirani jezik, što ima odgovarajući efekat na brzinu izvršavanja programa. Proizvod prevođenja izvornog Java koda je program predviđen za rad u okviru JVM, koji se često naziva bajt-kod (byte-code). 1.2 Programski jezik Java Iako je Java virtuelna mašina sastavni deo specifikacije, o njoj se govori veoma retko; praktično je koriste samo autori kompajlera i JVM interpretera iza konkretne računarske platforme. Sa druge strane, većina Java programera govori o drugom delu Java specifikacije, samom programskom jeziku Java, koji je i tema preostalog teksta u ovom poglavlju. Može se reći da je Java objektno-orijentisani programski jezik opšte namene, posebno pogodan za pisanje konkurentnih, mrežnih i distribuiranih programa. Sva referentna dokumentacija za Javu nalazi se na jednom mestu sajtu firme JavaSoft (ogranak firme Sun Microsystems) Knjiga Thinking in Java, (autor Bruce Eckel) se smatra za jednu od najboljih knjiga o samom jeziku, a dostupna je osim u klasičnoj štampanoj formi i u elektronskom obliku koji je besplatan na Osnovni koncepti Sintaksa Jave izuzetno podseća na sintaksu jezika C++, mada nije jednaka njoj. Sintaksna pravila neće biti posebno obrađena, jer smatramo da su dovoljno očigledna iz primera koji slede Tipovi podataka Java operiše sa dve vrste tipova podataka: primitivnim tipovima i objektima. Primitivni tipovi su tipovi koji se sreću i u drugim jezicima, npr. celobrojni tip, karakter, itd. Tabela 1.1 sadrži spisak svih primitivnih tipova sa njihovim osnovnim karakteristikama. Primitivni tip Veličina Minimum Maksimum boolean 1-bit - - char 16-bit Unicode 0 Unicode byte 8-bit short 16-bit int 32-bit long 64-bit

10 Primitivni tip Veličina Minimum Maksimum float 32-bit IEEE 754 IEEE 754 double 64-bit IEEE 754 IEEE 754 void Tabela 1.1. Primitivni tipovi Iz tabele se vidi da Java raspolaže primitivnim tipovima koji su na isti način definisani i u drugim programskim jezicima. Jedini izuzetak je tip char, koji zauzima dva bajta, umesto uobičajenog jednog bajta. Radi se o tome da se tipom char može predstaviti svaki karakter definisan Unicode standardom koji definiše kodni raspored koji obuhvata praktično sve današnje jezike (uključujući indoevropske, dalekoistočne, itd). To znači da su Java programi u startu osposobljeni da rade sa višejezičnim tekstom, ili u našim uslovima, ravnopravno sa srpskom latinicom i srpskom ćirilicom. Treba primetiti da string, kao često korišćen tip podatka, nema odgovarajući primitivni tip u Javi, slično jezicima C i C Klase i objekti Druga vrsta podataka sa kojima operiše Java program su objekti. Objekti predstavljaju osnovni koncept objektno-orijentisane paradigme u modelovanju sistema. Svaki objekat realnog sistema koga posmatramo predstavljamo odgovarajućim objektom koji je sastavni deo modela sistema. Objekte koji zajedničke osobine (ne moraju imati iste vrednosti tih osobina) možemo da opišemo klasom. U tom smislu, objekat je jedna instanca (primerak) svoje klase. Klasa, dakle, predstavlja model objekta, koji obuhvata atribute i metode. Sledi primer jedne Java klase: class Automobil { boolean radi; void upali() { radi = true; void ugasi() { radi = false; (Plavom bojom su navedene ključne reči jezika). Klasa ima naziv Automobil, definiše jedan atribut koji se zove radi i logičkog je tipa (boolean), i definiše dve metode koje se mogu pozvati nad objektima te klase, metode upali i ugasi. Kreiranje objekata koji predstavljaju instance (primerke) ove klase može se obaviti na sledeći način: Automobil a = new Automobil(); Automobil b = new Automobil(); Time su kreirana dva objekta klase Automobil, koji su nazvani a i b. Atributu radi objekta a može se pristupiti pomoću: a.radi 5

11 a poziv metoda upali i ugasi mogao bi da izgleda kao u sledećem primeru: a.upali(); b.ugasi(); Ovo do sada rečeno izuzetno podseća na C++. Neke od osobina Jave koje je bitno razlikuju u odnosu na C++ su: Nije moguće definisati promenljive i funkcije izvan neke klase. Samim tim, nije moguće definisati globalne promenljive, niti globalne funkcije ili procedure. Ne postoje odvojene deklaracija i definicija klase. Java poznaje samo definiciju klase. Prema tome, ne postoje posebni header fajlovi koji sadrže deklaraciju klase. Kako Java ne dopušta postojanje bilo čega što bi postojalo izvan neke klase, postavlja se pitanje odakle počinje izvršavanje Java programa. C i C++ koriste funkciju main kao osnovnu funkciju od koje počinje izvršavanje programa. Java takođe koristi funkciju main, samo što i ta funkcija mora biti metoda neke klase (u C++ terminologiji bi se reklo funkcija članica ). Izgled jedne klase koja sadrži metodu main, i predstavlja primer jednog izvršivog Java programa dat je u sledećem primeru: class Hello { public static void main(string args[]) { System.out.println( Hello world! ); (Trenutno nije bitno zašto metoda main mora biti definisana kao public static void, ali mora biti tako.) Kompletan tekst ove klase smešten je u datoteku Hello.java. Treba obratiti pažnju na naziv ove datoteke: njena ekstenzija je obavezno.java, a ime mora biti jednako imenu klase, uključujući i razliku između velikih i malih slova. Standardna preporuka je da se svaka klasa programa smešta u posebnu datoteku. Naziv datoteke mora odgovarati nazivu klase na prethodno opisani način. Iako će neki prevodioci dopustiti smeštanje teksta više klasa u isti fajl, ta praksa se ne preporučuje. Dakle, svakoj Java klasi odgovara jedan fajl sa identičnim nazivom i ekstenzijom.java. 1.5 Prevođenje i pokretanje programa Svaka Java klasa se može prevesti nezavisno od ostalih elemenata programa. Komanda kojom se klasa Hello iz prethodnog primera prevodi je javac Hello.java (Primeri za prevođenje i pokretanje opisuju korišćenje alata iz standardnog JDK paketa). Dakle, kompajler se poziva komandom javac, a kao parametri navode se imena onih datoteka koje želimo da prevedemo (može ih biti više, i možemo da koristimo džoker-znake). Treba obratiti pažnju na to da je navođenje ekstenzije datoteke obavezno, iako je ekstenzija uvek.java. 6

12 Prevođenjem datoteke Hello.java dobija se datoteka Hello.class, koja sadrži JVM bajt-kod koji pripada klasi Hello. Naziv te datoteke obavezno mora imati ekstenziju.class, i naziv mora biti jednak nazivu klase. Svaka klasa, data u odgovarajućem.java fajlu, kao rezultat prevođenja daje odgovarajući.class fajl. Treba obratiti pažnju da je kod prevođenja ovog primera neophodno pozicionirati se (u okviru DOS Prompt-a ili nekog shell-a na UNIX-u) u onaj direktorijum gde se nalazi.java fajl. Za pokretanje ovog programa dovoljan je dobijeni Hello.class fajl. Program ćemo pozvati iz komandne linije (ponovo se moramo nalaziti u istom direktorijumu gde i.class fajl) sledećom komandom: java Hello Ovog puta nije dozvoljeno navođenje ekstenzije.class prilikom pokretanja. U slučaju da se tako učini dobićemo poruku o grešci. Sada sledi primer jednog programa koji se sastoji iz dve klase: Automobil.java class Automobil { boolean radi; void upali() { radi = true; void ugasi() { radi = false; Test.java class Test { public static void main(string args[]) { Automobil a; a = new Automobil(); a.upali(); Ove dve klase su smeštene u odgovarajućim datotekama Automobil.java i Test.java. Njihovim prevođenjem dobijaju se dva.class fajla, Automobil.class i Test.class. Program se pokreće tako što se navodi ime one klase koja sadrži metodu main, što bi u ovom primeru bilo java Test Nema nikakve prepreke da više klasa koje čine program poseduju metodu main. Odakle će se početi sa izvršavanjem programa? To se određuje prilikom pokretanja programa, tako što se navodi ime one klase čiju metodu main želimo da pokrenemo. 1.6 Reference na objekte Kada smo u prethodnom primeru, u metodi main, napisali: Automobil a; a = new Automobil(); deklarisali smo promenljivu a tipa Automobil, a zatim kreirali objekat klase Automobil i vezali ga za tu promenljivu a. 7

13 Promenljiva a predstavlja, zapravo, referencu na objekat klase Automobil. Promenljiva a je lokalna promenljiva u metodi main, tako da se smešta na stek, na sličan način kako se to odvija u drugim jezicima, dok se memorija za objekat klase Automobil zauzima na heap-u programa. Slika 1.1 prikazuje tu situaciju. objekat klase Automobil a stek heap Slika 1.1. Referenca koja ukazuje na objekat U tom smislu kaže se da je a referenca na objekat klase Automobil. Promenljiva a nije pointer u smislu kako ga definiše C++, jer nije dopuštena nikakva aritmetika sa ovakvim promenljivama, niti dodeljivanje proizvoljnih vrednosti. Jedina vrednost koju referenca može da sadrži je adresa (namerno je pod navodnicima jer to nije prava adresa u memoriji) pravilno inicijalizovanog objekta na koga ukazuje. Sledeći primer prikazuje kreiranje dva objekta klase Automobil i inicijalizaciju referenci tako da ukazuju na odgovarajuće objekte. Reference se nalaze na steku programa, dok su objekti smešteni na heap. Automobil a = new Automobil(); Automobil b = new Automobil(); Situacija koja se nakon ovoga nalazi u memoriji je prikazana na slici 1.2. objekat klase Automobil b objekat klase Automobil a stek heap Slika 1.2. Dve refence koje ukazuju na dva objekta Ako se sada izvrši naredba b = a; u memoriji će biti sledeća situacija (slika 1.3). 8

14 objekat klase Automobil b objekat klase Automobil a stek heap Slika 1.3. Situacija nakon kopiranja referenci Postavlja se pitanje šta se u ovoj situaciji dešava sa objektom na koga je ukazivala referenca b: taj objekat više nije dostupan ni na jedan način, jer je jedina mogućnost da se nekoj referenci dodeli vrednost dodela vrednosti postojeće reference (tipa b = a) ili dodela vrednosti reference na novokreiran objekat (tipa a = new...). Kako objekat više nije dostupan, valjalo bi ga ukloniti iz memorije kako bi se izbeglo curenje memorije. Java ne poseduje posebnu jezičku konstrukciju kojom se memorija dealocira (poput operatora delete u jeziku C++). Za dealokaciju memorije zadužen je poseban pozadinski proces programa koji se naziva garbage collector ( skupljač đubreta ). O garbage collector-u će biti više reči u odeljku Operatori Operatori koji služe za gradnju Java izraza su operatori koji su, praktično, preuzeti iz jezika C++. Možemo ih grupisati u nekoliko grupa: aritmetički operatori (+, -, *, /) relacioni operatori (==, <, >, =,!=, >=, <=) logički operatori (&&,,!) bit-operatori (&,,!) operator dodele (=) Bitna razlika u odnosu na C++ je postojanje primitivnog tipa boolean; vrednost logičkih izraza mora biti ovog tipa. To znači da su vrednosti u if ili while konstrukcijama logičkog tipa, pa nije moguće pisati while (1) ili, još opasnije if (a = 1) Prioritet operatora je definisan na standardan način. Detaljna specifikacija operatora data je u specifikaciji jezika. 1.8 Kontrola toka programa Za kontrolu toka programa na raspolaganju su standardne konstrukcije, preuzete iz jezika C++. Treba primetiti da postoje izvesne razlike između Jave i jezika C++ i u ovom slučaju, pa za detaljnije informacije treba konsultovati specifikaciju jezika. Dostupne konstrukcije su sledeće: 9

15 if... else switch for while do... while break continue 1.9 Inicijalizacija objekata Prilikom konstruisanja novog objekta, nakon alokacije potrebne memorije za smeštaj objekta, biće pozvana specijalna metoda namenjena za inicijalizaciju objekta nazvana konstruktor. Konstruktor obavezno ima naziv jednak nazivu klase, i nema nikakav povratni tip, čak ni void. Sledi primer klase koja ima konstruktor. class A { A() { System.out.println("konstruktor"); U ovom primeru, konstruktor će biti pozvan prilikom kreiranja objekta klase A. Na primer: A vara = new A(); je deklaracija reference vara koja ukazuje na objekat klase A, pri čemu se odmah vrši i inicijalizacija ove reference na novokreirani objekat. U trenutku kada se izvrši ovaj red (zapravo kreiranje objekta pomoću new A()), na konzoli će se ispisati konstruktor što je rezultat izvršavanja konstruktora. Ukoliko se unutar definicije klase ne navede nijedan konstruktor, kompajler će sam generisati tzv. podrazumevani konstruktor koji nema parametre i telo mu je prazno Uništavanje objekata U odeljku 1.6 već je bilo reči o problemu uklanjanja nedostupnih objekata iz memorije. Za taj posao zadužen je poseban pozadinski proces koji se naziva garbage collector (GC). Ovaj proces radi nezavisno od pokrenutog programa, u smislu da sam odlučuje u kom trenutku će iz memorije osloboditi koji nedostupni objekat. Pored automatske dealokacije memorije, GC je zadužen i za automatsku defragmentaciju memorije. Za razliku od jezika C++, Java klase ne mogu imati destruktore. Destruktori su specijalne metode koje se pozivaju neposredno pre uklanjanja objekta iz memorije. Svu potrebnu dealokaciju memorije u Javi obavlja GC proces. U trenutku dealokacije podrazumeva se da je Java objekat oslobodio ostale resurse koje je koristio (otvorene datoteke, mrežne konekcije, itd). Ukoliko je 10

16 neophodno obaviti neku operaciju neposredno pre nego što GC uništi objekat, ta operacija se može implementirati u okviru specijalne metode finalize. Metoda finalize se poziva neposredno pre uništavanja objekta od strane GC-a. Ovde je važno naglasiti da metodu finalize ne treba koristiti za oslobađanje zauzetih resursa, jer se metoda finalize ne mora pozvati! Naime, GC sam određuje kada će ukloniti objekat iz memorije, i lako se može desiti da se to nikad ne dogodi: program je pokrenut, radio je neko vreme, računar raspolaže sa dovoljno radne memorije tako da GC nije počeo sa uklanjanjem objekata, i tako sve do završetka rada programa; GC nije uklonio objekat, samim tim nije pozvao metodu finalize, i eventualno oslobađanje zauzetih resursa se nije ni desilo. Sledi primer klase koja implementira metodu finalize (pokretanjem ovog programa sa java A verovatno će se demonstrirati mogućnost da se GC nikad ne aktivira): class A { A() { System.out.println("Konstruktor"); protected void finalize() throws Throwable { System.out.println("finalized"); public static void main(string[] args) { A a = new A(); System.out.println("main running..."); 1.11 Metode i njihovi parametri Sintaksa definisanja metoda (u smislu navođenja njihovog imena, liste parametara i tipa rezultata) je nalik sintaksi u jeziku C++. Sledi primer jedne metode koja prima tri parametra, sa tipovima String, int i boolean, a vraća vrednost tipa void (tj. ne vraća rezultat). void metoda(string name, int value, boolean test) {... Parametri metode mogu biti primitivni tipovi i reference na objekte; tip rezultata metode može biti primitivni tip ili referenca na objekat. Često se postavlja se pitanje da li promena vrednosti parametra u okviru metode ima efekta na promenljivu koja je korišćena kao parametar nakon povratka iz metode. Posmatrajmo sledeću metodu: void test(automobil a) { a.radi = true; U pitanju je metoda koja u okviru svog tela vrši modifikaciju svog parametra a preko metode upali. (Koristi se klasa Automobil definisana u prethodnim primerima). U slučaju da se ova metoda pozove u sledećem segmentu koda: Automobil x = new Automobil(); 11

17 x.radi = false; test(x); // da li je atribut radi ovde true ili false? vrednost atributa radi objekta x biće true. Slika 1.4 ilustruje šta se zapravo desilo: na steku je kreirana referenca x na objekat klase Automobil. Zatim je vrednost atributa radi ovog objekta postavljena na false (slika a). Nakon toga pozvana je metoda test, sa referencom x kao parametrom. Parametri metoda se, slično kao i u drugim programskim jezicima, smeštaju na stek prilikom poziva metode (ovde je nebitno u kom redosledu). Tako je i referenca x iskopirana na stek još jednom (slika b). U okviru tela metode test ova druga kopija reference x se koristi kao parametar metode i preko nje se pristupa istom onom objektu na koji ukazuje i originalna referenca x. Pristup objektu se u ovom slučaju svodi na promenu vrednosti atributa radi na true (slika c). Kod vraćanja iz metode nazad, sa steka se uklanjaju parametri korišćeni prilikom poziva metode. Tako se sa steka uklanja druga kopija reference x i ostaje samo originalna referenca. Kada preko nje pristupimo atributu radi, videćemo da je on promenio vrednost (slika d). radi: false radi: false x x x a) b) radi: true radi: true x x c) x d) Slika 1.4. Promena stanja objekta koji je parametar metode Nakon ovog primera može se zaključiti sledeće: promene nad parametrima metode načinjene u okviru tela metode koji su reference na objekte su vidljive nakon povratka iz metode. Ili, kako se to sreće u drugim programskim jezicima, efekat je isti kao kod prenosa parametara po adresi. Sa primitivnim tipovima stvari stoje upravo suprotno: oni se, kao parametri metoda ponašaju kao kod prenosa parametara po vrednosti. Sledi primer: void test(int a) { a = 1;... int a = 0; test(a); // koliko je ovde vrednost a? Slika 1.5 prikazuje šta se dešava u ovom slučaju: deklariše se promenljiva a tipa int i odmah se inicijalizuje na vrednost 0. Lokalne promenljive primitivnog 12

18 tipa se smeštaju na stek (trenutno stanje ilustruje slika a). Zatim se poziva metoda test sa parametrom a; parametar a se smešta na stek (zapravo, njegova vrednost se kopira još jednom slika b). U okviru metode vrednost parametra se menja u 1, pri čemu se menja druga kopija na steku (slika c). Nakon povratka iz metode, parametar se uklanja sa steka i na steku ostaje originalna vrednost promenljive a koja nije menjana (slika d). a = 0 a = 0 a = 0 a) b) a = 1 a = 0 c) a = 0 d) Slika 1.5. Promena vrednosti parametra metode koji je primitivnog tipa Preklapanje metoda (method overloading) je u Javi dopušteno. Preklopljene metode su metode koje imaju isto ime, ali se razlikuju po listi parametara. Kompajler ih smatra za sasvim različite metode, bez obzira što imaju isto ime. Metode ne mogu da se razlikuju samo po tipu rezultata kojeg vraćaju. Sledi primer klase sa tri preklopljene metode: class A { int metoda() {... int metoda(int i) {... int metoda(string s) {... Preklapanje metoda se odnosi kako na klasične metode, tako i na konstruktore Ključna reč final Ključna reč final se može naći ispred definicije atributa ili metode unutar definicije klase. Ako se nađe ispred atributa, označava atribut kome nije moguće promeniti vrednost. Drugim rečima, final atribut predstavlja konstantu. Inicijalizacija prilikom deklaracije atributa je obavezna. Primer definicije jednog final atributa bio bi: final int size = 100; Ključna reč final ima drugo značenje kod metoda: označava metode koje se ne mogu redefinisati prilikom nasleđivanja date klase. O nasleđivanju će više biti reči u odeljku 1.18, a o redefinsanju metoda u odeljku Primer jedne final metode glasi: final int metoda(int i) {... 13

19 1.13 Ključna reč static Ključna reč static se može naći ispred definicije atributa ili metode, nezavisno od pojave ključne reči final. Kada se nađe ispred definicije atributa, označava atribut koji pripada klasi, a ne objektima (kao instancama klase). Drugim rečima, može se reći da svi objekti date klase dele istu vrednost statičkog atributa. Na primer, klasa StaticTest poseduje jedan statički atribut: class StaticTest { static int i = 0; static void metoda() { i++; Tada će sledeći programski segment izazvati promenu vrednosti atributa i u oba objekta: StaticTest a = new StaticTest(); StaticTest b = new StaticTest(); a.i++; // ovde je a.i == b.i == 1 Statički atribut je pridružen klasi, a ne njenim instancama. U tom smislu, može mu se pristupiti i kada nije kreiran nijedna instanca klase. Tada se atributu pristupa tako što se navodi ime klase, pa zatim ime atributa, kao u sledećem primeru: StaticTest.i++; Statičke metode su metode koje ne mogu biti pozvane nad objektimainstancama klase, već nad klasom samom. U tom smislu, nije moguće pisati nego samo a.metoda(); StaticTest.metoda(); Statičke metode imaju pristup samo statičkim atributima klase. Često korišćeni primer upotrebe statičkog atributa je ispisivanje na konzolu: System.out.println("Hello, world!"); pri čemu se poziva metoda println objekta out koji je statički atribut klase System (out zapravo predstavlja standardni izlaz, slično kao stdout u jeziku C) Nizovi Nizovi se u Javi definišu vrlo slično kao u jeziku C++. Na primer, niz čiji su elementi tipa int se definiše na sledeći način: int[] a; ili int a[]; Ovim je samo definisana referenca na niz; niz se nakon toga mora kreirati na način sličan kreiranju objekata. Sledi primer gde se alocira niz od pet int elemenata: a = new int[5]; 14

20 Prvi element niza ima indeks nula. Postoji i način da se niz definiše, alocira memorija za njega i odmah inicijalizuje, kao u sledećem primeru: int[] a = { 1, 2, 3, 4, 5 ; Treba voditi računa o tome da se prilikom definicije niza referenca na niz čuva na steku, dok se elementi niza čuvaju na heap-u, slično kao i objekti. Slika 1.6 ilustruje ovu situaciju za niz definisan u prethodnom primeru a heap Slika 1.6. Inicijalizovan niz Kada je u pitanju niz čiji su elementi primitivnog tipa, alokacija memorije za elemente niza se odvija automatski. To nije slučaj kada je u pitanju niz čiji su elementi objekti neke klase. Na primer, niz od 5 elemenata klase Automobil se definiše kao na primer: Automobil[] parking = new Automobil[5]; Ovim je zapravo definisan niz čiji elementi su reference na objekte klase Automobil. Slika 1.7 ilustruje ovu situaciju. parking heap Slika 1.7. Niz objekata pri čemu objekti nisu inicijalizovani Ovakav niz referenci na objekte se može inicijalizovati, recimo, u odgovarajućoj for petlji, kao u primeru: for (int i = 0; i < parking.length; i++) parking[i] = new Automobil(); (Svaki niz ima definisan atribut length koji predstavlja dužinu alociranog niza). Sada će stanje u memoriji izgledati kao na slici 1.8. parking a1 a2 a3 a4 a5 heap Slika 1.8. Niz inicijalizovanih objekata 1.15 Višedimenzionalni nizovi Višedimenzionalni nizovi se predstavljaju kao nizovi nizova. Sintaksa je slična jeziku C++. Na primer, definicija 15

21 int[][] a = { {1, 2, 3, {4, 5, 6 ; će kreirati niz od dva elementa koji su reference na nizove od tri elementa tipa int. Stanje u memoriji će nakon kreiranja ovakvog niza izgledati kao na slici a heap Slika 1.9. Dvodimenzionalni niz Višedimenzionalni niz se može kreirati na sledeći način: int[][] a = new int[2][3]; pri čemu će se izvršiti potrebna alokacija memorije, ali ne i inicijalizacija vrednosti elemenata niza. Dvodimenzionalni niz se može kreirati i postupno, kao u sledećem primeru: int[][] a = new int[2][]; for (int i = 0; i < a.length; i++) a[i] = new int[3]; Prilikom kreiranja višedimenzionalnog niza čiji su elementi objekti, a ne primitivnog tipa, potrebno je još izvršiti i dodatno kreiranje svakog od objekata. Na primer: Automobil[][] parking = new Automobil[2][]; for (int i = 0; i < parking.length; i++) { parking[i] = new Automobil[3]; for (int j = 0; j < parking[i].length; i++) parking[i][j] = new Automobil(); Stanje u memoriji nakon kreiranja ovakvog niza izgledaće kao na slici a4 a5 a6 parking a1 a2 a3 heap Slika 1.10 Višedimenzionalni niz čiji elementi su objekti Višedimenzionalni niz objekata može se inicijalizovati odmah prilikom definicije, slično kao kod višedimenzionalnog niza primitivnih tipova. Sledi primer: Automobil[][] a = { { new Automobil(), new Automobil(), { new Automobil(), new Automobil() ; 16

22 1.16 Paketi, CLASSPATH i JAR arhive Paketi Java programi se sastoje isključivo iz klasa. Broj klasa koje čine program može biti relativno velik, pa je uvođenje nekakve organizacije u takav skup klasa neophodno. Paketi su način da se klase grupišu po nekom kriterijumu. Paketi mogu da sadrže klase ili potpakete, analogno odnosu direktorijuma i datoteka u okviru fajl-sistema. Svaka klasa mora da pripada nekom paketu. Ako se ne navede kom paketu pripada data klasa, podrazumeva se da pripada tzv. korenskom ili implicitnom paketu. Taj korenski paket nema posebno ime. On može da sadrži klase i potpakete, koji sa svoje strane takođe mogu da sadrže klase i potpakete. Slika 1.11 prikazuje strukturu paketa nekog programa. Slika 1.11 Struktura paketa u programu Paketi i klase su u okviru fajl-sistema zaista i organizovani kao direktorijumi i datoteke: paketi su predstavljeni direktorijumima, a klase se nalaze u odgovarajućim datotekama. Klasa koja se nalazi u nekom paketu (osim korenskog), mora u okviru svoje datoteke imati odgovarajuću deklaraciju, kao u sledećem primeru: package paket1; class Automobil {... Deklaracija package se mora nalaziti na samom početku teksta datoteke, tj. nijedna druga deklaracija se ne sme nalaziti ispred nje. Datoteka Automobil.java mora biti smeštena u direktorijum paket1 koji se nalazi u korenskom direktorijumu aplikacije. Naziv korenskog direktorijuma nije važan, niti je važno gde se on nalazi u okviru fajl-sistema. Prevođenje klase Automobil se mora obaviti komandom: Važno je primetiti da se komanda za prevođenje poziva iz korenskog direktorijuma projekta i da se kao parametar navodi ime.java datoteke, zajedno sa relativnom putanjom do nje. Analogno tome, klasa Tocak koja se nalazi u paketu paket3 gornjeg primera, prevela bi se komandom: Tekst klase Tocak obavezno mora početi odgovarajućom deklaracijom: package paket2.paket3; class Tocak {... 17

23 Vidimo da se za separaciju imena paketa u okviru Java programa koristi tačka, a ne kosa crta ili obrnuta kosa crta. Već je rečeno da se prilikom pokretanja programa navodi ime one klase koja sadrži metodu main. Prilikom navođenja imena ove klase mora se navesti njeno puno ime, uključujući i paket u kome se klasa nalazi. Na primer, ukoliko klasa Tocak poseduje metodu main, i želimo da odatle počne izvršavanje programa, program moramo pokrenuti pomoću sledeće komande: Dakle, ponovo je važno sa kog mesta se poziva Java interpreter: to mora biti korenski direktorijum aplikacije. Svaka prevedena klasa se u okviru aplikacije vidi u okviru paketa čija je putanja jednaka relativnoj putanji do odgovarajućeg direktorijuma. Separator naziva paketa je, kao što je već rečeno, tačka, a ne kosa crta ili obrnuta kosa crta. Programski jezik Java stiže sa velikim brojem klasa grupisanim u pakete. Te klase su dostupne kao i klase koje sami pišemo (čak se može dobiti i njihov izvorni kod). Recimo klasa Vector koja se nalazi u paketu java.util je u programima dostupna kao java.util.vector. Kako bi svako pominjanje ove klase u tekstu programa zahtevalo navođenje pune putanje do nje (odnosno navođenje odgovarajućeg paketa), to bi program učinilo manje čitljivim. Zato je moguće na početku teksta klase deklarisati da se koristi ta-i-ta klasa koja se nalazi u tom-i-tom paketu. Na primer: package paket1; import java.util.vector; class Automobil {... Nadalje se u tekstu klase Automobil klasa Vector koristi samo navođenjem njenog imena, bez imena paketa u kome se nalazi. Treba obratiti pažnju na to da se import deklaracija mora nalaziti između (opcione) package deklaracije i definicije klase. Ukoliko koristimo više klasa iz istog paketa, moramo svaku od njih navesti u odgovarajućoj import deklaraciji. Drugi način je da se importuju sve klase iz datog paketa pomoću džoker-znaka *: package paket1; import java.util.*; class Automobil {... Ovakav način importovanja ne obuhvata i sve potpakete importovanog paketa! Niti je dozvoljeno korišćenje džoker znakova kao u primeru: import java.util.vec*; // nije dozvoljeno! Klase koje se nalaze u paketu java.lang nije potrebno importovati. Odgovarajuća import deklaracija se podrazumeva. 18

24 CLASSPATH S obzirom na do sada izloženo, korišćenje klase Vector iz paketa java.util bi značilo da se odgovarajuće stablo direktorijuma java\util\... koje sadrži kompajlirane klase mora kopirati unutar strukture direktorijuma svake aplikacije koju pišemo. Time se bespotrebno zauzima prostor i komplikuje održavanje softvera. Zato postoji način da se paketi sa klasama koji se koriste iz više aplikacija čuvaju na jednom mestu, a sve aplikacije će pomoću odgovarajućeg mehanizma te klase videti kao da je struktura direktorijuma iskopirana u okviru svake aplikacije. U pitanju je mehanizam sličan korišćenju PATH promenljive okruženja (environment variable). Java interpreter za ovu svrhu koristi promenljivu okruženja koja se naziva CLASSPATH. Ona sadrži listu direktorijuma u kojima treba tražiti klase koje se koriste. Na primer, ukoliko je cela java\... hijerarhija paketa smeštena u direktorijum C:\java\lib, vrednost CLASSPATH promenljive bi mogla da glasi: CLASSPATH=C:\java\lib čime bi sve klase smeštene po svojim paketima unutar direktorijuma C:\java\lib bile vidljive za sve Java aplikacije. Ukoliko CLASSPATH treba da sadrži više direktorijuma, oni se navode jedan za drugim, sa tačkom-zarez kao separatorom. Na primer: CLASSPATH=C:\java\lib;D:\mojalib Na UNIX sistemima sintaksa navođenja vrednosti CLASSPATH promenljive se unekoliko razlikuje, time što se direktorijumi razdvajaju znakom dvotačka. Ukoliko u CLASSPATH dodamo direktorijum D:\temp\korenski paket iz prethodnih primera, na primer komandom: tada i naš program možemo pokrenuti sa bilo kog mesta u okviru fajl sistema, jer će klase biti vidljive preko CLASSPATH-a. Na primer, komanda: će pokrenuti naš program iako se ne nalazimo u direktorijumu D:\temp\korenski paket JAR arhive Distribucija biblioteka klasa smeštenih u svoje pakete nije preterano elegantna u slučaju većeg broja klasa i paketa, jer se povećava broj datoteka i direktorijuma koje treba instalirati i navesti u CLASSPATH-u. Zbog toga je omogućeno arhiviranje biblioteka u tzv. JAR arhive. U pitanju su arhive koje sadrže klase u svojim paketima arhivirane u klasičnom Zip formatu. Podrazumevana ekstenzija im je.jar (mada može biti i.zip). Ovakve arhive se mogu generisati alatkom jar koja je sastavni deo JDK paketa, ali mogu i bilo kojim drugim programom koji može da generiše Zip arhive (ekstenziju možemo sami promeniti kasnije). Sve klase iz osnovne Java biblioteke su, prilikom instalacije 19

25 JDK paketa, smeštene u datoteku %JAVA_HOME%\jre\lib\rt.jar, gde je JAVA_HOME direktorijum gde je instaliran JDK paket. Ovu datoteku možemo otvoriti, recimo, programom WinZip, kao na slici Slika Arhiva rt.jar otvorena programom WinZip Na slici vidimo da se klasa Vector (zapravo, prevedena datoteka Vector.class) u okviru arhive nalazi u direktorijumu java\util, dakle onom koji odgovara paketu u kome se nalazi klasa. Umesto da u okviru CLASSPATH-a navodimo direktorijum u kome se nalazi raspakovan sadržaj arhive rt.jar, možemo navesti samu datoteku rt.jar (sa svojom putanjom) i dobićemo isti efekat. Na primer: CLASSPATH=C:\jdk1.3\jre\lib\rt.jar Dakle, CLASSPATH može da sadrži nazive direktorijuma i Zip arhiva u kojima se nalaze deljene biblioteke. Korišćenje direktorijuma u arhiva je u ovom slučaju potpuno ravnopravno Podrazumevane komponente u CLASSPATH-u U dosadašnjim primerima je naglašavano da se prilikom pokretanja programa moramo nalaziti u korenskom direktorijumu aplikacije. To je, zapravo, posledica činjenice da se tekući direktorijum u kome se nalazimo nalazi u CLASSPATH-u kada on nije definisan, kao da je CLASSPATH=. gde je tačka (.) oznaka za tekući direktorijum. Ako se CLASSPATH promenljiva definiše, tekući direktorijum se mora eksplicitno navesti u CLASSPATH-u. Još jedna komponenta CLASSPATH-a se podrazumeva, a to je upravo biblioteka rt.jar o kojoj je bilo reči u prethodnom odeljku. Nju ne moramo navoditi čak ni kada definišemo promenljivu CLASSPATH. Dakle, svaki CLASSPATH uvek sadrži ovu dve komponentu: CLASSPATH=C:\jdk1.3\jre\lib\rt.jar Ukoliko CLASSPATH uopšte nije definisan, onda on obuhvata i tekući direktorijum, tako da se može reći da CLASSPATH u tom slučaju glasi: 20

26 CLASSPATH=.;C:\jdk1.3\jre\lib\rt.jar Ovde treba obratiti pažnju da je ovaj podrazumevani skup komponenti CLASSPATH-a uveden tek od Java verzije 1.2. U starijim verzijama CLASSPATH nema podrazumevanih komponenti. Iako se u ovom tekstu u primerima poziva Java kompajlera koristi standardni javac, u praksi se umesto njega često koristi IBM-ov kompajler jikes, koji je znatno brži. jikes nije deo standardne JDK instalacije i mora se instalirati posebno. Do svoje verzije 1.02 (tekuća verzija u ovom trenutku) on se ponaša kao Java 1.1 kompajler, tako da nema podrazumevanih komponenti u CLASSPATH-u. Kako je prilično nezgodno menjati sadržaj CLASSPATH promenljive naizmenično za kompajliranje jikes-om i pokretanje java-om, problem se može prevazići korišćenjem promenljive okruženja JIKESPATH koju koristi isključivo jikes. Ona ima isto značenje kao CLASSPATH do Java verzije 1.1. Dakle, ako CLASSPATH ima sadržaj: CLASSPATH=.;D:\nekamojabibl.zip JIKESPATH bi trebalo da ima sledeći sadržaj: JIKESPATH=.;C:\jdk1.3\jre\lib\rt.jar;D:\nekamojabibl.zip 1.17 Zadatak: klasa Matrix Zadatak 1. Napisati klasu Matrix datu na slici 1. Implementacija metoda je ostavljena kao zadatak. Namena svake metode je opisana odgovarajućim kometarom u tekstu klase. Napomena: u realizaciji izostaviti provere ispravnosti parametara (odgovarajuće dimenzije matrica). class Matrix { /* Postavlja sadržaj matrice. */ void setdata(double[][] x) {... /* Vraća sadržaj matrice. */ int[][] getdata() {... /* Množi sadržaj matrice objekta koji je pozvan (this) sa sadržajem matrice b (objekta koji je prosleđen kao parametar). Rezultat množenja smešta u novi objekat koga vraća kao rezultat metode. */ Matrix multiply(matrix b) {... /* Množi sadržaj dve date matrice i rezultat množenja vraća kao rezultat metode. Obratiti pažnju da je ovo statička metoda! */ static Matrix multiply(matrix a, Matrix b){... /* Množi sadržaj matrice objekta koji je pozvan (this) sa sadržajem matrice b (objekta koji je prosleđen kao parametar). Rezultat množenja se smesta u matricu objekta koji je pozvan. Metoda ne vraća nikakav rezultat! */ void multiply2(matrix b) {... /* Polazna tačka programa. Služi za testiranje funkcionalnosti ostalih metoda klase. Za potrebe testiranja formirati nekoliko 21

27 višedimenzionalnih nizova. */ public static void main(string[] args) {... /* Sadrzaj matrice */ double[][] data; /* Dimenzije matrice */ int n, m; 1.18 Nasleđivanje Nasleđivanje, kao jedan od osnovnih koncepata objektno-orijentisanog programiranja, postoji i u Javi. Kada jedna klasa nasleđuje drugu, potrebno je to naglasiti u okviru teksta klase klazulom extends kao u sledećem primeru, gde klasa BorbeniAvion nasleđuje klasu Avion: class Avion { Krilo levo, desno; void poleti() {... void sleti() {... class BorbeniAvion extends Avion { Top top; Bomba[] bombe; void poleti() {... void pucaj() {... Java ne dopušta višestruko nasleđivanje (onako kako je to definisano recimo u jeziku C++). Dakle klasa može da nasledi najviše jednu klasu Modifikatori pristupa U Javi postoje sledeća tri modifikatora pristupa: public: označava da su atribut ili metoda vidljivi za sve klase u programu protected: atribut ili metoda su vidljivi samo za klase naslednice private: atribut ili metoda su vidljivi samo unutar svoje klase nespecificiran (tzv. friendly): atribut ili metoda su vidljivi sa klase iz istog paketa Modifikatori pristupa se navode ispred definicije metode ili atributa. Sledi primer: class Avion { protected Krilo levo, desno; public void poleti() {... public void sleti() {... Na sličan način modifikatori pristupa se mogu primeniti i na celu klasu, na primer: public class Avion {... 22

28 1.20 Redefinisanje metoda Redefinisanje metoda (method overriding) je postupak kada klasa naslednica redefiniše telo metode nasleđene od roditeljske klase. U Javi se to specificira prostim navođenjem nove definicije metode u klasi naslednici. Sledi primer: class A { int metoda1() { System.out.println("metoda1 klase A"); int metoda2() { System.out.println("metoda2 klase A"); class B extends class A { int metoda1() { System.out.println("metoda1 klase B"); U slučaju da se izvrši sledeći segment koda: A vara = new A(); B varb = new B(); vara.metoda1(); varb.metoda1(); vara.metoda2(); varb.metoda2(); na konzoli će se ispisati: metoda1 klase A metoda1 klase B metoda2 klase A metoda2 klase A (metoda1 je redefinisana u klasi B, tako da je promenjen ispis na konzolu, dok metoda2 nije redefinisana, pa se za klasu B preuzima implementacija metode iz klase A) Apstraktne klase Apstraktne klase su klase koje ne mogu imati svoje instance (objekte). Razlog za to je što je implementacija neke od metoda izostavljena. U primeru public abstract class A { public void metoda1() {... public abstract void metoda2(); private int i; metoda metoda2 je proglašena za apstraktnu korišćenjem ključne reči abstract. Njena implementacija nije navedena. Samim tim klasa je apstraktna pa se i za nju to mora navesti navođenjem ključne reči abstract ispred class. Dakle iskaz poput: A x = new A(); 23

29 nije dopušten Interfejsi Interfejsi su poseban koncept u Javi: nisu u pitanju klase, ali interfejsi mogu da sadrže deklaracije apstraktnih metoda, konstanti i statičkih atributa. Sledi primer: interface Instrument { void sviraj(); void nastimaj(); Vidimo da interfejsi podsećaju na apstraktne klase. Veza između klasa i interfejsa je sledeća: kaže se da klasa implementira (a ne nasleđuje) interfejs. Klasa može da implementira više interfejsa istovremeno, što nije slučaj sa nasleđivanjem. Nema prepreke da klasa koja nasleđuje drugu klasu implementira i neke interfejse. Jedan interfejs može da nasledi drugi interfejs. Sledi primer: class Klarinet implements Instrument { void sviraj() {... void nastimaj() {... Time što je klasa implementirala interfejs zapravo se obavezala da će implementirati sve njegove metode. Kompajler neće dopustiti prevođenje klase koja implementira interfejs a nije redefinisala sve njegove metode Unutrašnje klase Od Java verzije 1.1 klasa može, osim atributa i metoda, da poseduje i tzv. unutrašnje klase (inner classes). Sledi primer: class Spoljasnja { void metoda() {... class Unutrasnja { int metoda2() {... Klasa Unutrasnja je, u principu, vidljiva samo unutar klase Spoljasnja, mada se to može promeniti modifikatorima pristupa na uobičajen način. Instanca unutrašnje klase se može kreirati i izvan nje, ali samo preko instance spoljašnje klase, kao u sledećem primeru: Spoljasnja s = new Spoljasnja(); Spoljasnja.Unutrasnja u = s.new Unutrasnja(); Sledeći izraz (pokušaj konstrukcije instance inutrašnje klase bez instance spoljašnje klase) nije dozvoljen: Spoljasnja.Unutrasnja u = new Spoljasnja.Unutrasnja(); Koncept unutrašnjih klasa se najviše koristi prilikom izgradnje grafičkog korisničkog interfejsa, o čemu će više reči biti u poglavlju 3. 24

30 1.24 Polimorfizam Polimorfizam je koncept koji omogućava objektima da ispolje različito ponašanje, zavisno od njihove klase, bez obzira što se oni koriste kao instance nekog zajedničkog roditelja. Posmatrajmo sledeće tri klase: abstract class Instrument { abstract void sviraj(); class Violina extends Instrument { void sviraj() {... class Klarinet extends Instrument { void sviraj() {... Dakle, primer definiše tri klase: klasa Instrument je apstraktna klasa (njena metoda sviraj je apstraktna), a klase Violina i Klarinet nasleđuju klasu Instrument i, naravno, implementiraju (zapravo, redefinišu) apstraktnu metodu. Posmatrajmo sada klasu Muzicar: class Muzicar { void sviraj(instrument i) { i.sviraj(); Vidimo da klasa Muzicar ima metodu sviraj koja kao parametar ima instancu klase Instrument; sa druge strane, znamo da klasa Instrument ne može imati instance, jer je apstraktna. Ova metoda će ipak biti upotrebljiva, jer se njoj kao parametar može proslediti instanca neke klase koja nasleđuje klasu Instrument u ovom slučaju instance klasa Violina i Klarinet. Iskaz Muzicar m = new Muzicar(); m.sviraj(new Klarinet()); će izazvati pozivanje metode sviraj klase Klarinet (iako se to nigde eksplicitno ne navodi u metodi sviraj klase Muzicar). Iskaz m.sviraj(new Violina()); će izazvati pozivanje metode sviraj klase Violina po istom principu. Dakle, poziv metode sviraj klase Muzicar će imati različite efekte zavisno od toga koji objekat prosledimo kao parametar. Određivanje koja metoda će se pozvati se obavlja u toku izvršavanja programa. U primeru se vidi da ovo specijalno ponašanje metoda nije ničim naglašeno u tekstu programa. Ovakav efekat se u jeziku C++ postizao korišćenjem tzv. virtuelnih funkcija članica, a u Javi je ovo podrazumevano (i jedino moguće) ponašanje. Dakle, možemo reći, u terminologiji jezika C++, da su sve metode u Javi virtuelne, pa se ta osobina ne mora naglašavati posebno u programu Izuzeci Izuzeci su mehanizam za kontrolu toka programa koji se koristi za obradu grešaka nastalih u toku izvršavanja programa. Segment programskog koda za 25

31 koji smatramo da može da izazove izuzetak možemo da smestimo u tzv. try/catch blok, kao u sledećem primeru: try { // kod koji može da izazove izuzetak catch (Exception ex) { System.out.println("Desio se izuzetak: " + ex); Izuzetak može biti, na primer, deljenje nulom, pristup elementu niza koji je izvan granice niza, itd. Ukoliko se prilikom izvršavanja koda koji se nalazi u try bloku desi izuzetak, tok izvršavanja programa se automatski prebacuje na početak catch bloka. Nakon izvršavanja koda u catch bloku, program dalje nastavlja rad. U okviru catch bloka informacije o samom izuzetku koji se dogodio su dostupne preko objekta klase Exception ili neke njene naslednice. U primeru je to objekat ex. Različite vrste izuzetaka su predstavljene različitim exception klasama, na primer: svi izuzeci prilikom izvršavanja aritmetičkih operacija (deljenje nulom, overflow, itd.) su predstavljene klasom ArithmeticException, pristup elementu čiji je indeks izvan granice niza je predstavljen klasom ArrayIndexOutOfBounds- Exception, itd. Klasa Exception je zajednički predak svim exception klasama. Jedan try blok može imati više sebi pridruženih catch blokova, kao u sledećem primeru: try { // kod koji može da izazove // izuzetak catch (ArithmeticException ex) { System.out.println("Deljenje nulom"); catch (ArrayIndexOutOfBoundsException ex) { System.out.println("Pristup van granica niza"); catch (Exception ex) { System.out.println("Svi ostali izuzeci"); finally { // kod koji se izvršava u svakom slučaju Kada se dogodi izuzetak, niz catch blokova se sekvencijalno obilazi i ulazi se u onaj catch blok čija klasa odgovara izuzetku koji se dogodio. Reč odgovara u ovom slučaju znači: u pitanju je klasa kojoj exception objekat pripada, ili njen predak. Kada poslednji catch blok hvata izuzetak klase Exception, to znači da će svi izuzeci biti obrađeni, jer je klasa Exception zajednički roditelj. Blok finally se ne mora navesti. On sadrži blok koda koji će se izvršiti u svakom slučaju, desio se izuzetak ili ne. 26

32 Kao što postoje odgovarajuće klase koje opisuju različite vrste izuzetaka, moguće je definisati i nove vrste izuzetaka definicijom odgovarajuće klase. Na primer, možemo da definišemo novu vrstu izuzetka predstavljenog klasom MojException koja je data u primeru: public class MojException extends Exception { public MojException() { super(); public MojException(String msg) { super(msg); Klasa MojException ima dva konstruktora koji pozivaju odgovarajuće konstruktore roditeljske klase Exception. Pisanje ovakvih konstruktora nije obavezno, ali je obavezno naslediti klasu Exception (ili nekog njenog potomka). Ovakav korisnički izuzetak može biti izazvan samo programski, pomoću ključne reči throw, kao u sledećem primeru: if (errorcheck()) throw new MojException("Houston, we have a problem."); Programski kod koji sadrži ovakvu throw naredbu mora biti smešten unutar try bloka koji hvata izuzetak MojException na to će nas naterati kompajler. Dakle, ovo bi moglo da izgleda na sledeći način: try { if (errorcheck()) throw new MojException("Houston, we have a problem."); catch (MojException ex) { System.out.println("Exception: " + ex); Drugi način da obradimo nastanak ovakvog izuzetka je da metodu u kojoj se nalazi throw naredba označimo kao metodu u kojoj može da nastane izuzetak date vrste. Na primer: public void metoda() throws MojException {... if (errorcheck()) throw new MojException("Houston, we have a problem.");... Sada poziv ovakve metode mora biti u odgovarajućem try bloku, ili metoda u kojoj sadrži ovaj poziv mora isto biti označena da može da izazove izuzetak. Dakle: public void m1() { try { metoda(); catch (MojException ex) { System.out.println("Exception: " + ex); 27

33 ili: public void m1() throws MojException { metoda(); Na ovaj način odgovornost za obradu izuzetka može propagirati sve do metode main od koje počinje izvršavanje programa! 1.26 Klasa Object Klasa Object predstavlja osnovnu klasu u hijerarhiji Java klasa, u smislu da sve klase nasleđuju klasu Object. Za klase za koje se navede da ne nasleđuju nijednu klasu (izostavljanjem extends klauzule) podrazumeva se da nasleđuju klasu Object. Klasa Object nije apstraktna, tako da je moguće kreirati objekat ove klase. Ona definiše neke metode koje se relativno često koriste, poput ovih koje su opisane u nastavku ovog odeljka. public boolean equals(object o); Koristi se prilikom poređenja objekata; poređenje tipa (a == b) je zapravo poređenje referenci. Poređenje (a.equals(b)) vraća rezultat zavisno od implementacije metode equals klase kojoj pripada objekat a. Klasa Object definiše podrazumevano poređenje objekata koje se svodi na poređenje referenci. public int hashcode(); Izračunava hash vrednost za dati objekat. Koristi se najviše u hash-tabelama. public String tostring(); Vraća string reprezentaciju objekta. Ukoliko se ne redefiniše, poziva se implementacija iz klase Object koja vraća prilično nerazumljiv rezultat. Ova metoda ima donekle specijalan tretman od strane kompajlera, o čemu će više reči biti u sledećem odeljku Klasa String Klasa String se nalazi u paketu java.lang i predstavlja string kao tip podatka (sećamo se da stringovi nemaju odgovarajući primitivni tip u Javi). U tom smislu, klasa String je kao i svaka druga Java klasa osim što ima donekle specijalan tretman od strane kompajlera. 1. Vrednosti primitivnih tipova se mogu predstaviti u Java programu odgovarajućim konstantama. Na primer, 16 je vrednost tipa int, vrednost 16L označava vrednost tipa long, 'x' je vrednost tipa char, itd. Objektima se ne može pridružiti vrednost koja se može predstaviti literalom, osim u slučaju objekata klase String. U tom smislu, "tekst" u Java programu predstavlja objekat klase String čija je vrednost inicijalizovana na dati tekst. Zbog toga je sasvim ispravno pisati String x = "tekst"; što ima isti efekat kao i 28

34 String x = new String("tekst"); 2. Java ne omogućava redefinisanje operatora (kao što je to moguće u jeziku C++). Međutim, operator + može da se upotrebi za konkatenaciju stringova. Kada naiđe na izraz poput "ime" + "prezime" ili x + "prezime" ili x + y kompajler će generisati kod koji će izvršiti konkatenaciju stringova i vratiti rezultat u obliku novokreiranog objekta klase String. Konkatenacija može da obuhvati i primitivne tipove ili objekte drugih klasa. Na primer, iskaz int a = 10; String x = "vrednost: " + a; rezultira kreiranjem novog String objekta čiji sadržaj je "vrednost: 10". U slučaju konkatenacije stringa sa objektom neke druge klase, kao na primer: Automobil a = new Automobil(); String x = "Moj auto je: " + a; biće pozvana metoda tostring klase Automobil, pa će se zatim izvršiti konkatenacija stringova pomoću dobijenog stringa. 3. Metoda koja kao parametar ima tip String, može u svom pozivu da primi i objekat neke druge klase, pri čemu će kompajler automatski generisati kod koji poziva metodu tostring() objekta, i zatim taj rezultat prosleđuje metodi koja se poziva. Na primer, posmatrajmo metodu public void handlemessage(string message) {... i njen poziv handlemessage(new Automobil()); Ovaj poziv metode handlemessage biće, u stvari, preveden u sledeći poziv: handlemessage(new Automobil().toString()); 4. Za razliku od svih ostalih parametara, parametri metoda tipa String se ponašaju kao da se prenose po vrednosti a ne po referenci, iako su u pitanju objekti, a ne primitivni tipovi. Na primer, poziv sledeće metode public void handlemessage(string message) { message += "xxx"; neće izazvati promenu objekta koji je prosleđen kao parametar, jer će se u telu metode, prilikom konkatenacije, generisati novi String objekat koji će biti dodeljen lokalnoj kopiji reference message. Po povratku iz metode uništava se promenjena lokalna kopija reference, i ostaje samo originalna referenca koja i dalje ukazuje na stari String objekat Primeri nekih klasa iz standardne biblioteke Namena ovog odeljka je da ilustruje korišćenje nekih od klasa koje su sastavni deo standardne Java biblioteke, a koriste se često u praksi. Prednost postojanja ovako bogate standardne biblioteke je i u tome što se sa sigurnošću zna da su 29

35 ove klase dostupne u svakoj Java instalaciji, pa se klase iz biblioteke mogu slobodno koristiti, bez bojazni da ih neće biti na računaru gde softver instalira, ili čak, u slučaju Jave 1.2, da ih neće biti u CLASSPATH-u Klasa java.util.vector Klasa Vector služi kao kontejnerska klasa koja čuva kolekciju objekata kao sekvencu. Elementima sekvence se može pristupati po indeksu, a elementi se mogu dodavati i uklanjati na proizvoljnom mestu. Klasa je pisana tako da radi sa Object objektima, tako da je u stanju da prihvati sve objekte koje joj prosledimo. Sledi primer u kome se u jednom Vector objektu čuva niz String-ova. Za dodavanje elemenata u vektor koristi se metoda addelement, a za pristup objektima koristi se metoda elementat. Iako ovaj primer demonstrira smeštanje objekata iste klase u vektor, to ne mora biti slučaj. Nema prepreke da se u isti vektor smeštaju objekti različitih klasa. import java.util.vector; class VectorTest { public static void main(string args[]) { Vector v = new Vector(); v.addelement("ovo"); v.addelement("je"); v.addelement("probni"); v.addelement("tekst"); for (int i = 0; i < v.size(); i++) System.out.print((String)v.elementAt(i) + " "); Klasa java.util.hashtable Klasa Hashtable implementira hash-tabelu koja mapira ključeve na vrednosti (i ključevi i vrednosti su predstavljeni odgovarajućim objektima). Parovi (ključ, vrednost) se u metodu smeštaju metodom put. Vrednost se u tabeli traži pomoću svog ključa metodom get. Sledeći primer predstavlja generisanje slučajnih celih brojeva u opsegu [0, 19] i brojanje koliko se puta koji broj pojavio pomoću hash-tabele. Tabela kao ključ koristi generisani broj, a vrednost je objekat klase Counter koji služi kao brojač pojava odgovarajućeg broja. class Counter { int i = 1; public String tostring() { return Integer.toString(i) + "\n"; import java.util.*; class Statistics { public static void main(string args[]) { Hashtable ht = new Hashtable(); for (int i = 0; i < 10000; i++) { Integer r = 30

36 new Integer((int)(Math.random() * 20)); if (ht.containskey(r)) ((Counter)ht.get(r)).i++; else ht.put(r, new Counter()); System.out.println(ht); Klasa java.util.stringtokenizer Klasa StringTokenizer je namenjena za parsiranje stringova oko datih delimitera. Za dati string i delimitere, generišu se tokeni u odgovarajućem redosledu. Metoda hasmoretokens vraća true ako nije iscrpljena lista tokena dobijenih parsiranjem. Metoda nexttoken vraća string koji predstavlja tekući token u parsiranju. Dati primer prikazuje parsiranje teksta oko blanko-znakova i ispisivanje dobijenih tokena na konzolu. import java.util.*; class TokenizerTest { public static void main(string args[]) { String text = "Ovo je probni tekst"; StringTokenizer st = new StringTokenizer(text, " "); while (st.hasmoretokens()) { System.out.println(st.nextToken()); 1.29 Konvencije davanja imena Ovaj odeljak navodi neke od opšteprihvaćenih konvencija za davanje imena identifikatorima u Java programima. 1. Nazivi klasa se pišu malim slovima, osim što počinju velikim slovom (npr. Automobil, Vector). Ne postoji nikakav prefiks (kao CVector ili TVector). Ukoliko se naziv klase sastoji iz više reči, reči se spajaju, a svaka od njih počinje velikim slovom (npr. StringTokenizer, ArrayIndexOutOfBoundsException). 2. Nazivi metoda i atributa se pišu malim slovima (npr. size, width). Ako se sastoje od više reči, reči se spajaju, pri čemu sve reči počevši od druge počinju velikim slovom (npr. setsize, handlemessage). 3. Nazivi paketa se pišu isključivo malim slovima. Ukoliko se sastoje iz više reči, reči se spajaju (npr. mojpaket, velikipaket.malipaket). Detaljan opis konvencija nalazi se na adresi index.html Generisanje programske dokumentacije i javadoc Standardna JDK distribucija sadrži i alat javadoc namenjen generisanju programske dokumentacije. Kao izvor informacija za generisanje dokumen- 31

37 tacije koriste se specijalni komentari u izvornom kodu, koji počinju sa /** i završavaju sa */ (za razliku od klasičnih komentara /*... */). Rezultat rada javadoc alata je skup HTML dokumenata koji opisuju dati program. Specijalni komentar koji se nalazi neposredno ispred definicije klase smatra se opisom klase koji se smešta na odgovarajuće mesto u dokumentaciji. Slično tome, specijalni komentar koji se nalazi neposredno ispred definicije metode ili atributa smatra se opisom te metode ili atributa. Unutar specijalnih komentara mogu se koristiti HTML tagovi za formatiranje teksta. Dostupne su takođe i sledeće posebne oznake (tzv. Opisuje parametar ime opis Opisuje rezultat opis Opisuje izuzetak koji može da izazove puno-ime-klase opis Referenca na neku drugu klasu, metod ili puno-ime-klase#ime-metode Podaci o author-info Opis version-info Navodi od koje verzije nekog objekta dati kod može da radi. Obično se koristi da označi minimalnu potrebnu verziju JDK since-info Označava zastarelu mogućnost koja može biti napuštena u sledećim verzijama. Kompajler će generisati upozorenje ako se koriste ovakve metode ili atributi. Primer jedne Java klase koja sadrži odgovarajuće javadoc komentare dat je u nastavku. /** Klasa namenjena za rad sa matricama Branko Milosavljević 1.0 */ public class Matrix { /** Konstruktor n Broj redova matrice m Broj kolona matrice MathException U slučaju da je neka od * dimenzija manja od 1 */ public Matrix(int n, int m) throws MathException {... /** Postavlja sadržaj matrice. x Nova vrednost matrice MathException U slučaju da je neka od 32

38 * dimenzija manja od 1, ili je vrednost parametra * <code>null</code> */ public void setdata(double[][] x) throws MathException {... /** Vraća sadržaj matrice. Tekuća vrednost matrice */ public double[][] getdata() {... /** Množi sadržaj matrice objekta koji je pozvan (this) sa * sadržajem matrice b (objekta koji je prosleđen kao * parametar). Rezultat množenja smešta u novi objekat koga * vraća kao rezultat metode. b Druga matrica u množenju Rezultat množenja MathException U slučaju neispravnih dimenzija matrica */ public Matrix multiply(matrix b) throws MathException {... /** Množi sadržaj dve date matrice i rezultat množenja * vraća kao rezultat metode. Obratiti pažnju da je ovo * statička metoda! a Prvi činilac poizvoda b Drugi činilac proizvoda Rezultat množenja MathException U slučaju neispravnih dimenzija matrica */ public static Matrix multiply(matrix a, Matrix b) throws MathException {... /** Množi sadržaj matrice objekta koji je pozvan (this) sa * sadržajem matrice b (objekta koji je prosleđen kao * parametar). Rezultat množenja se smešta u matricu objekta * koji je pozvan. Metoda ne vraća nikakav rezultat! b Drugi činilac proizvoda MathException U slučaju neispravnih dimenzija matrica */ public void multiply2(matrix b) throws MathException {... /** Vraća string reprezentaciju objekta. String reprezentacija objekta */ public String tostring() {... /** Sadržaj matrice */ private double[][] data; /** Dimenzije matrice */ private int n, m; Zadaci: modifikacije klase Matrix Zadatak 2. Proširiti zadatak 1 tako da se u okviru metoda klase Matrix vrši provera dimenzija matrice na odgovarajući način. Signalizaciju greške realizovati pomoću mehanizma izuzetaka. Napisati sopstvenu klasu MathException za obradu izuzetaka ove vrste. 33

39 Zadatak 3. Napisati klasu TestMatrix sa metodom main iz klase Matrix. Metodu main ukloniti iz klase Matrix. Klase Matrix i MathException smestiti u paket vta.math, a klasu TestMatrix u implicitni (korenski) paket. Prevesti i pokrenuti program. Zadatak 4. a) Isprobati pokretanje klase TestMatrix iz nekog drugog direktorijuma; modifikovati sistemsku varijablu CLASSPATH na odgovarajući način. b) Paket vta.math spakovati u JAR arhivu vta.jar. Arhivu dodati u CLASSPATH i pokrenuti klasu TestMatrix. 34

40 Poglavlje 2 Konkurentno programiranje u Javi Java je programski jezik koji sadrži koncepte potrebne za pisanje konkurentnih programa. Izvršavanje ovakvih programa zavisi, naravno, od korišćene Java virtuelne mašine, operativnog sistema, i hardverske platforme, ali su te zavisnosti sklonjene od Java programera. Drugim rečima, isti konkurentni program se može izvršavati na različitim računarskim platformama bez modifikacija. Pisanje konkurentnih programa obično zahteva korišćenje odgovarajućih funkcija operativnog sistema, što takve programe čini teško prenosivim na različite operativne sisteme. Svaki Java program je, zapravo, konkurentan program: garbage collector, o kome je bilo reči u prethodnom poglavlju, se izvršava kao posebna nit programa. Na izvršavanje garbage collector-a nemamo velikog uticaja, a u pisanju konkurentnih programa možemo zanemariti činjenicu da je garbage collector aktivan u okviru posebne niti. 2.1 Kreiranje programskih niti Programska nit (thread) se u Javi predstavlja objektom klase Thread ili njene naslednice. Klasa Thread je, u suštini, roditeljska klasa koju je potrebno naslediti prilikom definisanja nove programske niti. Sam programski kod koji definiše rad niti je smešten unutar metode run ovakve klase. Sledi primer novodefinisane niti: public class MojThread extends Thread { public void run() { // programski kod niti je ovde (U primerima će crvenom bojom biti naglašeni elementi programskog koda na koje se želi skrenuti posebna pažnja). Kreiranje instance ovakve klase nije dovoljno da bi se nit pokrenula. Za pokretanje niti potrebno je pozvati metodu start. Ne treba pozivati metodu run direktno, jer to neće izazvati potreban efekat. Metoda start (koja se obično ne redefiniše) će obaviti potrebnu inicijalizaciju i pozvati metodu run. Dakle, pokretanje nove niti klase MojThread može da se obavi sledećim segmentom koda: 35

41 MojThread mt = new MojThread(); mt.start(); Od ove tačke nadalje, naš program se sastoji iz dve niti: osnovne niti programa koja počinje svoje izvršavanje od metode main, i novostvorene niti koja je opisana u metodi run klase MojThread. Slika 2.1 ilustruje ovu situaciju. osnovna nit mt MojThread mt = new MojThread(); mt.start(); Slika 2.1 Pokretanje nove niti Drugi način za kreiranje programske niti je implementacija interfejsa Runnable. Ovaj postupak se obično koristi kada nije moguće naslediti klasu Thread (zato što nova klasa već nasleđuje neku klasu, a višestruko nasleđivanje nije dozvoljeno). Implementiranje interfejsa Runnable se svodi na implementiranje metode run koja ima istu funkciju kao i u prethodnom slučaju. Na primer, klasa MojaNit u ovom slučaju je definisana tako da implementira interfejs Runnable. public class MojaNit implements Runnable { public void run() { // programski kod niti je ovde Pokretanje ovakve niti se unekoliko razlikuje od prethodnog slučaja. Evo kako se to radi: MojaNit mn = new MojaNit (); Thread t = new Thread(mn); t.start(); Ukoliko je programski kod metode run jednak u oba slučaja, obe varijante su funkcionalno ekvivalentne. 2.2 Daemon i non-daemon niti Java programi razlikuju dve vrste programskih niti: tzv. daemon i non-daemon niti. Nit se proglašava za daemon-nit tako što se pozove metoda setdaemon(true), a non-daemon-nit tako što se pozove setdaemon(false). Suštinska razlika između ove dve vrste niti je u tome što će se Java program završiti kada se okončaju sve njegove non-daemon niti. Inicijalno program startuje sa jednom non-daemon niti koja počinje svoje izvršavanje metodom main. Daemon-niti su namenjene za obavljanje zadataka u pozadini, čije kompletno izvršavanje nije od značaja za rad programa. 36

42 2.3 Primer programa sa više niti Posmatrajmo sledeći program koji se sastoji iz klasa PrviThread i ThreadTest: public class ThreadTest { /** Broj niti koje ce se pokrenuti */ public static final int THREAD_COUNT = 10; /** Pokrece sve niti i zavrsava sa radom */ public static void main(string[] args) { for (int i = 0; i < THREAD_COUNT; i++) new PrviThread(i).start(); System.out.println("Threads started."); public class PrviThread extends Thread { /** Konstruktor threadid Identifikator niti */ public PrviThread(int threadid) { this.threadid = threadid; counter = 10000; /** Nit: na svaki 1000-ti prolaz petlje ispisi poruku na konzolu. */ public void run() { while (counter > 0) { if (counter % 1000 == 0) System.out.println("Thread[" + threadid + "]: " + (counter/1000)); counter--; /** Brojac petlje unutar niti */ private int counter; /** ID niti */ private int threadid; Klasa ThreadTest sadrži metodu main odakle počinje izvršavanje programa. U okviru ove metode kreira se deset novih niti klase PrviThread. Treba primetiti da se u telu petlje u istom redu kreira novi objekat klase PrviThread (sa new PrviThread(i)) i nad tim objektom odmah poziva metoda start. Nigde se ne čuva referenca na ovaj objekat, jer ona nije ni potrebna. Nakon izlaska iz petlje ispisuje se poruka da je kreiranje niti završeno i tu je kraj metode main. Klasa PrviThread ima konstruktor koji prima identifikator niti kao parametar (identifikator smo sami definisali). U konstruktoru se inicijalizuje i vrednost brojačke promenljive counter. U okviru metode run izvršava se petlja od iteracija (pomoću brojača counter) i u svakom hiljaditom prolazu ispisuje se poruka na konzolu. Nakon izlaska iz petlje nit se završava. 37

43 Posmatrajmo početak jedne moguće varijante izvršavanja ovog programa prikazane na slici 2.2. Slika 2.2. Izvršavanje programa ThreadTest Na slici vidimo da je prva ispisana poruka zapravo poruka koju ispisuje metoda main kada završava sa radom. To znači da je u ovom slučaju, prilikom pokretanja programa, osnovna nit programa stigla da izvrši celokupan svoj programski kod pre nego što su druge niti dobile priliku da zauzmu procesor. Samim tim, ovo je ilustracija slučaja gde završavanje osnovne niti programa ne predstavlja i završavanje celog programa: postoji još deset non-daemon niti koje nisu završile svoj rad. Ova situacija bi se grafički mogla predstaviti kao na slici 2.3. osnovna nit new PrviThread(0).start(); new PrviThread(1).start(); new PrviThread(2).start();... new PrviThread(9).start(); x x x x x Slika 2.3. Grafička predstava izvršavanja programa ThreadTest 38

44 2.4 Sinhronizacija niti Prethodni primer predstavlja program u kome izvršavanje jedne niti ne utiče na izvršavanje ostalih niti (osim što ta nit konkuriše za zauzeće procesora). Konkurentni programi ovakve vrste su relativno retki. Kada je potrebno da dve niti komuniciraju, komunikacija se mora obaviti putem zajedničkog (deljenog) resursa. U Javi je u pitanju zajednički objekat kojem obe niti mogu da pristupe. Kako niti dobijaju deo procesorskog vremena na osnovu odluke Java virtuelne mašine i operativnog sistema, ne možemo biti sigurni da jedna nit u toku pristupa deljenom objektu neće biti prekinuta i kontrola biti predata drugoj niti koja isto tako može početi da pristupa deljenom objektu i izazvati greške prilikom nastavka izvršavanja prve niti (koja u objektu zatiče drugačije stanje u odnosu na trenutak kada je bila prekinuta). Zbog toga je neophodno koristiti mehanizam zaključavanja objekata koji obezbeđuje da najviše jedna nit može da pristupa deljenom objektu u nekom periodu vremena. Ovaj mehanizam je u Javi implementiran pomoću tzv. synchronized blokova. Synchronized blok izgleda kao u sledećem primeru: synchronized (obj) { // obj je deljeni objekat; // imamo ekskluzivno pravo pristupa njemu // unutar ovog bloka Početak synchronized bloka predstavlja zaključavanje objekta od strane niti. Kraj bloka predstavlja oslobađanje objekta. Kada hronološki prva nit pokuša da uđe u synchronized blok, dobiće pravo pristupa i zaključaće objekat (acquire lock). Sve dok ta nit ne oslobodi objekat (release lock), druge niti neće moći da mu pristupe. Ako neka druga nit pokuša da uđe u svoj synchronized blok, biće blokirana u toj tački sve dok prva nit ne oslobodi objekat. Tada će druga nit dobiti pravo pristupa, zaključati objekat i ući u svoj synchronized blok. Slika 2.4 ilustruje ovu situaciju. nit A nit B sync { 1) lock 4) unlock obj 2) locked? 3) yes 5) lock wait sync { 6) unlock Slika 2.4. Pristup deljenom objektu iz dve niti Drugi način za implementaciju mehanizma zaključavanja objekata su tzv. synchronized metode. Synchronized metoda se definiše kao u sledećem primeru: public synchronized void metoda() {... 39

45 Poziv ovakve metode se ponaša kao ulazak u synchronized blok: za vreme izvršavanja metode samo nit koja je pozvala metodu ima prava pristupa objektu. 2.5 Dodatne metode za sinhronizaciju Nekad je potrebno da nit sačeka na neki događaj, iako se nalazi unutar synchronized bloka. To čekanje može da traje proizvoljno dugo, pa bi u tom slučaju pristup zaključanom objektu bio nemoguć u proizvoljno dugačkom intervalu vremena. Metoda wait (nasleđena iz klase Object, tako da je dostupna u svim klasama) radi sledeće: oslobađa zauzeti objekat i blokira izvršavanje niti sve dok neka druga nit ne pozove metodu notify nad istim objektom. Metoda notify (takođe nasleđena iz klase Object) obaveštava nit koja je (hronološki) prva pozvala wait da može da nastavi sa radom. Nit koja je čekala u wait metodi neće odmah nastaviti izvršavanje, nego tek nakon što nit koja je pozvala notify ne izađe iz svog synchronized bloka (slika 2.5). Metoda notifyall obaveštava sve niti koje čekaju u wait da mogu da nastave sa radom. Nakon izlaska iz synchronized bloka sve te niti će konkurisati za procesorsko vreme. nit A nit B sync { wait(); waiting for notify waiting for lock obj notify sync { notify(); Slika 2.5. Mehanizam wait/notify Ove tri metode mogu biti pozvane samo unutar synchronized bloka i to nad objektom nad kojim se vrši sinhronizacija. 2.6 Primer programa sa sinhronizacijom niti Posmatrajmo dve niti, jednu koja proizvodi podatke i drugu koja ih troši. One komuniciraju preko deljenog objekta koji je zapravo bafer za podatke. Potrebno je omogućiti da se punjenje i pražnjenje bafera odvijaju u paralelnim nitima (slika 2.6). Bafer predstavlja klasičnu implementaciju kružnog bafera. Nit proizvođač će puniti bafer (osim ako već nije pun, tada mora da čeka), a nit potrošač će 40

46 prazniti bafer (osim ako nije prazan, tada mora da čeka). U našem primeru nit proizvođač je implementirana klasom Producer, a nit potrošač klasom Consumer. public class Consumer extends Thread { public Consumer(Buffer buffer, int count) { this.buffer = buffer; this.count = count; public void run() { for (int i = 0; i < count; i++) buffer.read(); private Buffer buffer; private int count; public class Producer extends Thread { public Producer(Buffer buffer, int count) { this.buffer = buffer; this.count = count; public void run() { for (int i = 0; i < count; i++) buffer.write((int)math.round(math.random() * 100)); private Buffer buffer; private int count; Vidimo da klase Consumer i Producer ne poseduju nikakav programski kod koji vrši sinhronizaciju pristupa. Sinhronizacija je obavljena na nivou metoda read i write klase Buffer. Objekti klasa Consumer i Producer preko svojih konstruktora primaju bafer sa kojim će raditi i broj podataka koje treba da pročitaju, odnosno upišu u bafer. Klasa Buffer sadrži sve što je potrebno za sinhronizaciju niti. Sledi programski kod klase Buffer. /** Implementacija kružnog bafera */ public class Buffer { /** Konstruktor size Veličina kružnog bafera */ public Buffer(int size) { this.size = size; data = new int[size]; readpos = 0; writepos = 0; 41

47 /** Upisuje novu vrednost u bafer. value Nova vrednost koja se upisuje */ public synchronized void write(int value) { if (isfull()) { System.out.println("Waiting to write..."); try { wait(); catch (Exception ex) { ex.printstacktrace(); data[writepos] = value; if (++writepos == size) writepos = 0; notify(); System.out.println("Written: "+value); /** Čita narednu vrednost iz bafera. Pročitana vrednost */ public synchronized int read() { if (isempty()) { System.out.println("Waiting to read..."); try { wait(); catch (Exception ex) { ex.printstacktrace(); int retval = data[readpos]; if (++readpos == size) readpos = 0; System.out.println("Read: "+retval); notify(); return retval; /** Ispituje da li je bafer prazan. Vraća <code>true</code> ako je bafer prazan */ public synchronized boolean isempty() { return readpos == writepos; /** Ispituje da li je bafer pun. Vraca <code>true</code> ako je bafer pun */ public synchronized boolean isfull() { return readpos == (writepos + 1) % size; /** Veličina kružnog bafera */ private int size; /** Sadržaj kružnog bafera */ private int[] data; /** Naredna lokacija za čitanje */ private int readpos; /** Naredna lokacija za pisanje */ 42

48 private int writepos; Konstruktor klase Buffer prima kao parametar veličinu bafera. U konstruktoru se alocira memorija za bafer, i inicijalizuju se indeksi lokacije za čitanje iz bafera i lokacije za pisanje u bafer. Metoda isempty služi za testiranje da li je bafer prazan, a metoda isfull za testiranje da li je bafer pun. Smatra se da je bafer prazan ako su indeksi pozicija lokacija za čitanje i pisanje jednaki. Bafer je pun ako je indeks pozicije za čitanje za jedan manji od lokacije za pisanje ili je indeks lokacije za čitanje jednak nuli, a indeks lokacije za pisanje jednak indeksu poslednjeg elementa niza koga koristi bafer. Slika 2.6 ilustruje ove situacije. a) writepos readpos writepos readpos b) writepos readpos readpos writepos c) readpos writepos Slika 2.6. a) Slučajevi kada je bafer prazan; b) slučajevi kada je bafer pun; c) slučajevi kada bafer nije ni prazan ni pun Metoda read je namenjena za čitanje podataka i njihovo uklanjanje iz bafera. Metoda je definisana kao synchronized, tako da obezbeđuje ekskluzivno pravo pristupa baferu onoj niti koja je pozove. U okviru metode, prvo se proveri da li je bafer prazan; ako nije, prvi podatak koji je na redu za čitanje se uklanja iz bafera i vraća se kao rezultat metode. Ako je bafer prazan, poziva se wait metoda, čime se izvršavanje ove niti suspenduje sve dok proizvođač nit ne upiše novi podatak u bafer; tada će se, u okviru metode write, pozvati metoda notify, čime će se potrošač nit ponovo aktivirati. Metoda write je namenjena za pisanje podataka u bafer. Takođe je definisana kao synchronized. Njeno funkcionisanje je simetrično metodi read. U okviru metode prvo se proverava da li je bafer pun; ako nije, novi podatak se upisuje u bafer. Ako je bafer pun, poziva se metoda wait, čime se nit suspenduje sve dok potrošač nit ne pročita podatak iz bafera, čime će se proizvođač nit ponovo aktivirati. Klasa Test je namenjena za pokretanje programa. Sadrži samo metodu main u okviru koje se kreira bafer, proizvođač nit, potrošač nit i niti se pokrenu. public class Test { public static final int BUFFER_SIZE = 100; 43

49 public static final int PRODUCE_COUNT = 100; public static void main(string[] args) { Buffer buffer = new Buffer(BUFFER_SIZE); Producer p = new Producer(buffer, PRODUCE_COUNT); Consumer c = new Consumer(buffer, PRODUCE_COUNT); p.start(); c.start(); 2.7 Zadatak: problem pet filozofa Zadatak 5. Napisati program koji simulira problem pet filozofa. Objašnjenje: Posmatra se okrugli sto za kojim sedi pet filozofa. Između njihovih tanjira nalazi se pet štapića za jelo. Kako su za obedovanje potrebna dva štapića, nije moguće obezbediti da svih pet filozofa obeduje istovremeno. Svaki od filozofa će zauzeti jedan od njemu potrebnih štapića čim ovaj bude slobodan. Ovaj problem može da ilustruje nastanak deadlock-a. Slika 2.7 prikazuje ovaj problem. Slika 2.7. Ilustracija problema pet filozofa 44

50 Poglavlje 3 GUI aplikacije i JavaBeans 3.1 AWT i Swing Programski jezik Java je, u svojoj inicijalnoj verziji, posedovao biblioteku komponenti za izgradnju grafičkog korisničkog interfejsa (GUI) zvanu Abstract Window Toolkit (AWT). U pitanju je biblioteka koja se zasniva na korišćenju komponenti korisničkog interfejsa koje su dostupne na platformi na kojoj se program pokreće (Windows, Motif, Macintosh, itd). To znači da je implementacija AWT komponenti različita za svaki operativni sistem. Java klase koje predstavljaju AWT komponente koriste su u velikoj meri native programski kod koji je vršio interakciju sa operativnim sistemom. Na primer, AWT klase u Windows distribuciji Java virtuelne mašine koriste awt.dll datoteku. Aplikacije koje koriste AWT komponente izgledaju kao da su pisane u bilo kom drugom jeziku na datom operativnom sistemu. Ovakav koncept ima za posledicu da je za skup GUI komponenti bilo neophodno izabrati samo one komponente koje postoje u svim operativnim sistemima na kojima će se Java programi izvršavati. To dalje znači da je ovakav skup komponenti vrlo siromašan. Umesto da se postigne cilj da Java GUI aplikacije izgledaju jednako kao i sve druge aplikacije, postiglo se da one izgledaju jednako osrednje na svim platformama zbog siromašnog skupa komponenti od kojih mogu biti sačinjene. U vreme kada je bila aktuelna Java verzija 1.1, počet je razvoj na novoj biblioteci GUI koponenti koja je imala drugačiji koncept: kompletna biblioteka je napisana u Javi, što znači da se komponente samostalno iscrtavaju na ekranu umesto da ih iscrtava operativni sistem. Posledica toga je da GUI aplikacije izgledaju isto na svim operativnim sistemima i da nema ograničenja na broj i tip GUI komponenti koje će ući u biblioteku. Naziv biblioteke u toku njenog razvoja bio je Swing, i to ime se zadržalo i kasnije. Biblioteka je zamišljena tako da izgled komponenti na ekranu bude promenljiv, zavisno od izabrane teme (look-and-feel). Tako je u startu implementirano tri look-and-feel modula: Windows (sve komponente izgledaju kao odgovarajuće Windows komponente), Motif (GUI okruženje na UNIX-u) i Metal (izgled svojstven samo Java aplikacijama, i, moguće, nekom budućem Java opera- 45

51 tivnom sistemu). Kasnije su se pojavili look-and-feel dodaci sa Macintosh izgledom, itd. Promena izgleda aplikacije može da se obavi čak i za vreme izvršavanja programa. Iako se Swing biblioteka može koristiti i sa Java verzijom 1.1 (uz dodavanje biblioteke u CLASSPATH), sve mogućnosti biblioteke su dostupne tek od verzije 1.2. Od verzije 1.2 ova biblioteka je proglašena za standard za razvoj korisničkog interfejsa u Java aplikacijama, dok je AWT zadržan zbog kompatibilnosti sa starijim programima. Swing je postao sastavni deo veće biblioteke nazvane Java Foundation Classes (JFC). U ovom praktikumu biće reči isključivo o Swing komponentama. 3.2 Event-driven model Kaže se da je kod GUI aplikacija korisnički interfejs upravljan događajima (event-driven). To znači da se program sastoji od relativno nezavisnih segmenata koji su namenjeni za obradu odgovarajućeg događaja (koga je najčešće izazvao korisnik). Na primer, klik mišem, kucanje na tastaturi, itd. su događaji korisničkog interfejsa na koje program reaguje u okviru svojih obrađivača događaja posebnih funkcija pisanih za tu namenu. Event-driven model ima za posledicu da se program sastoji iz određenog inicijalizacionog bloka i raznih obrađivača događaja. Sam program se ne izvršava linearno od gore prema dole nego se izvršava samo u određenim vremenskim intervalima. To su momenti pokretanja aplikacije (kada se vrši inicijalizacija programa) i reakcije na događaje (kada se vrši obrada događaja). Sve ostalo vreme je vreme koje koristi operativni sistem ili druge aplikacije koje rade po istom principu. Inicijalizacioni blok se u Java GUI programima izvršava počevši od metode main, dakle na način koji smo i do sada koristili. Događaji se opisuju tzv. xxxevent klasama. Za svaku vrstu događaja definisana je posebna klasa. Na primer, pritisku na taster odgovara klasa KeyEvent, pomeranju miša odgovara klasa MouseEvent, itd. Sve xxxevent klase nasleđuju klasu Event, slično kao kod raznih exception klasa o kojima je bilo reči u prvom poglavlju. Kada se dogodi neki događaj, kreira se objekat odgovarajuće klase koji opisuje taj događaj, i zatim se taj objekat prosleđuje onima koji su se registrovali da osluškuju taj događaj. Osluškivači događaja su instance neke od xxxlistener klasa. Na primer, osluškivač za KeyEvent događaj je KeyListener, itd. Mehanizam osluškivača je uveden u Java verziji 1.1. Pre toga korišćen je drugačiji mehanizam za obradu događaja čija se upotreba danas ne preporučuje. 3.3 Osnovna struktura GUI aplikacije Svaka Java aplikacija počinje svoje izvršavanje metodom main. Tako i GUI aplikacija počinje svoje izvršavanje ovom metodom, ali se najčešće tom prilikom odmah inicijalizuje i glavni prozor aplikacije koji se potom prikaže na ekranu. 46

52 Sledi primer jedne elementarne GUI aplikacije koja ima main metodu i otvara prozor. public class MyApp { public static void main(string[] args) { MainFrame mf = new MainFrame(); mf.setvisible(true); import javax.swing.*; public class MainFrame extends JFrame { public MainFrame() { setsize(300, 200); settitle("my First GUI App"); Aplikacija se sastoji iz dve klase: klasa MyApp samo sadrži main metodu. U okviru main metode kreira se objekat klase MainFrame (što predstavlja inicijalizaciju glavnog prozora aplikacije) i zatim se taj prozor prikaže na ekranu (poziv metode setvisible). Klasa MainFrame nasleđuje klasu JFrame, što je standardan način za definisanje novih prozora. Klasa JFrame je deo Swing biblioteke smeštene u paket javax.swing. Komponente Swing korisničkog interfejsa po pravilu počinju velikim slovom J. U okviru konstruktora klase MainFrame se postavlja veličina prozora u pikselima (setsize) i naslov prozora (settitle). 3.4 Razlika u konstrukciji GUI-ja za Windows i Java aplikacije Operativni sistem Windows koristi tzv. resurse za opis izgleda elemenata korisničkog interfejsa. Resurs je, zapravo, deklarativni opis izgleda nekog elementa korisničkog interfejsa. Takav opis se može formirati u tekstualnoj datoteci odgovarajućeg formata, ali se može i nacrtati primenom odgovarajućeg alata. Tzv. vizuelna okruženja za razvoj softvera su i zamišljena tako da omoguće programeru da nacrta izgled svoje aplikacije. Crtanje aplikacije u Windows okruženju predstavlja definisanje resursa. Tim resursima (dugmadima, tekstualnim poljima, itd.) se kasnije mogu pridružiti programski elementi preko kojih će se odvijati pristup resursima (to, na primer, radi Class Wizard u paketu Visual C++). U programskom jeziku Java (i nekim drugim prozorskim operativnim sistemima) izgled korisničkog interfejsa se ne definiše deklarativno, pomoću resursa, nego programski: komponente interfejsa se nanose na prozor u određenom segmentu programa (tipično u konstruktoru prozorske klase) pozivima odgovarajućih metoda. 3.5 Dodavanje komponenti na prozor Pogledajmo sledeći primer: import java.awt.*; 47

53 import javax.swing.*; public class MainFrame extends JFrame { public MainFrame() { setsize(300, 200); settitle("my Second GUI App"); // dodajemo komponente na formu: getcontentpane().add(bok, BorderLayout.NORTH); getcontentpane().add(bcancel, BorderLayout.SOUTH); // elementi na formi su najčešće privatni atributi klase private JButton bok = new JButton("OK"); private JButton bcancel = new JButton("Cancel"); Prozoru iz prethodnog primera dodata su dva dugmeta, predstavljena klasom JButton. Ovakve komponente korisničkog interfejsa najčešće se definišu kao atributi prozorske klase, u ovom slučaju MainFrame. U konstruktoru je dodato postavljanje komponenti na prozor pozivi metode add. Jedan od osnovnih principa Swing biblioteke je da se komponente mogu smestiti samo unutar nekog kontejnera objekta koji je namenjen za prihvat komponenti. Svaki prozor već ima svoj kontejner, koga možemo dobiti pozivom metode getcontentpane. Slika 3.1 prikazuje izgled ove aplikacije. Klasa MyApp je preuzeta iz prethodnog primera. Slika 3.1. Elementarna GUI aplikacija 3.6 Prostorni raspored komponenti U prethodnom primeru vidi se da su dva dugmeta postavljena na prozor u toku inicijalizacije (u konstruktoru), ali nigde nije eksplicitno specificirano bar na prvi pogled gde će stojati i kako će izgledati, kakve će im biti dimenzije, itd. Za određivanje ovih karakteristika komponente zadužen je objekat koji se naziva layout manager. U pitanju je instanca neke od xxxlayout klasa. Svaki kontejner ima sebi asociran layout manager. Podrazumevani layout manager je objekat klase BorderLayout. On raspoređuje komponente u okviru kontejnera u zone koje izgledaju kao na slici 3.2. NORTH WEST CENTER EAST SOUTH 48

54 Slika 3.2. Zone BorderLayout manager-a Različiti layout manager-i će iste komponente raspoređivati na različit način, zavisno od sopstvenog algoritma raspoređivanja. Sledeći primer prikazuje upotrebu raznih layout manager-a u istom prozoru. import java.awt.*; import javax.swing.*; public class MainFrame extends JFrame { public MainFrame() { setsize(300, 200); settitle("my Second GUI App"); // biramo layout manager: getcontentpane().setlayout(new FlowLayout()); //getcontentpane().setlayout(new BorderLayout()); //getcontentpane().setlayout(new GridLayout(3, 3)); getcontentpane().add(bok, BorderLayout.NORTH); getcontentpane().add(bcancel, BorderLayout.SOUTH); private JButton bok = new JButton("OK"); private JButton bcancel = new JButton("Cancel"); Kada se ovaj primer pokrene sa korišćenjem FlowLayout manager-a dobiće se prozor čije su varijante prikazane na slici 3.3. a) b) Slika 3.3. Primer korišćenja FlowLayout manager-a Sa slike 3.3 se vidi da FlowLayout raspoređuje komponente sleva na desno, dajući im neku podrazumevanu veličinu. Kada se prvi red sa komponentama popuni (što zavisi od širine prozora i broja i oblika komponenti) prelazi se u sledeći red i tako dalje. Layout manager mehanizam se koristi kako u Swing, tako i u AWT biblioteci. Odgovarajuće xxxlayout klase zato se nalaze u starijem paketu java.awt (odatle prva import deklaracija). Komponenta JPanel je zanimljiva po tome što ona predstavlja i komponentu i kontejner istovremeno. Korišćenjem ove komponente mogu se dobiti složeni rasporedi komponenti na formi. Zanimljivo je, međutim, da osnovni skup layout manager-a ne obuhvata nijedan koji omogućava postavljanje komponenti na prozor na način kako su to navikli Windows programeri postavljanjem komponente na tačno određeno mesto na 49

55 prozoru, određeno koordinatama datim u pikselima. Kompajler Borland JBuilder ima u svojoj biblioteci upravo takav layout manager, zvani XYLayout. Sledi primer njegove upotrebe u klasi MainFrame: import java.awt.*; import javax.swing.*; import com.borland.jbcl.layout.*; public class MainFrame extends JFrame { public MainFrame() { setsize(300, 200); settitle("my Second GUI App"); // biramo layout manager: getcontentpane().setlayout(new XYLayout()); // dodajemo komponente na formu: getcontentpane().add(bok, new XYConstraints(10, 10, 100, -1)); getcontentpane().add(bcancel, new XYConstraints(10, 50, 100, -1)); private JButton bok = new JButton("OK"); private JButton bcancel = new JButton("Cancel"); Slika 3.4 predstavlja izgled ovakve aplikacije u dve varijante veličine prozora. a) b) Slika 3.4. Primer korišćenja Borland-ovog XYLayout manager-a 3.7 Rukovanje događajima Događaji, osluškivači i komponente U odeljku 3.2 već je bilo reči o rukovanju događajima. Da podsetimo, događaji su predstavljeni objektima xxxevent klasa, a osluškivači događaja su odgovarajući xxxlistener objekti. xxxlistener-i su, zapravo, interfejsi: osluškivač mora biti instanca neke klase koja implementira taj interfejs. Na primer, klasa koja implementira ActionListener interfejs može da posluži kao obrađivač događaja za klik mišem na dugme. Sledi jedna takva klasa: import java.awt.*; import java.awt.event.*; public class MyListener implements ActionListener { public void actionperformed(actionevent ev) { System.exit(0); 50

56 Interfejs ActionListener definiše jednu metodu, actionperformed. Njen parametar je objekat klase ActionEvent koji bliže opisuje događaj. U prikazanom primeru osluškivač će, kada se događaj dogodi, zatvoriti aplikaciju (metoda exit). Listener mehanizam se koristi kako u Swing, tako i u AWT biblioteci tako da su svi događaji definisani u starijim paketima java.awt i java.awt.event. Osluškivač događaja (instanca neke Listener klase) se pridružuje onoj komponenti korisničkog interfejsa za koju želimo da reaguje na taj događaj. To pridruživanje se obavlja metodom addxxxlistener koju ima komponenta. Sledi primer MainFrame klase iz prethodnih primera koja je modifikovana tako što je dugmadima dodat prethodno prikazani osluškivač. import java.awt.*; import java.awt.event.*; import javax.swing.*; public class MainFrame extends JFrame { public MainFrame() { setsize(300, 200); settitle("my Second GUI App"); getcontentpane().setlayout(new FlowLayout()); getcontentpane().add(bok); getcontentpane().add(bcancel); // dodajemo reakcije na dogadjaje dugmadima bok.addactionlistener(new MyListener()); bcancel.addactionlistener(new MyListener()); private JButton bok = new JButton("OK"); private JButton bcancel = new JButton("Cancel"); Ovakav prozor sadrži dva dugmeta koja će, na klik mišem, reagovati na isti način koriste isti Listener zatvaranjem aplikacije. (Ovo morate probati praktično, slika ne pomaže puno) Osluškivači kao unutrašnje klase Prozori često znaju biti pretrpani komponentama koje, sa svoje strane, obrađuju više vrsta događaja. Rezultat može biti jedna prozorska klasa koja sadrži par desetina komponenti, i nekoliko desetina Listener klasa. Definisati pedesetak Listener klasa samo za jedan prozor može učiniti program nepreglednim. Zato se Listener klase najčešće definišu kao unutrašnje klase u okviru prozorske klase. Posmatrajmo sledeći segment programskog koda: ActionListener a = new ActionListener() { public void actionperformed(actionevent ev) { System.exit(0); ); U pitanju je definicija reference a na objekat klase koja implementira ActionListener interfejs. Ime klase nigde nije navedeno! Samim tim, ne možemo 51

57 konstruisati još jedan objekat ove klase. Sve što nam je iz ove komplikovane konstrukcije potrebno je referenca na objekat, koju možemo iskoristiti na sledeći način: bcancel.addactionlistener(a); Time smo definisali Listener klasu i njenu instancu (osluškivač) pridružili dugmetu bcancel. Ove dve operacije (kreiranje osluškivača i njegovo pridruživanje dugmetu) se mogu obaviti jednim iskazom: bcancel.addactionlistener(new ActionListener() { public void actionperformed(actionevent ev) { System.exit(0); ); Upravo je ovaj poslednji način i najčešće korišćeni način za definisanje osluškivača (ovakve iskaze koriste i alati poput Borland JBuilder-a kada generišu kod). Njegova komplikovana sintaksa traži malo navikavanja, ali je kudikamo preglednija od desetina odvojenih datoteka u kojima se nalaze definicije osluškivača onako kako je to u prvom primeru prikazano. Sledeći primer predstavlja prozor sa dva dugmeta, od kojih dugme Cancel zatvara aplikaciju, a klik na dugme OK menja boju samog dugmeta slučajnim izborom. import java.awt.*; import java.awt.event.*; import javax.swing.*; public class MainFrame extends JFrame { public MainFrame() { setsize(300, 200); settitle("my Second GUI App"); getcontentpane().setlayout(new FlowLayout()); getcontentpane().add(bok); getcontentpane().add(bcancel); // dodajemo reakcije na dogadjaje dugmadima bok.addactionlistener(new ActionListener() { public void actionperformed(actionevent ev) { int r = (int)math.round(math.random()*256); int g = (int)math.round(math.random()*256); int b = (int)math.round(math.random()*256); bok.setbackground(new Color(r, g, b)); ); bcancel.addactionlistener(new ActionListener() { public void actionperformed(actionevent ev) { System.exit(0); ); private JButton bok = new JButton("OK"); private JButton bcancel = new JButton("Cancel"); 52

58 3.8 Primeri korišćenja standardnih komponenti U prethodnim primerima korišćena je komponenta dugme i događaj klik na dugme (predstavljeni klasama JButton i ActionEvent). Biblioteka sadrži veliki broj komponenti za izgradnju korisničkog interfejsa i veliki broj događaja na koje se može reagovati. Neke od najčešće korišćenih komponenti su pobrojane u tabeli 3.1. Klasa ButtonGroup JButton JCheckBox JComboBox JDialog JFrame JLabel JList JMenu JMenuBar JMenuItem JOptionPane JPanel JRadioButton JTabbedPane JTextArea JTextField Opis povezuje više radio button-a da rade zajedno; nije vidljiva komponenta dugme check box combo box dijalog (prozor kome se ne može menjati veličina) prozor labela list box meni linija menija stavka menija prozor koji ispisuje kraću poruku (message box) komponenta koja je kontejner za druge komponente radio button kartice (tabs); pojedine kartice se na ovu komponentu dodaju kao JPanel-i višelinijsko polje za unos teksta (memo) jednolinijsko polje za unos teksta Tabela 3.1. Najčešće korišćene GUI komponente Na isti način na koji je dugme u prethodnim primerima reagovalo na klik mišem, može se dodati osluškivač neke druge vrste događaja nekoj komponenti. Tabela 3.2 prikazuje najčešće korišćene događaje i odgovarajuće Listener-e. Tip događaja ActionEvent AdjustmentEvent ComponentEvent ContainerEvent FocusEvent KeyEvent MouseEvent WindowEvent ItemEvent TextEvent Odgovarajući listener ActionListener AdjustmentListener ComponentListener ContainerListener FocusListener KeyListener MouseListener WindowListener ItemListener TextListener Tabela 3.2. Tipovi događaja i odgovarajući listener-i U narednih nekoliko primera biće ilustrovana upotreba različitih komponenti korisničkog interfejsa i reakcije na događaje vezane za te komponente. Prvi primer ilustruje reagovanje na pritisnut taster (KeyEvent) u tekstualnom polju za unos (JTextField). Komponenta za unos teksta tf ima svog osluškivača događaja, objekat klase Reakcija. Klasa Reakcija ne implementira interfejs KeyListener, što bismo očekivali, već nasleđuje klasu KeyAdapter. Radi se o tome da interfejs KeyListener definiše više metoda za obradu događaja (keypressed, 53

59 keyreleased, itd). Kako želimo da reagujemo samo na jednu vrstu događaja otpušten taster, tj. keyreleased, želimo da redefinišemo samo tu metodu. Pošto implementiranje interfejsa obavezuje implementiranje svih njegovih metoda, morali bismo da napišemo i nekoliko metoda sa praznim telom, da bismo zadovoljili formu. Klasa KeyAdapter nam rešava taj problem, jer ona implementira interfejs KeyAdapter na takav način da su joj sve metode prazne. Tako ćemo nasleđivanjem klase KeyAdapter i redefinisanjem samo onih metoda koje su nam potrebne uštedeti nešto kodiranja i doprineti preglednosti programskog koda. Prilikom otpuštanja pritisnutog tastera dok je fokus na tf komponenti, poziva se osluškivač klase Reakcija. Ukoliko je pritisnut taster A, tekst labele l se menja u Pritisnuo taster a, a inače se menja u Tekst. import java.awt.*; import java.awt.event.*; import javax.swing.*; public class JTextFieldTest extends JFrame { public JTextFieldTest() { setsize(400, 200); settitle("component test"); getcontentpane().setlayout(new FlowLayout()); getcontentpane().add(l); getcontentpane().add(tf); tf.addkeylistener(new Reakcija()); /** Rukovalac dogadjajima definisan kao inner klasa */ class Reakcija extends KeyAdapter { public void keyreleased(keyevent e) { if(e.getkeycode() == KeyEvent.VK_A) l.settext("pritisnuo taster a"); else l.settext("tekst"); JTextField tf = new JTextField(30); JLabel l = new JLabel("Tekst"); Sledeći primer predstavlja mogućnost obrade događaja pomeranja kursora unutar tekstualnog polja. Kursor se može pomeriti kucanjem teksta, brisanjem teksta, strelicama za kretanje po tekstu, itd. Prilikom pomeranja kursora (CaretEvent) u gornjem JTextArea polju, novi položaj kursora se upisuje kao sadržaj donjeg JTextArea polja. Za osluškivanje ovakvog događaja potrebno je implementirati CaretListener interfejs. Metoda koja se poziva prilikom pomeranja kursora je caretupdate. CaretEvent klasa koja predstavlja događaj ima metodu getdot koja vraća novi položaj kursora. import java.awt.*; import javax.swing.event.*; import javax.swing.*; 54

60 public class JTextAreaTest extends JFrame { public JTextAreaTest() { setsize(400, 300); Container cp = getcontentpane(); cp.setlayout(new FlowLayout()); ta1 = new JTextArea("Tekst1", 5, 30); ta1.addcaretlistener(new Reakcija()); cp.add(ta1); ta2 = new JTextArea("Tekst2", 5, 30); cp.add(ta2); class Reakcija implements CaretListener { public void caretupdate(caretevent e) { ta2.settext("" + e.getdot()); JTextArea ta1; JTextArea ta2; Naredni primer demonstrira reagovanje na događaj izbora stavke (ItemEvent) u check box polju (JCheckBox) i radio button polju (JRadioButton). Interfejs koji treba implementirati je ItemListener, metoda koja se poziva prilikom događaja je itemstatechanged, a metoda getitem klase ItemEvent vraća referencu na onaj objekat tj. komponentu kojoj je stavka izabrana. Prilikom izbora stavke labeli l se menja tekst u Odabrao stavku: + <tekst komponente na koju je kliknuto>. Da bi dva radio button-a radila u paru, tj. da bi selekcija jednog izazvala deselekciju drugog, potrebno je staviti ih u istu grupu, tj. ButtonGroup objekat. Metoda add klase ButtonGroup služi za dodavanje komponenti u grupu. import java.awt.*; import java.awt.event.*; import javax.swing.*; public class JCheckBoxTest extends JFrame { public JCheckBoxTest() { setsize(500, 200); Container cp = getcontentpane(); cp.setlayout(new FlowLayout()); l = new JLabel("Tekst"); cp.add(cb1); group.add(rb1); // dodajemo radio button-e u grupu group.add(rb2); // kako bi radili u paru cp.add(rb1); cp.add(rb2); cb1.additemlistener(new Reakcija()); Reakcija r = new Reakcija(); rb1.additemlistener(r); rb2.additemlistener(r); 55

61 cp.add(l); class Reakcija implements ItemListener { public void itemstatechanged(itemevent e) { l.settext("odabrao stavku: " + ((AbstractButton)e.getItem()).getText()); JCheckBox cb1 = new JCheckBox("CheckBox1"); ButtonGroup group = new ButtonGroup(); JRadioButton rb1 = new JRadioButton("RadioButton1", true); JRadioButton rb2 = new JRadioButton("RadioButton2", false); JLabel l; Poslednji primer u ovom odeljku ilustruje reagovanje na događaj izbora stavke (ItemEvent) u combo box-u (JComboBox). Primer je sličan prethodnom, sa malom razlikom što se u metodi itemstatechanged koristi metoda getsource klase ItemEvent koja vraća objekat koji je izvor događaja. Proverava se da li je taj objekat instanca klase JComboBox, i ako jeste tekst labele l se postavlja na izabrani tekst u combo box-u. Stavka combo box-a koja je izabrana se može dobiti pozivom metode getselecteditem klase JComboBox. import java.awt.*; import java.awt.event.*; import javax.swing.*; public class JComboBoxTest extends JFrame { public JComboBoxTest() { setsize(500, 200); // napuni combo box stavkama for (int i = 0; i < items.length; i++) c.additem(items[i]); c.additemlistener(new Reakcija()); Container cp = getcontentpane(); cp.setlayout(new FlowLayout()); cp.add(c); cp.add(l); class Reakcija implements ItemListener { public void itemstatechanged(itemevent e) { if (e.getsource() instanceof JComboBox) l.settext((string)c.getselecteditem()); String[] items = {"Prva opcija", "Druga opcija", "Treca opcija"; JComboBox c = new JComboBox(); JLabel l = new JLabel("Labela"); 56

62 Ispitivanje da li je izvor događaja instanca klase JComboBox u prethodnom primeru je ilustracija kako se jedan osluškivač događaja može upotrebiti za obradu događaja koji potiču od različitih komponenti korisničkog interfejsa. 3.9 Apleti Pojam apleta Apleti su posebna vrsta Java programa koji su namenjeni za ugrađivanje u HTML stranice. U okviru stranice aplet dobija na raspolaganje određenu pravougaonu površinu čije su dimenzije date u pikselima. U tom smislu, aplet se u HTML stranicu ugrađuje na sličan način kao i slika. Kada Web čitač pristupi stranici koja sadrži aplet, automatski će preuzeti i programski kod apleta (prevedene Java klase), pokrenuti Java virtuelnu mašinu i početi izvršavanje apleta. Aplet je Java program koji na raspolaganju ima gotovo sve mogućnosti klasičnih Java aplikacija, izuzev dva bitna ograničenja, uvedena iz bezbednosnih razloga: apleti ne mogu da pristupe fajl-sistemu računara na kome se izvršavaju; apleti ne mogu da uspostave mrežnu konekciju sa bilo kojim računarom osim sa Web serverom sa koga su preuzeti. Aplet je zapravo klasa koja nasleđuje klasu Applet (za AWT) ili JApplet (za Swing). Pisanje apleta svodi se na nasleđivanje klase JApplet i implementiranje odgovarajućih metoda. Neke od najvažnijih metoda pobrojane su ovde: init: poziva je Web čitač prilikom učitavanja apleta u JVM Web čitača destroy: poziva je Web čitač prilikom uklanjanja apleta iz JVM Web čitača; obično se koristi za oslobađanje zauzetih resursa (npr. zaustavljanje niti ili zatvaranje mrežne konekcije) start: poziva je Web čitač kada hoće da naznači da aplet treba da počne sa svojim izvršavanjem stop: analogno prethodnom, poziva je Web čitač kada aplet treba da prekine sa svojim izvršavanjem paint: poziva je Web čitač kada je potrebno da aplet iscrta svoj sadržaj Pogledajmo primer jednog elementarnog apleta: import java.awt.*; import javax.swing.*; public class AppletTest extends JApplet { public void init() { getcontentpane().add(new JLabel("Applet!")); 57

63 Aplet klasa se zove AppletTest, nasleđuje klasu JApplet i redefiniše metodu init. U okviru init metode vrši se inicijalizacija apleta: u ovom slučaju to se svodi na postavljanje jedne labele na površinu apleta. Aplet nema metodu main, tako da ga ne možemo pokrenuti na do sada poznat način iz komandne linije. Potrebno je ovakav aplet ugraditi u HTML stranicu u okviru koje će biti prikazan. Sledi primer ovakve HTML stranice. <html> <head> <title>test stranica sa apletom</title> </head> <body> <applet code = "AppletTest" width = 100 height = 50> </applet> </body> </html> Ugrađivanje apleta u stranicu se postiže tagom applet. Njegovi atributi su code (naziv aplet klase), width (širina apleta u pikselima) i height (visina apleta u pikselima). Ovakva stranica, kada se otvori u Web čitaču, izgleda kao na slici 3.5. Slika 3.5. Aplet prikazan u okviru HTML stranice Web čitači i Java Plug-In Kada Web čitač prilikom analize HTML stranice koju je preuzeo naiđe na applet tag, vrši inicijalizaciju svoje Java virtuelne mašine, preuzima aplet i pokreće ga. To znači da se aplet izvršava u okviru JVM koja pripada Web čitaču. Današnji Web čitači većinom imaju svoje JVM, ali je njihova kompatibilnost sa standardnom JVM problematična. Naime, Internet Explorer (u verzijama do 5.5) i Netscape Navigator (u verzijama do 4.7) poseduju virtuelne mašine koje odgovaraju Java verziji 1.1, i čak nemaju sve mogućnosti koje verzija 1.1 definiše. Najuočljiviji nedostatak je izostanak podrške za Swing biblioteku. Da bi apleti koji koriste Swing bili upotrebljivi u okviru ovih Web čitača, Sun je izdao Java 1.2 Plug-In za te čitače. Radi se o klasičnim plug-in dodacima za Netscape Navigator i Internet Explorer, slično kao što se koristi Macromedia Flash plug-in. Namena tog plug-ina je da zameni osnovnu virtuelnu mašinu Web čitača svojom, koja je u potpunosti kompatibilna sa Java verzijom

64 Instalacija ovog plug-ina se odvija automatski prilikom instaliranja paketa JDK ili JRE (Java Runtime Environment, samo Java interpeter, bez razvojnih alata). Sama instalacija nije dovoljna da bi se plug-in zaista i koristio. Naime, kada Web čitač, analizirajući HTML stranicu, naiđe na applet tag, on će ponovo pokrenuti svoju JVM umesto nove koju je instalirao plug-in. Ugrađivanje plugina u stranicu se razlikuje od ugrađivanja apleta, po tome što se koristi object tag (za Internet Explorer), odnosno embed tag (za Netscape Navigator). Sledeći primer prikazuje HTML stranicu koja sadrži aplet iz prethodnog primera, samo što se umesto podrazumevane JVM Web čitača koristi instalirani Java 1.2 plug-in. <html> <head> <title>applet1</title> </head> <body> <OBJECT classid="clsid:8ad9c e-11d1-b3e f499d93" width="100" height="50" align="baseline" codebase=" jinstall-1_2_2-win.cab#version=1,2,2,0"> <PARAM NAME="code" VALUE="AppletTest.class"> <PARAM NAME="codebase" VALUE="."> <PARAM NAME="type" VALUE="application/x-java-applet;version=1.2.2"> <COMMENT> <EMBED type="application/x-java-applet;version=1.2.2" width="100" height="50" align="baseline" code="applettest.class" codebase="." pluginspage=" products/plugin/1.2/plugin-install.html"> <NOEMBED> No Java 2 support for APPLET!! </NOEMBED> </EMBED> </COMMENT> </OBJECT> </body> </html> Iako je u pitanju prilično komplikovana HTML konstrukcija, ona se ponaša kao applet tag. Crvenom bojom su naznačeni elementi koji su promenljivi to su naziv aplet klase, širina i visina apleta. Sve ostale parametre ne treba menjati. Ostali parametri, između ostalog, specificiraju Web čitaču kako automatski instalirati plug-in ako on nije već instaliran, i navode adesu na JavaSoft Web sajtu gde se plug-in može naći. Dokle god savremene verzije čitača ne budu posedovale svoje JVM u verziji 1.2, primorani smo da koristimo Java 1.2 plug-in na ovakav način. Svi naredni primeri apleta koriste ovaj plug-in u svojim HTML stranicama Apleti i komponente korisničkog interfejsa Naredni primer prikazuje aplet koji na svojoj površini sadrži jedno dugme. import java.awt.*; 59

65 import javax.swing.*; public class JButtonTest extends JApplet { JButton b; public void init() { b = new JButton("Pritisni me"); Container cp = getcontentpane(); cp.add(b); Iz primera vidimo da se postavljanje komponenti na površinu apleta ni po čemu ne razlikuje od postavljanja komponenti na prozor klasične aplikacije. Za raspoređivanje komponenti koristi se mehanizam layout manager-a. Sledeći primer predstavlja proširenje prethodnog primera, u smislu da je dugmetu dodat osluškivač događaja za klik mišem (ActionEvent). Aplet sadrži i jednu labelu čiji se tekst menja kada se klikne na dugme. import java.awt.*; import java.awt.event.*; import javax.swing.*; public class JButtonTest2 extends JApplet { JButton b; JLabel l; public void init() { Container cp = getcontentpane(); cp.setlayout(new FlowLayout()); l = new JLabel("Tekst u labeli"); cp.add(l); b = new JButton("Pritisni me"); b.addactionlistener(new Reakcija()); cp.add(b); class Reakcija implements ActionListener { public void actionperformed(actionevent e) { l.settext("pritisnuo dugme"); Iz ovog primera vidimo da je rukovanje događajima identično kao u aplikacijama Aplet i aplikacija istovremeno Iz prethodnih primera smo videli da je raspoređivanje komponenti na aplet i rukovanje događajima identično kao i kod klasičnih grafičkih aplikacija. Zato i nema puno tehničkih razlika u razvoju aplikacije i apleta. Sada sledi primer kako napisati program koji može biti i aplet i aplikacija, zavisno od toga na koji način se pokrene. Pošto je u pitanju aplet, osnovna klasa mora naslediti klasu JApplet. A kako je u pitanju i aplikacija, dodaćemo ovoj klasi metodu main. import java.awt.*; import java.awt.event.*; import javax.swing.*; public class AppletApplicationTest extends JApplet { 60

66 public void init() { getcontentpane().add(new JLabel("Aplet i aplikacija!")); static class WL extends WindowAdapter { AppletApplicationTest a; public WL(AppletApplicationTest a) { super(); this.a = a; public void windowclosing(windowevent e) { a.stop(); a.destroy(); System.exit(0); public static void main(string args[]) { JFrame f = new JFrame("AppletApplicationTest"); AppletApplicationTest a = new AppletApplicationTest(); f.addwindowlistener(new WL(a)); a.init(); a.start(); f.getcontentpane().add(a, BorderLayout.CENTER); f.setsize(300, 200); f.setvisible(true); Posmatrajmo metodu main ove aplikacije. Vidimo da se u njoj kreira novi prozor klase JFrame, a zatim se kreira i aplet objekat. Prozoru se doda osluškivač događaja za zatvaranje prozora klikom na dugme close ( ). Dalje, poziva se metoda init apleta, a zatim i metoda start. Na ovaj način aplikacija simulira Web čitač prilikom pokretanja apleta. Aplet se postavlja na sredinu prozora, postave se dimenzije prozora i on se prikaže. Suština se ovde nalazi u inicijalizaciji apleta (metode init i start) i njegovom postavljanju na prozor aplikacije. Na taj način aplet će biti prikazan u osnovnom prozoru aplikacije i imaćemo utisak da je u pitanju klasična GUI aplikacija. Klikom na dugme close zatvara se aplikacija. Pri tome, potrebno je ponovo simulirati Web čitač: pozivaju se metode stop i destroy našeg apleta. Dakle, možemo da zaključimo da je omogućavanje apletu da se koristi i kao aplikacija vrlo jednostavno: svodi se na dodavanje metode main i jednog osluškivača događaja. Sadržaj metode main i obrada događaja se praktično i ne menjaju, tako da se ovaj segment koda može kopirati u sve slične programe Korisnički definisane komponente Swing biblioteka obezbeđuje relativno bogat izbor komponenti za izgradnju korisničkog interfejsa, ali to ponekad ne mora biti dovoljno. Pisanje novih komponenti koje će imati neke specifične mogućnosti je relativno jednostavno. Potrebno je naslediti neku od postojećih komponenti i redefinisati potrebne 61

67 metode. Ako nijedna konkretna komponenta nije adekvatna za ovakvo nasleđivanje, može se koristiti generiška komponenta JComponent. Sledi primer jedne korisnički definisane komponente koja predstavlja labelu uokvirenu tankom linijom. import java.awt.*; import javax.swing.*; public class UserDefined extends JComponent { public UserDefined(String text) { this.text = text; /** Iscrtava komponentu */ public void paint(graphics g) { Dimension s = getsize(); g.setcolor(color.black); g.drawrect(0, 0, s.width - 1, s.height - 1); g.drawstring(text, 0, 10); /** Vraća poželjnu veličinu komponente */ public Dimension getpreferredsize() { int width = 70, height = 20; Graphics g = getgraphics(); FontMetrics fm = null; if (g!= null) fm = g.getfontmetrics(); if (fm!= null) { width = fm.stringwidth(text); height = fm.getheight(); return new Dimension(width, height); /** Tekst koji se ispisuje */ private String text; U primeru se vidi da je nasleđena klasa JComponent. Redefinisane su dve njene metode, paint i getpreferredsize. Metoda paint se poziva kad god je potrebno da se komponenta iscrta (prilikom pomeranja prozora, preklapanja prozora, itd). Nju poziva Swing okruženje. Samo crtanje se obavlja koristeći objekat klase Graphics, koji ima veliki broj metoda za crtanje. U okviru ove metode postavlja se crna boja kao tekuća boja za crtanje, iscrtava se pravougaonik oko ivica komponente, i unutar njega se ispisuje dati tekst. Metoda getpreferredsize vraća dimenzije koje bi komponenta volela da ima. Ovu metodu će pozivati layout manager prilikom raspoređivanja komponenti na prozor. Izračunavanje ove poželjne veličine komponente se vrši na osnovu dimenzija koje će zauzimati tekst kada se ispiše. Ovako definisana komponenta koristi se u aplikacijama i apletima na isti način kao i komponente iz biblioteke. Sledi primer apleta koji koristi prethodno 62

68 definisanu komponentu. Komponente se konstruišu i dodaju na površinu apleta na uobičajen način. import java.awt.*; import javax.swing.*; public class UserDefinedTest extends JApplet { public void init() { Container cp = getcontentpane(); cp.setlayout(new FlowLayout()); cp.add(u1); cp.add(u2); UserDefined u1 = new UserDefined("Tekst u komponenti br. 1"); UserDefined u2 = new UserDefined("Tekst u komponenti br. 2"); Slika 3.6 prikazuje izgled ovog apleta. Slika 3.6. Aplet sa korisnički definisanim komponentama 3.12 JavaBeans JavaBeans je standard za kreiranje softverskih komponenti koje imaju svoje osobine i ponašanje i koje se mogu koristiti u okviru RAD (Rapid Application Development) alata kao što su Borland JBuilder, Symantec Visual Café, itd. Svaka JavaBean komponenta ima svoja svojstva (properties) i reaguje na neke događaje (events). Formalno posmatrano, JavaBean je svaka Java klasa za koju važi: 1. Ima podrazumevani konstruktor (konstruktor bez parametara koji je public). 2. Za svako svojstvo koji se zove xxx moraju da postoje public metode setxxx i getxxx (obratite pažnju na odnos velikih i malih slova!). Atribut klase koji bi sadržao vrednost tog svojstva nije obavezan! 3. Za svaki događaj predstavljen klasom xxxevent na koji komponenta može da reaguje, moraju da postoje metode addxxxlistener(xxxlistener) i removexxxlistener(xxxlistener). 63

69 Modifikujmo sada komponentu UserDefined prikazanu u prethodnom primeru tako da postane JavaBean. Umesto konstruktora koji prima parametre, ovde je sada podrazumevani konstruktor. Tekst koji se ispisuje u okviru komponente opisaćemo property-jem text. To znači da klasa mora posedovati metode settext i gettext. Kako naša komponenta već nasleđuje JComponent, nasleđuje više addxxxlistener/removexxxlistener metoda. Među njima su i addmouselistener i removexxxlistener koje omogućavaju reagovanje na događaje izazvane mišem. import java.awt.*; import java.awt.event.*; import javax.swing.*; public class UserDefinedBean extends JComponent { public UserDefinedBean() { public void settext(string s) { text = s; public String gettext() { return text; public void paint(graphics g) { Dimension s = getsize(); g.setcolor(color.black); g.drawrect(0, 0, s.width - 1, s.height - 1); g.drawstring(text, 2, 12); public Dimension getpreferredsize() { int width = 70, height = 20; Graphics g = getgraphics(); FontMetrics fm = null; if (g!= null) fm = g.getfontmetrics(); if (fm!= null) { width = fm.stringwidth(text); height = fm.getheight(); return new Dimension(width + 5, height + 2); /** Ovde čuvamo property text */ private String text = "text1"; Kada ovakvu komponentu upotrebimo u okviru RAD alata kakav je JBuilder, on će biti u stanju da prepozna svojstva i događaje ove komponente i omogući nam da ih podešavamo u vreme pisanja aplikacije (design-time). Slika 3.6a prikazuje svojstva koja je JBuilder otkrio u našoj komponenti, a slika 3.6b prikazuje događaje na koje naša komponenta može da reaguje. Vidimo da se u spisuku property-ja nalazi i text, koji smo sami definisali. Ostali property-ji su nasleđeni iz klase JComponent. 64

70 a) b) Slika 3.6. Svojstva i događaji komponente u JBuilder-u JBuilder ne koristi nikakve posebne tehnike za otkrivanje svojstava i događaja u komponentama. Naprotiv, koristi standardan introspection mehanizam da otkrije te informacije. Ovaj mehanizam implementiran je u klasi java.beans. Introspector. Na kraju, sam JBuilder je pisan u Javi, tako da je prirodno da koristi mehanizme koje obezbeđuje Java platforma! 65

71 Poglavlje 4 Mrežno programiranje u Javi 4.1 Osnovne karakteristike Pod mrežnim programiranjem u programskom jeziku Java podrazumeva se pisanje programa koji komuniciraju sa drugim programima preko računarske mreže. Zahvaljujući konceptu prenosivog izvršnog koda, pisanje ovakvih programa je istovetno na različitim hardversko/softverskim platformama. Komunikacija putem računarske mreže u Java programima podrazumeva korišćenje IP mrežnog protokola. Drugi protokoli protokoli (npr. Novell IPX) nisu podržani. Standardna Java biblioteka poseduje klase za komunikaciju preko ovakve mreže korišćenjem TCP i UDP protokola. Ovde će biti reči samo o komunikaciji putem TCP protokola. Komuniciranje između dve mašine odvija se putem tokova (streams): svaka konekcija između dva programa je dvosmerna za svakog od njih, u smislu da oba programa koji učestvuju u konekciji koriste stream za čitanje i stream za pisanje. Stream-ovi se koriste na isti način kao što se koriste prilikom rada sa datotekama u okviru fajl-sistema. Klase standardne biblioteke namenjene za pristup mrežnim funkcijama nalaze se u paketu java.net, a familija stream klasa koja se takođe koristi nalazi se u paketu java.io Pojam socket-a Za vezu između dva programa na mreži karakterističan je pojam socket-a. Socket zapravo predstavlja uređeni par (IP adresa, port) jednog učesnika u komunikaciji. Uspostavljena veza između dva programa je zapravo skup dva socket-a. Slika 4.1 ilustruje uspostavljenu vezu između dva programa sa stanovišta socket-a. program A program B ( , 7534) ( , 9000) Slika 4.1. Uspostavljena veza između dva programa 66

72 Kada se govori o vezi, govori se o vezi između dva programa, a ne o vezi između dva računara. Dva programa koji učestvuju u vezi mogu se izvršavati i na istom računaru. Sa druge strane, jedan računar može istovremeno izvršavati više programa koji pristupaju mreži. Koncept porta je upravo način da se omogući razlikovanje više programa koji su pokrenuti na istom računaru (tj. na istoj IP adresi) i istovremeno pristupaju mreži. Slika 4.2 ilustruje situaciju kada se na jednom čvoru mreže izvršavaju dva programa, i jedan od njih ima vezu sa dva programa istovremeno. Program A (na čvoru X sa IP adresom ) ima uspostavljenu vezu sa programom B (na čvoru Y). Port koji koristi program A za ovu vezu je 7534, a port koji koristi program B je Program A ima još jednu uspostavljenu vezu, sa programom C, preko svog porta 7826, ka portu 8080 čvora Y. čvor X ( ) čvor Y ( ) program A program B program C čvor Z ( ) program D 9864 Slika 4.2. Slučaj više uspostavljenih veza između programa 4.2 Identifikacija čvorova mreže Identifikator čvora u IP mreži je IP adresa 32-bitni broj. Ovakve adrese se često, radi lakšeg pamćenja, pišu u formatu koji se sastoji od četiri decimalno zapisana okteta razdvojena tačkom (na primer, ). Java standardna biblioteka poseduje klasu InetAddress koja predstavlja IP adresu. Kreiranje objekta ove klase se najčešće obavlja pozivom statičke metode getbyname. Ova metoda prima string parametar koji sadrži bilo IP adresu zapisanu u oktetima, bilo simboličku adresu (npr. java.sun.com). Sledi primer: InetAddress a = InetAddress.getByName("java.sun.com"); InetAddress b = InetAddress.getByName(" "); Statička metoda getlocalhost generiše InetAddress objekat koji predstavlja adresu mašine na kojoj se program izvršava: InetAddress c = InetAddress.getLocalHost(); 4.3 Klasa Socket Objekti klase java.net.socket predstavljaju uspostavljene TCP konekcije. To znači da se prilikom kreiranja objekta klase Socket vrši uspostavljanje veze. Tipično se otvaranje konekcije vrši na jedan od sledećih načina: Socket s1 = new Socket(addr, 25); // addr je InetAddress objekat 67

73 Socket s2 = new Socket("java.sun.com", 80); Kreiranje Socket objekta, tj. otvaranje konekcije, omogućava da se preuzmu reference na stream objekte koji se koriste za slanje i primanje poruka. Jedna moguća inicijalizacija stream-ova je prikazana na sledećem primeru: // inicijalizuj ulazni stream BufferedReader in = new BufferedReader( new InputStreamReader( sock.getinputstream())); // inicijalizuj izlazni stream PrintWriter out = new PrintWriter( new BufferedWriter( new OutputStreamWriter( sock.getoutputstream())), true); Konstrukcija i upotreba Stream, Reader i Writer objekata je detaljnije opisana u knjizi Thinking in Java. Treba primetiti da se odgovarajući Reader/Writer objekti generišu na osnovu stream-ova koje obezbeđuje Socket objekat, metodama getinputstream i getoutputstream. Komunikaca sa programom sa kojim je uspostavljena konekcija sada se može odvijati putem poziva odgovarajućih metoda Reader i Writer klasa. Na primer: out.writeln("hello"); String response = in.readline(); Prekid komunikacije treba završiti propisnim zatvaranjem konekcije. Zatvaranje konekcije se nejčešće svodi na zatvaranje ulaznog i izlaznog stream-a i zatvaranje socket-a. Sledi primer: out.close(); in.close(); sock.close(); 4.4 Tipičan tok komunikacije klijent strana Kao rezime prethodnog odeljka, ovde se izlaže tipičn scenario komunikacije dva programa, podrazumevajući ovde klijent-stranu (tj. klijentski program). Uloga klijenta u klijent/server komunikaciji podrazumeva nekoliko stvari: Klijent inicira komunikaciju. Nakon uspostavljanja veze, komunikacija se obično svodi na niz parova zahtev/odgovor poruka. Zahteve šalje klijent, a odgovore server. Klijent prekida komunikaciju. Ovakva sekvenca aktivnosti može biti predstavljena sledećim segmentom programa: // inicijalizacija Socket s = new Socket(addr, port); BufferedReader in = new BufferedReader(...,s.getInputStream()); PrintWriter out = new PrintWriter(...,s.getOutputStream()); 68

74 // komunikacija out.println( zahtev ); // šaljem zahtev String response = in.readline(); // čitam odgovor // i tako potreban broj puta... // prekid veze in.close(); out.close(); s.close(); 4.5 Klasa ServerSocket Klasa java.net.serversocket koristi se na serverskoj strani. Glavna metoda u ovoj klasi je accept metoda koja blokira izvršavanje programa sve dok neki klijent ne uspostavi vezu na portu na kome ServerSocket očekuje klijente. Objekti klase ServerSocket kreiraju se na standardan način, operatorom new. Parametar konstruktora je port na kome će server očekivati klijente; kao IP adresa se podrazumeva IP adresa lokalne mašine. Sledi primer: ServerSocket ss = new ServerSocket(9000); Ovim je konstruisan ServerSocket objekat pomoću koga će se očekivati klijenti na portu Samo osluškivanje na datom portu inicira se pozivom metode accept. Već je rečeno da ova metoda blokira izvršavanje programa sve dok neki klijent ne uspostavi vezu. Rezultat metode je inicijalizovani Socket objekat koga serverski program dalje koristi za komunikaciju sa klijentom koji je uspostavio vezu. Tipično poziv accept metode izgleda ovako: Socket s = ss.accept(); 4.6 Tipičan tok komunikacije server strana Imajući u vidu prethodne odeljke, tipičan scenario ponašanja serverskog programa je sledeći: 1. Konstrukcija ServerSocket objekta. 2. Očekivanje klijenta metodom accept. 3. Komunikacija sa klijentom: a. Inicijalizacija stream-ova b. Komuniciranje po principu prijem zahteva/slanje odgovora. c. Završavanje komunikacije oslobađanje resursa. Ovakav scenario može se predstaviti sledećim segmentom programa: // čekam klijenta... ServerSocket ss = new ServerSocket(port); Socket s = ss.accept(); // inicijalizacija BufferedReader in = new BufferedReader(...,s); PrintWriter out = new PrintWriter(...,s); // komunikacija 69

75 String request = in.readline(); out.println( odgovor ); // čitam zahtev // šaljem odgovor // prekid veze in.close(); out.close(); s.close(); 4.7 Server koji opslužuje više klijenata Prethodni primer je prikazao serverski program koji komunicira sa jednim klijentom nakon što ga server sačeka, komunikacija između klijenta i servera se obavi i potom završi. Ovakvi serverski programi su vrlo retki serveri se konstruišu tako da mogu da opslužuju više klijenata i to istovremeno. Potreba da server komunicira sa više klijenata istovremeno se može rešiti uvođenjem posebnih programskih niti za komunikaciju sa klijentima, tako da se sa svakim klijentom komunikacija obavlja u posebnoj programskoj niti. Dakle, za n istovremenih klijenata postojaće n ovakvih programskih niti. Sa stanovišta implementacije u programskom jeziku Java, ove niti predstavljene su odgovarajućom klasom koja nasleđuje klasu Thread, kao u sledećem primeru: // obrada pojedinačnog zahteva class ServerThread extends Thread { public void run() { // inicijalizacija // komunikacija // prekid veze Pored niti za komunikaciju sa pojedinim klijentima, potrebna je i posebna nit koja osluškuje serverski port i, po uspostavljanju veze, pokreće nit za komunikaciju sa klijentom, a sama se vraća u stanje čekanja na novog klijenta. Ukupno se, dakle, serverski program sastoji od n+1 niti prilikom obrade n istovremenih klijentskih zahteva. // Serverska petlja ServerSocket ss = new ServerSocket(port); while (true) { Socket s = ss.accept(); ServerThread st = new ServerThread(s); 4.8 Primer klijent/server komunikacije Imajući u vidu dosadašnje izlaganje, možemo konstruisati jednostavnu klijent/server aplikaciju. Zadatak klijenta u sledećem primeru je sledeći: 1. Uspostavlja vezu sa serverom. 2. Šalje zahtev serveru (tekst HELLO ). 3. Čita odgovor servera. 4. Ispisuje odgovor na konzolu. 5. Završava komunikaciju. 70

76 Klijentski program je predstavljen klasom Client1. import java.io.*; import java.net.*; public class Client1 { public static final int TCP_PORT = 9000; public static void main(string[] args) { try { // odredi adresu racunara sa kojim se povezujemo // (povezujemo se sa nasim racunarom) InetAddress addr = InetAddress.getByName(" "); // otvori socket prema drugom racunaru Socket sock = new Socket(addr, TCP_PORT); // inicijalizuj ulazni stream BufferedReader in = new BufferedReader( new InputStreamReader( sock.getinputstream())); // inicijalizuj izlazni stream PrintWriter out = new PrintWriter( new BufferedWriter( new OutputStreamWriter( sock.getoutputstream())), true); // posalji zahtev System.out.println("[Client]: HELLO"); out.println("hello"); // procitaj odgovor String response = in.readline(); System.out.println("[Server]: " + response); // zatvori konekciju in.close(); out.close(); sock.close(); catch (UnknownHostException e1) { e1.printstacktrace(); catch (IOException e2) { e2.printstacktrace(); Zadatak serverskog programa je sledeći: 1. Čeka klijente u beskonačnoj petlji. 2. Za svakog klijenta koji je uspostavio vezu pokreće posebnu nit koja radi sledeće: a. Čita zahtev klijenta (tekst HELLO ). 71

77 b. Šalje odgovor redni broj obrađenog zahteva. Osnovna nit servera u kojoj se očekuju klijenti nalazi se u klasi Server1: import java.io.*; import java.net.*; public class Server1 { public static final int TCP_PORT = 9000; public static void main(string[] args) { try { int clientcounter = 0; // slušaj zahteve na datom portu ServerSocket ss = new ServerSocket(TCP_PORT); System.out.println("Server running..."); while (true) { Socket sock = ss.accept(); System.out.println("Client accepted: " + (++clientcounter)); ServerThread st = new ServerThread(sock, clientcounter); catch (Exception ex) { ex.printstacktrace(); Vidimo da se u okviru osnovne niti nalazi beskonačna while petlja u okviru koje se očekuju klijenti i pokreće nit za komunikaciju sa klijentom. Konstruktor ove niti prima kao argumente Socket objekat koji će koristiti u komunikaciji (sock) i redni broj klijenta koji se prijavio (clientcounter). Nit za komunikaciju predstavljena je klasom ServerThread: import java.io.*; import java.net.*; public class ServerThread extends Thread { public ServerThread(Socket sock, int value) { this.sock = sock; this.value = value; try { // inicijalizuj ulazni stream in = new BufferedReader( new InputStreamReader( sock.getinputstream())); // inicijalizuj izlazni stream out = new PrintWriter( new BufferedWriter( new OutputStreamWriter( sock.getoutputstream())), true); catch (Exception ex) { ex.printstacktrace(); start(); 72

78 public void run() { try { // procitaj zahtev String request = in.readline(); // odgovori na zahtev out.println("(" + value + ")"); // zatvori konekciju in.close(); out.close(); sock.close(); catch (Exception ex) { ex.printstacktrace(); private Socket sock; private int value; private BufferedReader in; private PrintWriter out; Komunikacija između, recimo, Web servera i klijenta (Web čitača), podseća na komunikaciju prikazanu u gornjem primeru. Zahtev Web čitača tipično sadrži naziv datoteke koju čitač traži. Odgovor servera je poruka u kojoj se nalazi tražena datoteka. U objašnjenju prethodnog primera bilo je malo reči o formatu poruka koje se razmenjuju između klijenta i servera. Zahtev klijenta je tekst HELLO koji se završava znakom za novi red (linefeed, LF). Slanje ovakve poruke postiže se pozivom out.println("hello"); u okviru klijentskog programa. Sa druge strane, server očitava zahtev klijenta pomoću poziva metode readline: String request = in.readline(); Ova metoda će blokirati izvršavanje programa sve dok se na ulazu ne pojavi znak za novi red (LF), i tada će vratiti tekst koji je sa mreže pristigao pre tog znaka. Korišćenje znaka LF kao oznake kraja poruke (ili kraja jednog dela poruke) je relativno često u specifikaciji raznih Internet protokola. Sa druge strane, nije obavezno koristiti baš LF kao oznaku kraja poruke. Pre svega, komunikacioni protokol može biti tako specificiran da je dužina poruke koja se očekuje unapred poznata, tako da takvu poruku možemo pročitati pozivom in.read(buffer, 0, length); U slučaju da je dužina poruke nije unapred poznata, korišćenje karaktera LF je zgodno jer postoji metoda readline koja blokira izvršavanje sve dok taj karakter ne pristigne sa mreže. U slučaju da odlučimo da ne koristimo karakter LF nego neki drugi, morali bismo sami da implementiramo funkcionalnost ove metode. 73

79 4.9 Zadatak: klijent i server za listanje sadržaja direktorijuma Zadatak 6. Napisati klijent/server aplikaciju koja omogućava listanje sadržaja direktorijuma sa servera na klijentu. Na klijentov zahtev koji sadrži putanju direktorijuma na serveru koga treba izlistati, server formira spisak i vraća ga klijentu kao odgovor. Klijent i server nemaju potrebe za GUI interfejsom. Komentar: Jasno je da će klijent i server izgledati nalik klijentu i serveru koji su prikazani u prethodnom primeru. Ono što je neophodno uraditi prvo, je definisati protokol komunikacije klijenta i servera, pre svega format poruka koje se šalju tokom komunikacije. Za listanje sadržaja direktorijuma treba pogledati kako se koristi klasa java.io.file i njene metode exists, isdirectory i list. Odgovor servera bi trebalo da na odgovarajući način reaguje na situacije kada traženi direktorijum ne postoji, ili kada je u pitanju fajl, a ne direktorijum. 74

80 Poglavlje 5 Vežba: chat aplikacija Zadatak 7. Napisati klijent/server GUI aplikaciju koja mogućava chat za sve korisnike koji se prijave na isti server. Zadatak klijenta je da omogući unos novih i pregled pristiglih poruka (sa podacima o pošiljaocu poruke). Zadatak servera je da poruke poslate od strane jednog klijenta prosledi do ostalih klijenata (ne i pošiljaocu). Svaki korisnik u sistemu je jednoznačno određen svojim korisničkim imenom (username) koga bira prilikom prijavljivanja na sistem. Odmah nakon pokretanja klijenta korisnik mora da se prijavi na željeni server (određen svojom simboličkom ili numeričkom adresom) pod određenim korisničkim imenom. Naredne slike prikazuju jedan od mogućih izgleda ovakve aplikacije; ovakav izgled nije obavezan. Slika 5.1. Login forma klijenta Slika 5.2. GUI interfejs servera 75

81 Slika 5.3. GUI interfejs klijenata 5.1 Uvodna razmatranja U ostatku ovog poglavlja prikazuje se jedno moguće rešenje zadatka. Potrebno je izgraditi klijent/server sistem gde server mora da opslužuje više korisnika istovremeno. Na prvi pogled, sistem liči na primer iz prethodnog poglavlja. Međutim, ovaj sistem je nešto složeniji. Njegove osnovne osobine su sledeće: Klijent može da šalje poruke serveru, što se inicira akcijom nad korisničkim interfejsom. Klijent može da prima poruke od servera u proizvoljnom vremenskom trenutku, što je posledica slanja poruke od strane nekog drugog klijenta. Server može da prima poruke od strane više klijenata istovremeno, i to u slučajnim vremenskim trenucima. Server mora da prosledi poruku jednog klijenta svim ostalim klijentima. 5.2 Funkcije klijenta Posmatrajmo sada klijenta. On mora biti u mogućnosti da reaguje na pristiglu poruku tako što će je prikazati u odgovarajućoj komponenti korisničkog interfejsa. Poruka može da pristigne u bilo kom trenutku. Dakle, klijent mora neprestano osluškivati da li server šalje poruku. Kako realizovati ovakvu reakciju? Razmotrimo sledeću mogućnost: klijent ima tačno jednu konekciju sa serverom, koja se raskida po završetku rada. Postoje dve posebne niti, za čitanje poruka sa mreže i za pisanje poruka na mrežu. Čitačka nit čeka poruke servera, a pisačka nit šalje serveru one poruke koje je korisnik uneo 76

82 posredstvom GUI interfejsa. Kako će pisačka nit znati da treba da pošalje poruku? Tako što će sinhronizovano pristupati deljenom objektu koji predstavlja kontejner za slanje poruka. Poruke će u ovaj objekat upisivati osnovna nit programa (nit koja se bavi reakcijama na događaje korisnikog interfejsa). Slika 5.4. predstavlja dijagram sekvenci koji opisuje situaciju kada korisnik otkuca poruku i klikne na dugme Send da bi je poslao. Slika 5.5 predstavlja dijagram sekvenci koji opisuje prijem poruke kada je server pošalje. bsend.doclick() eventdispatchthread actionlistener chatdata writerthread outputstream actionperfomed() setmessage() notify() writeln() Slika 5.4. Klijent inicira slanje poruke readerthread inputstream textarea readline() append() Slika 5.5. Klijent prima poruku od servera Slika 5.6 predstavlja dijagram klasa koje učestvuju u komunikaciji sa serverom. Klasa ChatClient je osnovna klasa programa koja predstavlja i glavni prozor aplikacije. U okviru nje uspostavlja se veza sa serverom kreiranjem Socket objekta. Inicijalizovani Socket objekat poseduje stream-ove za čitanje (InputStream) i pisanje (OutputStream). Na osnovu njih kreiraju se BufferedReader i PrintWriter objekti za jednostavnije rukovanje stream-ovima. Konačno, kreiraju se ReaderThread i WriterThread objekti koji implementiraju čitačku i pisačku nit. Ovi objekti koriste odgovarajuće Reader/Writer objekte za komunikaciju. ChatData objekat je namenjen za sinhronizovanu komunikaciju sa WriterThread niti. Slika 5.7 prikazuje dijagram klasa koje učestvuju u radu korisničkog interfejsa. LoginDlg je dijalog za prijavljivanje na server prilikom pokretanja klijenta. JTextArea je višelinijsko tekstualno polje u kome se hronološki ispisuju poruke. 77

83 JButton je dugme za iniciranje slanja poruke. JTextField je jednolinijsko tekstualno polje u kome se unosi nova poruka. Socket InputStream OutputStream BufferedReader PrintWriter ChatClient ReaderThread ChatData WriterThread Slika 5.6. Klase koje učestvuju u komunikaciji sa serverom ChatClient JTextField LoginDlg JButton JTextArea ReaderThread Slika 5.7. Klase koje učestvuju u radu korisničkog interfejsa 5.3 Funkcije servera Serverska aplikacija kreira posebne niti za komunikaciju sa svakim korisnikom, i to po dve niti čitačku i pisačku. Čitačka nit je zadužena da očekuje poruke od klijenta, a pisačka da klijentu prenese poruku koju je poslao neki drugi klijent. Pisačka nit šalje poruku kada je dobije u svoj deljeni kontejnerski objekat. Situacija kada čitačka nit primi poruku i prosledi je svim čitačkim nitima preko odgovarajućih ActiveClient objekata je prikazana na slici 5.8. Klijent otpočinje komunikaciju prijavljivanjem na server. Dakle, prvo što će server primiti od klijenta je poruka kojom se vrši prijavljivanje. Prijavljivanje može biti uspešno ili neuspešno (u slučaju da se neko već prijavio pod tim korisničkim imenom). Slika 5.9 opisuje proces uspešnog prijavljivanja. 78

84 readerthread inputstream ClientUtils activeclient writerthread outputstream readline() sendmessagetoall() setmessage() notify() writeln() Slika 5.8. Čitačka nit prima poruku i prosleđuje je svim pisačkim nitima serverlistener serversocket accept() create() inputstream create() outputstream create() create() create() activeclient readerthread writerthread Slika 5.9. Uspešno prijavljivanje klijenta i kreiranje posvećene čitačke i pisačke niti Klasa ChatServer je osnovna klasa serverskog programa, koja predstavlja i osnovnu prozorsku klasu. Prilikom inicijalizacije ChatServer objekat kreira ServerListener nit koja čeka klijente. Po uspostavljanju veze sa klijentom, ServerListener nit kreira PrintWriter i BufferedReader objekte za komunikaciju, kreira ActiveClient objekat koji je namenjen za razmenu poruka između čitačkih i pisačkih niti i, na posletku, kreira čitačku i pisačku nit posvećenu novom 79

85 klijentu. Klasa ClientUtils implementira operacije nad kolekcijom prijavljenih klijenata (registracija, slanje poruke svima, itd). Slika prikazuje klase koje učestvuju u komunikaciji sa klijentima. ChatServer PrintWriter ServerListener BufferedReader ClientUtils WriterThread ActiveClient ReaderThread Slika Klase koje učestvuju u komunikaciji Kompletan programski kod klijentske i serverske aplikacije dat je u prilogu. 80

86 Poglavlje 6 Rad sa bazama podataka JDBC 6.1 Osnovne odrednice Java ima definisan standardni interfejs za komunikaciju sa bazama podataka nazvan JDBC. Njegov naziv namerno podseća na ODBC (Open Database Connectivity) interfejs, jer im je i koncept sličan. Naime, JDBC definiše skup klasa i interfejsa koji se koriste za pristup bazama podataka. Podrazumeva se da se koristi sistem za upravljanje relacionim bazama podataka (SUBP) sa kojim se komunicira putem jezika SQL. Za komunikaciju sa serverima najčešće se koristi TCP/IP mreža. Baze zasnovane na nekom drugačijem modelu podataka, na primer objektno-orijentisanom ili mrežnom modelu, nisu obuhvaćene ovim standardom. To ne znači da se njima ne može pristupati, već samo da se za tu namenu neće koristiti JDBC interfejs. Za pristup konkretnoj bazi podataka putem JDBC-a potrebna je odgovarajuća biblioteka. Biblioteka, u ovom slučaju, predstavlja običnu Java biblioteku klasa tipično spakovanu u jedan JAR fajl. Takva biblioteka se naziva JDBC drajver. Korišćenje standardnih klasa i interfejsa za komunikaciju sa SUBP čini jednostavnijom modifikaciju programa za rad sa nekim drugim SUBP. Idealno bi bilo kada program ne bi pretrpeo nikakve izmene u tom slučaju. Korišćenje JDBC-a je blisko ovom idealu: izmene je potrebno praviti samo u slučaju da su korišćene nestandardne SQL naredbe (odnosno naredbe koje nisu podržane kod drugih SUBP). Sve JDBC klase i interfejsi definisani su u standardnom paketu java.sql. JDBC interfejs je deo standardne Java biblioteke od Java verzije 1.1. JDBC interfejs ima svoje oznake sopstvenih verzija; Java 1.1 sadrži JDBC verziju 1.22, dok Java 1.2 sadrži JDBC verziju 2.0. Verzija 2.0 sadrži neka proširenja u odnosu na verziju 1.22, ali se i stariji drajveri obično mogu koristiti u okviru novijih verzija Jave. 6.2 JDBC drajveri JDBC drajveri su klasične Java biblioteke; da bi se koristile unutar nekog Java programa nije potrebna nikakva specifična instalacija tog drajvera (što je kod ODBC drajvera obavezno), nego je dovoljno tu biblioteku uključiti u sastav 81

87 programa. Tipično se JAR fajl u kome se nalazi JDBC drajver/biblioteka smešta u CLASSPATH i time postaje dostupan svim programima na datom računaru. Nema prepreke da se više različitih drajvera smesti u CLASSPATH istovremeno. Takođe, nema prepreke da jedan program komunicira sa više baza podataka istovremeno. Na primer, za pristup Oracle serveru potrebno je u program uključiti odgovarajući drajver. U pitanju je biblioteka koju kompanija Oracle distribuira besplatno i nalazi se u fajlu sa nazivom classes111.zip (starija verzija) ili classes12.jar (novija verzija). Dovoljno je ovu datoteku uključiti u CLASSPATH da bi se JDBC drajver za Oracle instalirao. Slično drajveru za Oracle koriste se i drajveri drugih proizvođača sistema za upravljanje bazama podataka. Obično proizvođač određenog SUBP nudi i JDBC drajver za svoje sisteme. Najupadljiviji izuzetak je Microsoft, koji nema drajver za svoj SQL Server, ali se takav drajver može nabaviti od third-party firmi. 6.3 Uspostavljanje veze sa bazom podataka Dve su radnje neophodne da bi se komuniciralo sa nekom bazom podataka putem JDBC-a: učitavanje drajvera i otvaranje konekcije sa bazom podataka. Pogledajmo primer ove dve operacije za Oracle SUBP: // učitavanje Oracle drajvera Class.forName("oracle.jdbc.driver.OracleDriver"); // otvaranje konekcije Connection conn = DriverManager.getConnection( "jdbc:oracle:thin:@branko.tmd.ns.ac.yu:1526:vta", "vta", "vta"); Prvi red predstavlja učitavanje odgovarajuće drajver klase; proizvođač drajvera obavezno navodi naziv ove klase za svoj drajver. Šta, zapravo, znači učitavanje klase? Odeljak 6.9 opisuje detaljnije ovu temu i druge pojedinosti vezane za korišćenje JDBC drajvera koje nisu od velikog značaja za samo korišćenje drajvera. Drugi red primera predstavlja otvaranje konekcije sa SUBP nakon što je drajver učitan. Prvi parametar metode getconnection je string koji sadrži podatke potrebne drajveru da bi se povezao sa SUBP. Format ovog stringa propisuje proizvođač drajvera. Tipično ovaj string sadrži adresu računara na kome se nalazi SUBP (u primeru to je branko.tmd.ns.ac.yu), TCP port na kome SUBP očekuje klijente (u primeru 1526) i naziv baze kojoj se pristupa (VTA). Druga dva parametra metode getconnection su korisničko ime i lozinka kojima se vrši prijavljivanje na SUBP. Sledi primer povezivanja na SQL Server SUBP pomoću JDBC drajvera TaveConn24C kompanije Atinav. // učitavanje SQL Server drajvera Class.forName("net.avenir.jdbc2.Driver"); // otvaranje konekcije Connection conn = DriverManager.getConnection( "jdbc:avenirdriver://branko.tmd.ns.ac.yu:1526/vta", 82

88 "vta", "vta"); Rezultat uspešne uspostave veze sa SUBP je, sa stanovišta Java programa, inicijalizovani Connection objekat. Metoda forname može da izazove izuzetak ClassNotFoundException, a metoda getconnection izuzetak SQLException. Pozivi ovih metoda moraju biti smešteni u odgovarajući try/catch blok. Sve ostale JDBC metode mogu da izazovu izuzetak SQLException. Prilikom završetka komunikacije sa bazom podataka potrebno je zatvoriti otvorenu konekciju. To se postiže pozivom metode close klase Connection: conn.close(); 6.4 Postavljanje upita Primeri u ovom poglavlju koriste šemu baze podataka prikazanu na slici 6.1. (Korišćena je notacija alata PowerDesigner, a korišćeni SUBP je Oracle; ovde nećemo ulaziti u detalje ove notacije, jer smatramo da je dijagram dovoljno jasan). U pitanju je baza podataka o nastavnicima i predmetima koje oni predaju. Jedan nastavnik može da predaje više predmeta, a takođe i jedan predmet može da predaje više nastavnika. NASTAVNICI NASTAVNIK_ID INTEGER IME VARCHAR2(25) PREZIME VARCHAR2(35) ZVANJE VARCHAR2(15) NASTAVNIK_ID = NASTAVNIK_ID PREDAJE PREDMET_ID INTEGER NASTAVNIK_ID INTEGER PREDMETI PREDMET_ID INTEGER NAZIV VARCHAR2(150) PREDMET_ID = PREDMET_ID Slika 6.1. Šema baze podataka korišćena u primeru Sve operacije nad bazom podataka, pa tako i postavljanje upita, definišu se odgovarajućim SQL naredbama koje se šalju serveru. SQL naredba je, u okviru JDBC interfejsa, definisana Statement objektom. Ovakav objekat se može kreirati nakon uspostavljene veze sledećim iskazom: Statement stmt = conn.createstatement(); gde je conn inicijalizovani Connection objekat iz prethodnih primera. Za slanje upita serveru koristi se metoda executequery, čiji je parametar string koji sadrži tekst SQL upita. Sledi primer: ResultSet rset = stmt.executequery( "SELECT ime, prezime FROM nastavnici"); Rezultat ove metode je inicijalizovani objekat klase ResultSet, koji je namenjen za skladištenje rezultata upita. Rezultat upita se može pročitati pomoću ovog objekta. Čitanje rezultata je operacija koja se odvija red-po-red u okviru tabele koja predstavlja rezultat. Za kretanje kroz tabelu rezultata koristi se koncept tekućeg reda. Tekući red se može pomerati isključivo od početka ka kraju tabele, bez preskakanja i bez više prolaza (u JDBC verziji 1.22; JDBC 2.0 omogućava prolaz kroz tabelu rezultata u oba smera i mnogo veću fleksibilnost u korišćenju ResultSet objekata). Inicijalno, nijedan red nije tekući red. Prvim 83

89 pozivom metode next klase ResultSet tekući red će biti prvi red tabele rezultata (ukoliko tabela sadrži bar jedan red). Metoda next vraća boolean vrednost koja označava da li novi tekući red postoji ili ne. Tipično se rezultat upita čita u petlji kao u sledećoj primeru: while (rset.next()) { // ovde čitamo red po red rezultata Za tekući red rezultata pojedine vrednosti polja očitavaju se metodama getstring, getint, getdate, itd. (za svaki tip podatka u bazi postoji odgovarajuća metoda). Konverziju između tipova podataka baze i jezika Java obavlja JDBC drajver. Parametar getxxx metoda je redni broj kolone koja se očitava; redni brojevi počinju od 1, a ne od nula kako bi se očekivalo. Nakon prestanka korišćenja ResultSet objekta potrebno je pozvati njegovu metodu close radi oslobađanja resursa koje je taj rezultat upita zauzimao. Slično važi i za Statement objekat. Sledi primer programa koji šalje upit Oracle serveru i ispisuje rezultat upita na konzolu. import java.sql.*; public class Demo1 { public static void main(string args[]) { try { // učitavanje Oracle drajvera Class.forName("oracle.jdbc.driver.OracleDriver"); // konekcija Connection conn = DriverManager.getConnection( "jdbc:oracle:thin:@branko.tmd.ns.ac.yu:1526:vta", "vta", "vta"); // slanje upita String query = "SELECT ime, prezime FROM nastavnici"; Statement stmt = conn.createstatement(); ResultSet rset = stmt.executequery(query); // čitanje rezultata upita while (rset.next()) { System.out.println(rset.getString(1) + " " + rset.getstring(2)); // oslobađanje resursa i zatvaranje veze rset.close(); stmt.close(); conn.close(); catch (Exception ex) { ex.printstacktrace(); 84

90 Iz primera se vidi da je jedini deo programa koji zavisi od upotrebljenog SUBP blok koji obavlja inicijalizaciju: učitavanje odgovarajućeg drajvera i otvaranje konekcije. SQL naredba koja se šalje serveru je, u ovom primeru, elementarna: svaki server bi trebalo da ume da je interpretira. U tom smislu, programski kod koji koristi JDBC je prenosiv na različite SUBP, jer se u celom programu menjaju samo iskazi za učitavanje drajvera i otvaranje konekcije; ostatak programa bi, u idealnom slučaju, funkcionisao i sa novim serverom. 6.5 DML operacije Prethodni odeljak je prikazao kako se šalju upiti serveru. Za slanje DML (data manipulation) naredbi SQL-a poput INSERT, UPDATE ili DELETE takođe se koristi Statement objekat, koji se inicijalizuje na isti način kao i u prethodnom slučaju. Razlika je ovde u slanju konkretne naredbe serveru, što se postiže pozivom metode executeupdate. Ova metoda, za razliku od executequery, ne vraća ResultSet objekat, već samo jednu int vrednost koja predstavlja broj redova na koje je operacija uticala (npr. broj ažuriranih ili obrisanih redova). Sledi primer dodavanja novog reda u tabelu predmeti: String sql = "INSERT INTO predmeti (predmet_id, naziv) " + "VALUES (10, 'Matematika 1')"; Statement stmt = conn.createstatement(); int rowsaffected = stmt.executeupdate(sql); stmt.close(); Statement objekat nakon upotrebe i u ovom slučaju treba da oslobodi resurse koje je zauzimao pozivom metode close. 6.6 Uzastopno izvršavanje istih SQL naredbi Prethodni odeljak definiše sve što je potrebno da bi se pisao program koji može da obavlja bilo koju operaciju nad bazom podataka (koja se može definisati SQL naredbama, naravno). Ovaj odeljak predstavlja situaciju kada se ista SQL naredba šalje serveru više puta uzastopno, što je prilično čest slučaj u praksi. Na primer, dodavanje više redova u tabelu nastavnici može se obaviti sledećim nizom SQL naredbi: INSERT INTO nastavnici (nastavnik_id, ime, prezime) VALUES (10, 'Sima', 'Simić'); INSERT INTO nastavnici (nastavnik_id, ime, prezime) VALUES (11, 'Vasa', 'Vasić'); INSERT INTO nastavnici (nastavnik_id, ime, prezime) VALUES (12, 'Petar', 'Petrović'); Vidimo da je u pitanju praktično ista naredba koja se ponavlja više puta: njena struktura je ista, a razlikuju se samo podaci koji se u njoj pojavljuju. Slanje ovakvih naredbi pomoću Statement objekta i metode executeupdate će željeni posao obaviti potpuno korektno. Svaki poziv executeupdate će jednu ovakvu SQL naredbu slati serveru. Server će, po prijemu naredbe, nju parsirati, analizirati i formirati nekakav plan njenog izvršavanja. Nakon toga će tu 85

91 naredbu i izvršiti. U ovakvim slučajevima moguće je popraviti performanse programa korišćenjem klase PreparedStatement. Ideja iza ove klase je sledeća: ako se serveru šalje više identičnih SQL naredbi (kao u prethodnom primeru), bilo bi zgodno da server samo jednom izvrši parsiranje i analizu SQL naredbe i formira plan izvršavanja. Takav plan izvršavanja može da se koristi više puta, za identične naredbe koje se razlikuju samo u podacima koje nose u sebi. To bi značilo da se za n identičnih naredbi takva naredba šalje samo jednom. Ona se tamo jednom analizira i n puta izvrši na osnovu plana izvršavanja. U slučaju da koristimo Statement objekte, server bi n puta vršio analizu i n puta izvršio naredbu. Objekat klase PreparedStatement se konstruiše kao u sledećem primeru: PreparedStatement pstmt = conn.preparestatement( "INSERT INTO nastavnici (nastavnik_id, ime, prezime, zvanje)"+ "VALUES (?,?,?,?)"); Ovakva inicijalizacija obuhvata i slanje naredbe serveru na analizu. Vidimo da je u okviru naredbe njen promenljivi deo (mesto gde se nalaze konkretni podaci za svaku naredbu) predstavljen upitnicima. Pre slanja konkretne naredbe serveru potrebno je definisati vrednost svakog od upitnika u ovoj naredbi. Ovo ilustruje sledeći primer: pstmt.setint(1, 4); pstmt.setstring(2, "Sima"); pstmt.setstring(3, "Simić"); pstmt.setstring(4, "docent"); Metode setxxx su namenjene za postavljanje vrednosti parametara SQL naredbe. Postoji odgovarajuća setxxx metoda za svaki tip podatka, analogno getxxx metodama klase ResultSet. Prvi parametar setxxx metoda je redni broj upitnika u SQL naredbi (počevši brojanje od 1). Drugi parametar je konkretna vrednost koju prima dati parametar. Sada je moguće izvršiti konkretnu naredbu iskazom: pstmt.executeupdate(); Sekvenca postavljanja vrednosti parametara (setxxx) i izvršavanja naredbe (executeupdate) se može ponoviti više puta, bez ponovne inicijalizacije PreparedStatement objekta to je i bila ideja analize SQL naredbi unapred. PreparedStatement je moguće koristiti i za slanje upita, samo što se tada ne poziva metoda executeupdate, već metoda executequery, čiji rezultat je ponovo ResultSet objekat koji se koristi na ranije opisani način. Nakon korišćenja PreparedStatement objekta potrebno je osloboditi resurse koje je zauzimao pozivom metode close. Sada sledi primer programa koji koristi PreparedStatement za dodavanje više redova u tabelu nastavnici. import java.sql.*; public class Demo2 { public static void main(string args[]) { 86

92 try { // učitavanje Oracle drajvera Class.forName("oracle.jdbc.driver.OracleDriver"); // konekcija Connection conn = DriverManager.getConnection( "jdbc:oracle:thin:@branko.tmd.ns.ac.yu:1526:vta", "vta", "vta"); // dodavanje novih nastavnika PreparedStatement stmt = conn.preparestatement( "insert into nastavnici "+ "(nastavnik_id, ime, prezime, zvanje) "+ "values (?,?,?,?)"); stmt.setint(1, 4); stmt.setstring(2, "Sima"); stmt.setstring(3, "Simić"); stmt.setstring(4, "docent"); stmt.executeupdate(); stmt.setint(1, 5); stmt.setstring(2, "Vasa"); stmt.setstring(3, "Vasić"); stmt.setstring(4, "docent"); stmt.executeupdate(); stmt.close(); conn.close(); catch (Exception ex) { ex.printstacktrace(); 6.7 Pozivanje uskladištenih procedura Uskladištene procedure (stored procedures) predstavljaju procedure koje se smeštaju u okviru baze podataka i dostupne su za pozivanje od strane klijenata. Najčešće se pišu u nekom od proširenja jezika SQL koje definiše proizvođač konkretnog SUBP. Na primer, Oracle sistemi nude PL/SQL za pisanje ovakvih procedura, Microsoft SQL Server ima svoj jezik Transact-SQL, itd. Sve ovo se odnosi i na uskladištene funkcije, pri čemu podela na funkcije i procedure je, zapravo, tradicionalna podela na potprograme koji vraćaju neku vrednost kao rezultat ili ne vraćaju nikakvu vrednost. Prednost korišćenja uskladištenih procedura je u poboljšanju performansi sistema. Naime, procedura najčešće predstavlja nekakvu složenu operaciju koja se izvršava nad bazom podataka. Takvu operaciju možemo implementirati i odgovarajućim Java kodom, koristeći prethodno izložene JDBC koncepte. Međutim, takav Java kod bi se često obraćao bazi podataka i time generisao veliki mrežni saobraćaj između klijenta i servera, i potrošio bi izvesno procesorsko vreme i na klijentu i na serveru za tu komunikaciju. Sa druge 87

93 strane, uskladištena procedura nalazi se kompletno na serveru. Tamo je smeštena u obliku koji je unapred pripremljen za efikasno izvršavanje, tako da njen poziv ne obuhvata i parsiranje, analizu naredbi, itd. Jedan poziv ovakve uskladištene procedure generiše daleko manji saobraćaj na mreži, a takođe je i izvršavanje procedure u okviru servera brže nego što bi to bio slučaj da se ona izvršava na klijentu. Slika 6.2 ilustruje razliku između pisanja Java koda koji operiše nad bazom i korišćenja uskladištenih procedura. klijent procedura server SQL naredbe a) klijent poziv uskladištene procedure procedura server b) Slika 6.2. a) procedura koja operiše nad bazom pisana u jeziku klijenta b) poziv ekvivalentne uskladištene procedure na serveru Sledi primer jedne uskladištene funkcije pisane u Oracle-ovom jeziku PL/SQL. Namena ove procedure je da poveže nastavnika datog svojim imenom i prezimenom i predmet koji on predaje datog svojim nazivom. Funkcija vraća 1 ako je operacija uspešno izvršena ili 0 ukoliko ne postoji dati nastavnik ili predmet. create or replace function povezi (ime_ in varchar2, prezime_ in varchar2, naziv_ in varchar2) return integer as nasid integer; predid integer; begin select nastavnik_id into nasid from nastavnici where ime = ime_ and prezime = prezime_; select predmet_id into predid from predmeti where naziv = naziv_; insert into predaje (nastavnik_id, predmet_id) values (nasid, predid); return 1; exception when no_data_found then return 0; end povezi; Preostaje još da vidimo kako se ovakva procedura može pozvati iz Java programa. Za tu namenu koristi se CallableStatement objekat koji se konstruiše kao u sledećem primeru: 88

94 CallableStatement cstmt = conn.preparecall( "{? = call povezi (?,?,?)"); Format stringa koji predstavlja poziv procedure definisan je JDBC-om; ne definiše ga svaki proizvođač SUBP posebno. Ovakav string obavezno sadrži vitičaste zagrade. Obavezna je i ključna reč call iza koje sledi naziv procedure ili funkcije koja se poziva. Zatim sledi lista parametara datih upitnicima u običnim zagradama. Ukoliko je u pitanju poziv funkcije, pre ključne reči call treba da se nađe jedan upitnik i znak za jednako (kao u ovom primeru), što predstavlja preuzimanje rezultata funkcije. Parametri ovakvih procedura ili funkcija mogu biti ulazni, izlazni, ili ulaznoizlazni. Svi ulazni parametri moraju biti definisani pre samog poziva procedure. Svim izlaznim parametrima se mora definisati tip podatka, takođe pre poziva procedure. Evo i primera kako se to radi, koristeći objekat cstmt inicijalizovan u prethodnom primeru: cstmt.setstring(2, "Sima"); cstmt.setstring(3, "Simić"); cstmt.setstring(4, "Osnovi računarstva"); cstmt.registeroutparameter(1, Types.INTEGER); Metode setxxx se koriste na isti način kao i kod PreparedStatement objekata. Metoda registeroutparameter je namenjena za definisanje tipa izlaznih argumenata uskladištene procedure/funkcije i za definisanje tipa rezultata funkcije. U ovom primeru je rezultat funkcije označen kao vrednost celobrojnog tipa. Oznake tipova nalaze se u klasi java.sql.types kao konstante. Treba obratiti pažnju na to da se kao redni broj parametra navodi redni broj upitnika koji se javlja u pozivu funkcije, uključujući i upitnik koji predstavlja rezultat funkcije. Sada je moguće i uputiti poziv funkcije, na sledeći način: cstmt.executequery(); Rezultat izvršavanja uskladištene funkcije dobija se sledećim pozivom: cstmt.getint(1) Sledi primer programa koji poziva uskladištenu funkciju povezi prikazanu u prethodnim primerima. import java.sql.*; public class Demo3 { public static void main(string args[]) { try { // učitavanje Oracle drajvera Class.forName("oracle.jdbc.driver.OracleDriver"); // konekcija Connection conn = DriverManager.getConnection( "jdbc:oracle:thin:@branko.tmd.ns.ac.yu:1526:vta", "vta", "vta"); // povezivanje novih nastavnika sa predmetima CallableStatement stmt = conn.preparecall( 89

95 "{? = call povezi (?,?,?)"); stmt.setstring(2, "Sima"); stmt.setstring(3, "Simic"); stmt.setstring(4, "Osnovi racunarstva"); stmt.registeroutparameter(1, Types.INTEGER); stmt.executequery(); System.out.println("Status: " + stmt.getint(1)); stmt.close(); conn.close(); catch (Exception ex) { ex.printstacktrace(); 6.8 Upravljanje transakcijama Svaka konekcija se, inicijalno, nalazi u tzv. auto-commit režimu rada: potvrda uspešnog završetka transakcije (commit) će se slati automatski nakon svake poslate SQL naredbe. Kada se konekcija ne nalazi u auto-commit režimu transakcija se mora ručno potvrditi ili opozvati. Potvrda transakcije se vrši pozivom metode commit nad Connection objektom: conn.commit(); Opoziv transakcije se vrši pozivom metode rollback nad Connection objektom: conn.rollback(); Promena režima rada se postiže pozivom metode setautocommit: conn.setautocommit(false); Najčešće se konekcije ne koriste u auto-commit režimu. Tipičan blok programskog koda koji vrši izmene u bazi podataka bi izgledao ovako: try { Statement stmt = conn.createstatement(); // izvrši neke izmene... stmt.close(); conn.commit(); catch (SQLException ex) { try { conn.rollback(); catch (Exception e) { Dakle, na kraju svake transakcije koja se tipično nalazi u try/catch bloku mora se pozvati commit metoda. Ukoliko se dogodilo nešto nepredviđeno u toku izvršavanja operacije što je rezultovalo izuzetkom, poziva se metoda rollback u okviru catch sekcije. Metoda rollback takođe može da izazove izuzetak, tako da je i ona morala biti smeštena u poseban try/catch blok. 90

96 6.9 Dodatak: inicijalizacija drajvera Ovaj odeljak je posvećen detaljnijem objašnjenju nekih pojedinosti vezanih za inicijalizaciju JDBC drajvera i korišćenje JDBC klasa i interfejsa. Učitavanje JDBC drajvera, kako je ranije rečeno, obavlja se pozivom Class.forName("oracle.jdbc.driver.OracleDriver"); U pitanju je poziv statičke metode forname klase Class. Instance klase Class predstavljaju klase i interfejse pokrenute Java aplikacije. Dakle, za svaku klasu i interfejs koja se koristi u programu postoji po jedna instanca klase Class koja je opisuje. Klasa Class sadrži metode pomoću kojih se mogu, u toku izvršavanja programa, dobiti informacije o metodama, atributima i ostalim karakteristikama neke konkretne klase koja se koristi u programu. Statička metoda forname vraća inicijalizovan objekat klase Class koji odgovara klasi čiji je naziv dat parametrom metode. Inicijalizacija ovakvog Class objekta obuhvata i inicijalizaciju statičkih atributa klase koja se učitava u JVM. Inicijalizacija statičkih atributa klase može se smestiti u poseban static blok u okviru klase koji ne pripada nijednoj metodi. Sledi primer jedne klase koja sadrži takav blok: class Test { static int attr; static { // ovde se vrši inicijalizacija statičkih atributa attr = 0; Vratimo se sada JDBC drajveru: klasa OracleDriver je osnovna klasa Oracle-ovog JDBC drajvera. Njeno učitavanje pozivom metode forname će izvršiti i static blok ove klase u kome se poziva metoda registerdriver klase DriverManager čime se konkretan drajver registruje na jednom jedinstvenom mestu. Poziv metode getconnection klase DriverManager vraća inicijalizovanu vezu sa bazom podataka predstavljenu Connection objektom. Za uspostavljanje veze koristiće se onaj drajver koji može da interpretira adresu servera navedenu kao parametar metode getconnection. Dakle, ako se metoda getconnection pozove sa sledećim parametrima: Connection conn = DriverManager.getConnection( "jdbc:oracle:thin:@branko.tmd.ns.ac.yu:1526:vta", "vta", "vta"); klasa DriverManager će upotrebiti baš Oracle JDBC drajver za uspostavljanje konekcije zato što se Oracle drajver registrovao da može da uspostavlja konekcije čiji opis počinje sa jdbc:oracle. Zapravo, jdbc je obavezni početak ovakvog stringa, čiji se segmenti razdvajaju dvotačkom. Sledeći segment stringa (oracle) označava drajver koji će obezbediti povezivanje sa bazom podataka. U primeru povezivanja sa SQL Server SUBP, gde je povezivanje izvršeno sa Connection conn = DriverManager.getConnection( "jdbc:avenirdriver://branko.tmd.ns.ac.yu:1526/vta", "vta", "vta"); 91

97 vidi se da je vrednost drugog segmenta AvenirDriver što je string kojim se registrovao odgovarajući drajver. Rezultat getconnection metode je inicijalizovani Connection objekat. Connection je sam po sebi interfejs i ne može imati svoje instance. Ovde se radi o objektu koji je instanca klase koja implementira Connection interfejs. Koja je klasa u pitanju zavisi od drajvera koji je upotrebljen; Oracle drajver će vratiti instancu klase OracleConnection, neki drugi drajver će vratiti instancu neke druge klase, itd. Klasa OracleConnection sadrži kod koji je specifičan za komunikaciju sa Oracle serverima, itd. Nadalje, kreiranje Statement objekta je rezultat poziva createstatement metode Connection interfejsa. U konkretnom slučaju, kada se metoda createstatement pozove nad instancom klase OracleConnection rezultat će biti instanca klase OracleStatement koja implementira Statement interfejs. Slično važi i za ResultSet interfejs. Konačni rezultat ovakvog koncepta je program koji operiše nad objektima kojima pristupa preko njihovih standardnih (JDBC-om definisanih) interfejsa. Konkretne klase koje implementiraju te interfejse se nigde ne spominju u okviru programa. Jedino mesto gde se specificira koja familija klasa će biti upotrebljena je učitavanje drajvera i otvaranje konekcije sa SUBP. Ovakva arhitektura je zaslužna što se isti JDBC programski kod može koristiti sa različitim SUBP prostom zamenom drajvera. 92

98 Poglavlje 7 Uvod u višeslojne klijent/server sisteme 7.1 Klasični klijent/server sistemi U klasičnim sistemima za obradu podataka po klijent/server modelu mogu se uočiti tri klase komponenti: serveri, klijenti i mreža. Namena servera je, pre svega, optimalno upravljanje zajedničkim resursima, što su najčešće podaci. Server obavlja upravljanje bazom podataka kojoj pristupa više korisnika, vrši kontrolu pristupa i bezbednosti podataka i centralizovano obezbeđuje integritet podataka za sve aplikacije. Klijenti omogućavaju korisnicima pristup do podataka. Klijent-aplikacije vrše upravljanje korisničkim interfejsom i izvršavaju deo logike aplikacije. Računarska mreža i komunikacioni softver omogućavaju prenos podataka između klijenta i servera. Slika 7.1 prikazuje skicu klijent/server sistema. Klijent Mreža Klijent Server Klijent Slika 7.1. Skica klasičnog klijent/server sistema Jedna od osnovnih karakteristika klijent/server sistema je distribuirana obrada podataka logika aplikacije je podeljena između klijenta i servera tako da obezbedi optimalno korišćenje resursa. Na primer, prezentacija podataka i provera ulaznih podataka su sastavni deo klijent-aplikacije, dok se rukovanje podacima, u smislu njihovog fizičkog smeštaja i kontrole pristupa, vrši na serveru. Neke od prednosti ovakvog modela obrade podataka su centralizovano upravljanje resursima sistema i jednostavnije obezbeđivanje sigurnosti podataka. 93

99 U ovakvim sistemima se najčešće nalazi samo jedan server. Sa aspekta računarskog hardvera to može biti više računara povezanih na odgovarajući način radi povećanja pouzdanosti sistema (otkaz jednog server-računara ne izaziva otkaz celog sistema) ili brzine odziva (kroz paralelizovan rad više serverskih računara). Osnovni problem koji se ovde javlja je nedostatak skalabilnosti. Pod skalabilnošću se podrazumeva osobina sistema da omogući efikasan rad velikom broju korisnika, i da dalje povećavanje broja korisnika ne izaziva drastičan pad performansi sistema. Povećavanje propusne moći servera u pogledu broja korisnika koji mogu efikasno da rade ili količine podataka koja se obrađuje je izuzetno skupo jer zahteva velika ulaganja u serverske računare visokih performansi. Klijent-aplikacije u ovakvim sistemima su programi pisani za konkretnu računarsku platformu klijenta. U heterogenim sistemima to podrazumeva programe pisane posebno za svaku platformu (Windows, Macintosh, razne Unix radne stanice itd.). Pored toga, klijent-aplikacije je potrebno instalirati i održavati na svakom klijent-računaru, što u velikim mrežama predstavlja mnogo veći izdatak od inicijalne nabavke opreme, na primer. 7.2 WWW i Java kao platforma za klijente Široka prihvaćenost Interneta, odnosno World Wide Web-a, je proizvela, između ostalog, i jedan izuzetno važan efekat: okruženje Web čitača (browsera) je postalo poznato za većinu korisnika računara. Informacioni sistemi kod kojih se komunikacija sa korisnikom odvija kroz Web čitač u velikoj meri eliminiše potrebu za dugotrajnom i skupom obukom korisnika. Sa druge strane, Java je programski jezik čija je osnovna karakteristika potpuna nezavisnost od fizičke platforme na nivou prevedenog programskog koda. Java programi se, u formi apleta, mogu ugrađivati u Web stranice i na taj način distribuirati korisnicima. Posledica ovoga je mogućnost automatske distribucije i instalacije klijent-aplikacija na mreži, bez obzira na konkretnu fizičku platformu klijenta dovoljan je Web čitač sa podrškom za Javu. Kombinacija WWW i Java tehnologija je omogućila implementaciju klijent/server informacionih sistema koje, za razliku od klasičnih sistema, karakterišu sledeće osobine: jednostavan i široko prihvaćen oblik korisničkog interfejsa (Web čitač); automatska distribucija i instalacija klijent-aplikacija; jednostavnije održavanje sistema, naročito u heterogenim mrežama. Slika 7.2 predstavlja skicu klijent/server sistema zasnovanog na WWW i Java tehnologijama. 94

100 Web čitač Mreža Web čitač Web server + SUBP Web čitač Slika 7.2 Sistem zasnovan na WWW i Java tehnologijama 7.3 Troslojni klijent/server sistemi Informacione sisteme koji su do sada razmatrani možemo nazvati dvoslojnim: u okviru njih izdvajaju se segmenti klijenta i servera. Klijent/server sistemi sa troslojnom arhitekturom (three-tier architecture) predstavljaju sisteme sa tri, u velikoj meri nezavisna, podsistema. U pitanju su sledeći podsistemi: 1. podsistem za interakciju sa korisnikom (implementira funkcije korisničkog interfejsa); 2. podsistem za implementaciju osnovnih funkcija sistema (implementira tzv. poslovnu logiku ); 3. podsistem za rukovanje podacima, pri čemu se pre svega misli na fizički smeštaj podataka (ovo je, zapravo, sistem za upravljanje bazama podataka). Na slici 7.3 je prikazan odnos ova tri podsistema. Na slici se vidi da ne postoji direktna veza između podsistema za interakciju sa korisnikom i podsistema za rukovanje podacima. Zbog ovakvog međusobnog odnosa, ovi podsistemi se nazivaju i slojevi. Klijent aplikacija Aplikacioni server SUBP Slika 7.3. Elementi troslojne arhitekture sistema Za razliku od dvoslojnog modela obrade podataka, gde je logika aplikacije bila podeljena između klijenta i servera, u ovom modelu ona se nalazi koncentrisana u tzv. aplikacionom serveru serveru čija je namena da izvršava programski kod koji implementira logiku aplikacije. Klijent aplikacija je namenjena samo za implementaciju korisničkog interfejsa, a funkcija sistema za upravljanje bazom podataka je isključivo fizičko rukovanje podacima (u prethodnom slučaju je, pored toga, izvršavao i deo logike aplikacije). 95

101 Ovakav koncept je doveo do podele programskog koda na segmente koji implementiraju tačno određene funkcije sistema. Tako organizovan sistem je jednostavniji za održavanje, jer je moguće nezavisno razvijati korisnički interfejs, i logiku aplikacije. Za potrebe fizičkog rukovanja podacima najčešće se koristi neki od komercijalno dostupnih servera za tu namenu. Troslojne arhitekture informacionih sistema podrazumevaju oslanjanje na standarde u odgovarajućom oblastima. Najčešće su u pitanju sistemi zasnovani na Internet tehnologijama. Oslanjanje na standarde omogućava integraciju informacionih sistema heterogenih u pogledu korišćene hardverske i softverske opreme. Na primer, računarska mreža ovakvog sistema može biti zasnovana na TCP/IP familiji protokola. Serveri u mreži mogu biti od različitih proizvođača, sve dok obezbeđuju standardne servise predviđene protokolom. Druga važna karakteristika troslojnih sistema je skalabilnost. Pre svega, povećavanje broja klijenata je jednostavno. Povećavanje propusne moći servera srednjeg sloja je moguće kroz dodavanje novih serverskih mašina. Analogno tome moguće je povećati i propusnu moć zadnjeg sloja. Slika 7.4 prikazuje jednu od mogućih konfiguracija ovakvog sistema. Ovde je važno primetiti da se povećanje brzine odziva serverskog sloja može postići dodavanjem novih serverskih mašina uz korišćenje postojećih. Na taj način može se iskoristiti i oprema koja ne mora imati vrhunske performanse. Sistem sa više servera karakteriše i povećana pouzdanost i fleksibilnost. Logika aplikacije se može menjati i u toku rada sistema. Pored toga, moguće je efikasno vršiti balansiranje opterećenja serverskog podsistema. Daljim proširivanjem koncepta troslojnih sistema dolazi se do pojma višeslojnih sistema (multitier architecture), gde se vrši dalja podela na komponente u okviru srednjeg sloja sa ciljem još većeg povećanja skalabilnosti, odnosno performansi. Klijent Klijent Aplikacioni server SUBP Klijent Aplikacioni server SUBP Klijent Aplikacioni server Klijent Slika 7.4. Skica konfiguracije sistema sa troslojnom arhitekturom 96

102 Jedna moguća arhitektura višeslojnih sistema je prikazana na slici 7.5. Srednji sloj je podeljen na dva sloja: jedan je namenjen za opsluživanje Web klijenata, a drugi sadrži komponente koje implementiraju poslovnu logiku sistema. Web browser Web Server App server Web browser DBMS Web Server App server Web browser DBMS Web Server Web browser App server Slika 7.5. Jedna moguća arhitektura višeslojnog sistema Za ovakve četvoroslojne sisteme postoje odgovarajuće tehnologije koje omogućavanju njihovu izgradnju. Slika 7.6 prikazuje skup ovakvih tehnologija definisanih oko programskog jezika Java. HTML Servlets / JSP EJB / CORBA HTTP RMI / IIOP JDBC RDBMS RDBMS Slika 7.6. Java tehnologije za izgradnju višeslojnih sistema Interakciju sa korisnikom u ovakvom sistemu obavljaju klijenti koji imaju standardan Web interfejs. U pitanju su Web čitači koji prikazuju HTML stranice. Komunikacija između Web čitača i Web servera se odvija putem standardnog HTTP protokola, uz dodatak cookie podataka kojima se prati korisnička sesija dok se on kreće po Web sajtu. Stranice koje prikazuju klijenti su najčešće generisane dinamički, tj. po prijemu zahteva za nekom stranicom. Dinamičko generisanje Web sadržaja na osnovu podataka iz ostatka sistema vrše servleti ili se za tu namenu koriste JSP (Java Server Pages) stranice. Za potrebe manipulacije podacima u sistemu servleti ili JSP stranice pristupaju objektima u okviru aplikacionih servera koji su dostupni kao CORBA ili EJB (Enterprise JavaBeans) komponente. Protokol za komunikaciju između ova dva 97

103 sloja je JRMP (Java Remote Method Protocol), protokol za komunikaciju između distribuiranih Java objekata, ili IIOP (Internet Inter-ORB Protocol) ekvivalentan protokol vezan za CORBA tehnologiju. CORBA/EJB komponente za potrebe skladištenja podataka u bazi podataka pristupaju serveru za upravljanje bazama podataka preko standardnog JDBC interfejsa. Naredna poglavlja će opisati ovde pomenute tehnologije. 98

104 Poglavlje 8 Dinamičko generisanje HTML-a i servleti 8.1 HTTP protokol Web čitači su namenjeni za prikazivanje Web stranica koje im isporučuju odgovarajući Web serveri. Struktura i izgled samih stranica se opisuje jezikom HTML. Komunikacija između Web klijenta (tj. čitača) i Web servera odvija se po standardnom HTTP protokolu. Slika 8.1 prikazuje slanje zahteva od klijenta ka serveru po HTTP protokolu. (Ovde prikazujemo HTTP protokol kako bi se lakše razumela materija u narednim odeljcima; detaljima ovog protokola se nećemo baviti.) HTTP klijent GET /docs.html HTTP/1.0 User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0) Accept-Cookies: yes Host: branko.tmd.ns.ac.yu... Slika 8.1. Slanje zahteva HTTP klijenta HTTP server Zahtev koji klijent upućuje serveru je tekstualna poruka koja sadrži više redova. Prvi red poruke je najvažniji: on sadrži komandu koju klijent upućuje serveru (u ovom slučaju to je GET komanda kojom se zahteva određena datoteka sa Web servera), putanju datoteke u okviru Web sajta servera (/docs.html) i oznaku verzije protokola (HTTP/1.0). Naredni redovi u poruci predstavljaju dodatne informacije koje server može da iskoristi za svoje potrebe. U ovom primeru, polje User-Agent predstavlja opis klijentskog softvera (tip i verzija Web čitača i operativnog sistema), polje Host predstavlja simboličku adresu klijenta, itd. GET je samo jedna od komandi koje može da uputi klijent. Ujedno je to i daleko najčešće upotrebljavana komanda. U nastavku teksta biće reči i o nekim drugim komandama. Zadatak servera je da po prijemu ovakvog zahteva odgovori na njega. U ovom slučaju odgovor servera treba da sadrži traženu datoteku (docs.html), pri čemu je format odgovora takođe definisan HTTP protokolom. Slika 8.2 prikazuje situaciju kada server šalje odgovor klijentu. 99

105 HTTP klijent HTTP/ OK Content-Type: text/html <HTML> <HEAD>... HTTP server Slika 8.2. Slanje odgovora HTTP klijentu Prvi red odgovora sadrži oznaku protokola, trocifreni broj koji predstavlja status izvršene operacije (u ovom slučaju to je 200), i tekstualni opis tog statusa (OK). Konstanta 200 označava da je zahtev uspešno izvršen i da se tražena datoteka nalazi u nastavku poruke. Druge konstante koje se češće sreću su 404 (tražena datoteka nije pronađena), 407 (pristup datoteci nije dozvoljen), i 302 (datoteka premeštena na drugo mesto). Konstante su definisane HTTP protokolom. Sledeći red odgovora (Content-Type) je oznaka tipa sadržaja koji se vraća. U pitanju su standardizovane oznake propisane u odgovarajućim RFC dokumentima. Na primer, HTML datoteke imaju oznaku text/html, datoteke sa ASCII tekstom bez formatiranja imaju oznaku text/plain, GIF slike image/gif, JPEG slike image/jpeg, itd. Neposredno pre sadržaja datoteke koja se šalje nalazi se jedan prazan red koji razdvaja zaglavlje odgovora od samog sadržaja datoteke. Ukupna sekvenca aktivnosti klijenta i servera u HTTP komunikaciji je sledeća: 1. klijent otvara konekciju sa serverom 2. klijent šalje zahtev serveru 3. server vraća odgovor 4. zatvara se konekcija. Vidimo da je komunikacija između klijenta i servera zasnovana na zahtev/odgovor principu. Svaki par zahtev/odgovor smatra se nezavisnim od ostalih. Recimo, u slučaju da prvi klijent pošalje zahtev serveru i dobije odgovor, zatim drugi klijent pošalje zahtev i dobije odgovor, pa potom ponovo prvi klijent pošalje novi zahtev, nema načina da se ustanovi da je prvi klijent poslao dva zahteva (prvi i treći). Server svaki zahtev opslužuje nezavisno od ostalih zahteva. U tom smislu, HTTP je stateless protokol: ne omogućava praćenje stanja korisničke sesije između slanja više različitih zahteva. Važno je primetiti još nešto: jedino što klijent može da zatraži od servera je datoteka. Na serveru je da tu datoteku pronađe (eventualno i modifikuje!) i pošalje klijentu. Web sadržaji koji se smeštaju na server vidljivi su klijentima kao pojedine datoteke. Te datoteke mogu biti unapred pripremljene (npr. u editoru kakav je Microsoft FrontPage) i smeštene u fajl-sistem Web servera. Mogu biti i generisane u letu po prijemu zahteva klijenta na neki poseban način; klijent ne zna da li je datoteka koju je tražio generisana statički ili dinamički. U tom smislu, Web sadržaje (zapravo, datoteke) možemo podeliti na statičke i dinamičke. 100

106 8.2 Statički i dinamički Web sadržaji Statički Web sadržaji su datoteke koje su unapred smeštene u odgovarajući direktorijum fajl-sistema Web servera i spremne su za isporuku klijentima po njihovom zahtevu. Slika 8.3 prikazuje sekvencu događaja kada klijent zatraži ovakvu datoteku. 1) klijent zahteva fajl HTTP klijent 2) server učitava fajl iz fajl-sistema i šalje ga klijentu HTTP server Slika 8.3. Isporuka statičkih sadržaja Sa slike se vidi da, po prijemu zahteva klijenta, server učitava traženu datoteku iz svog fajl-sistema i šalje je nazad klijentu preko mreže. Dinamički sadržaji nisu uskladišteni unapred već se generišu za svaki zahtev klijenta posebno. Sekvenca događaja kada klijent zatraži neki dinamički generisanu datoteku je prikazana na slici ) klijent zahteva fajl HTTP klijent 2) server generiše fajl i šalje ga klijentu; ne snima ga u svoj fajl-sistem HTTP server Slika 8.4. Isporuka dinamičkih sadržaja U ovom slučaju server neće tražiti datoteku u okviru fajl-sistema; na neki način server zna da je u pitanju dinamički generisana datoteka i poziva odgovarajući potprogram koji će je generisati. Najčešće nema potrebe ovako generisanu datoteku čuvati na serveru; ona se zato neće čuvati u okviru fajlsistema servera. 8.3 Servleti Servleti su jedna od tehnologija za generisanje dinamičkih Web sadržaja. Da bi se servleti mogli koristiti, Web server mora da ima odgovarajuću podršku za servlete. Pisanje servleta je moguće samo u programskom jeziku Java, tako da je za njihovo izvršavanje potrebna i JVM (koju najčešće obezbeđuje Web server). Servlet je, zapravo, Java klasa koja nasleđuje standardnu klasu HttpServlet. Klase i interfejsi koji se koriste u pisanju servleta nalaze se u paketima javax.servlet i javax.servlet.http. Mogli bismo da napišemo klasu koja nasleđuje HttpServlet i ne dodaje ili redefiniše ništa; takav servlet bio bi funkcionalan ali ne bi radio ništa korisno. Dodavanje funkcionalnosti u servlet postiže se redefinisanjem sledećih metoda (spisak nije potpun, ovde su pobrojane samo najčešće korišćene metode): init destroy doget dopost 101

107 Važno je imati na umu da se ove metode, u principu, nikada ne pozivaju direktno. Njih će pozivati Web server u odgovarajućim trenucima Metoda init Metoda init je namenjena za inicijalizaciju servleta pre njegove prve upotrebe. Poziva se tačno jednom. Nema prepreke da servlet klasa sadrži i svoj konstruktor u kome će obaviti deo inicijalizacije, ali je na raspolaganju i ova metoda Metoda destroy Metoda destroy se poziva prilikom uništavanja servleta. Namenjena je za obavljanje zadataka koje je neophodno obaviti pre nego što se završi sa radom (oslobađanje resursa koje je servlet zauzimao: otvorenih datoteka, konekcija sa bazom podataka, itd). To se najčešće dešava prilikom zaustavljanja Web servera ili u slučaju da Web server iz nekog razloga mora da uništi servlet objekat pre nego što nastavi sa radom Metoda doget Metoda doget se poziva za svaki GET zahtev klijenta koji je tražio datoteku za čije generisanje je zadužen dati servlet. Metoda ima dva parametra: public void doget(httpservletrequest request, HttpServletResponse response); prvi parametar (request) sadrži informacije o zahtevu klijenta na koji se odgovara, a drugi parametar (response) je namenjen da prihvati generisani odgovor servleta. Dakle, tipična sekvenca poziva metoda servleta je sledeća: 1. poziv metode init prilikom pokretanja Web servera 2. višestruki pozivi metode doget prilikom obrade zahteva klijenata 3. poziv metode destroy prilikom zaustavljanja Web servera 8.4 Primer: elementarni servlet Ovaj odeljak donosi primer elementarnog servleta, koji redefiniše samo doget metodu. U okviru doget metode generiše se HTML stranica koja će biti poslata klijentu. U pitanju je stranica koja sadrži tekst Hello world. import javax.servlet.*; import javax.servlet.http.*; import java.io.*; /** Hello world u servlet tehnologiji */ public class HelloWorld extends HttpServlet { // Obrada GET zahteva public void doget( HttpServletRequest request, HttpServletResponse response) 102

108 throws ServletException, IOException { response.setcontenttype("text/html"); PrintWriter out = response.getwriter(); out.println("<html>"); out.println("<head>"); out.println("<title>hello World Servlet</TITLE>"); out.println("</head>"); out.println("<body>hello World!</BODY>"); out.println("</html>"); Pozivom metode setcontenttype nad objektom response definisan je tip sadržaja koji će se vratiti klijentu. U ovom slučaju to je text/html. Ova vrednost će se direktno ugraditi u zaglavlje odgovora HTTP protokola, tako da je poziv ove metode obavezan. Sledeći je poziv metode getwriter. Rezultat ove metode je inicijalizovan izlazni stream (objekat klase PrintWriter) u koji se upisuje generisani sadržaj. U toku formiranja rezultujuće HTML stranice najčešće se poziva metoda println koja dodaje fragmente stranice u izlazni stream. Redosled pozivanja ovih metoda je važan: setcontenttype je neophodno pozvati pre metode getwriter. Drugo, setcontenttype se obično poziva na samom vrhu doget metode, pre bilo kog drugog poziva. Prevođenjem ovakvog servleta dobija se.class fajl koji se smešta na odgovarajuće mesto u okviru instalacije Web servera. Način kako pristupiti servletu iz Web čitača zavisi od korišćenog Web servera. Najčešće se takvom servletu može pristupiti pomoću URL-a koji ima sledeći oblik: Poslednji segment URL-a predstavlja naziv servlet klase. Ovo se, kod većine Web servera, može konfigurisati na određeni način. Upućivanjem Web čitača na ovakvu adresu dobiće se rezultat kao na slici 8.5. Slika 8.5. Rezultat rada HelloWorld servleta 8.5 Analiza zaglavlja HTTP zahteva Sledeći primer ilustruje mogućnost pristupa svim podacima iz HTTP zahteva klijenta na koji se odgovara. Pristup tim podacima se vrši preko request objekta koji je parametar doget metode. 103

109 import javax.servlet.*; import javax.servlet.http.*; import java.io.*; import java.util.enumeration; import java.util.vector; /** Servlet koji ispisuje sadržaj zaglavlja zahteva koje je * primio od browsera. */ public class DisplayHeader extends HttpServlet { // Obrada GET zahteva public void doget( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setcontenttype("text/html; charset=utf-8"); PrintWriter out = response.getwriter(); String[] headers = getheaders(request); for (int i = 0; i < headers.length; i++) { out.println(headers[i]); out.println("<br>"); private String[] getheaders(httpservletrequest request) { Vector temp = new Vector(); Enumeration enum = request.getheadernames(); while (enum.hasmoreelements()) { String headername = (String)enum.nextElement(); String headervalue = request.getheader(headername); temp.addelement(headername + ": " + headervalue); String[] retval = new String[temp.size()]; temp.copyinto(retval); return retval; Metoda getheaders je namenjena da na osnovu datog request objekta formira niz stringova čiji je sadržaj [naziv zaglavlja: vrednost]. Metoda getheadernames objekta request je vraća listu naziva zaglavlja koje se nalaze u okviru zahteva. Za svaki takav naziv zaglavlja može se dobiti sadržaj pozivom metode getheader. Rezultujuća HTML stranica sadrži redove teksta koji prikazuju sadržaje zaglavlja zahteva. 8.6 Konkurentni pristup servletu Za svaku servlet klasu koja se pravilno instalira Web server će kreirati tačno jednu instancu ove klase. Ova instanca se koristi za obrađivanje svih zahteva koji pristignu od klijenata. 104

110 Server će, tipično, kreirati posebnu programsku nit za obradu svakog pojedinog zahteva klijenta. (Ovakva struktura servera je opisana u poglavlju 4). U okviru tih niti će se pozivati metoda doget unapred inicijalizovanog servlet objekta. To znači da se može desiti da se metoda doget pozove nad jednim istim servlet objektom istovremeno. Prilikom pisanja servleta to se mora imati u vidu tako da se obezbedi sinhronizovani pristup resursima koji to zahtevaju. Ovaj problem ilustruje sledeći primer. Servlet klasa AccessTest sadrži atribut hitcount koji sadrži broj pristupa datom servletu. Brojanje pristupa se obavlja inkrementiranjem ovog brojača u okviru metode doget. Samo inkrementiranje mora biti sinhronizovana operacija, u ovom primeru definisana metodom inc. Sinhronizacija se obavlja nad samim servlet objektom, pozivom metode inc. Svi zahtevi klijenata biće upućivani na isti servlet objekat, pa će se samim tim koristiti i isti atribut koji služi kao brojač. Konačan efekat je da će svaki korisnik u stranici koju je tražio dobiti izveštaj o ukupnom broju pristupa toj stranici. import javax.servlet.*; import javax.servlet.http.*; import java.io.*; /** Servlet koji demonstrira sinhronizovani pristup * deljenim resursima. */ public class AccessTest extends HttpServlet { // Obrada GET zahteva public void doget( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setcontenttype("text/html"); PrintWriter out = response.getwriter(); out.println("<html><body>"); out.println("ovoj stranici je pristupano "+inc()+" puta."); out.println("</body></html>"); private synchronized int inc() { return ++hitcount; private int hitcount; 8.7 Praćenje sesije korisnika U odeljku 8.1 prikazan je HTTP protokol i tamo je naglašeno kako on ne omogućava praćenje sesije korisnika. Kako bi se ovaj cilj ipak postigao definisano je pomoćno rešenje. Radi se o mehanizmu slanja kolačića (cookies) između klijenta i servera koga je uveo Netscape Navigator, a kasnije je postao standardan mehanizam za ovu namenu podržan od svih Web čitača i servera. 105

111 Princip rada cookie mehanizma prikazan je na slici 8.6. Prilikom slanja prvog zahteva server će ustanoviti da mu klijent nije poslao cookie kao jednu stavku u zaglavlju zahteva. U odgovor na taj zahtev server će dodati cookie. Ukoliko je Web čitač podešen tako da radi sa cookie-ima, on će u svim sledećim zahtevima koje bude slao tom serveru uključiti i cookie, tako da će server moći da prepozna klijenta koga je već ranije opsluživao. Šta je jedan cookie zapravo? Možemo ga shvatiti kao string od tipično nerazumljivih znakova koji je namenjen za jednoznačno identifikovanje korisnika na serveru. 1) zahtev HTTP klijent 2) odgovor + cookie HTTP server a) 1) zahtev + cookie HTTP klijent 2) odgovor + cookie HTTP server b) Slika 8.6. a) slanje prvog zahteva i prijem odgovora koji uključuje cookie b) svi sledeći zahtevi sadrže cookie Iako je moguće pristupiti cookie informacijama iz servleta, to nije potrebno činiti radi praćenja sesije korisnika. Za tu svrhu na raspolaganju su funkcije višeg nivoa koje će biti ilustrovane na sledećem primeru. Posmatrajmo servlet čiji je zadatak da generiše stranicu sa izveštajem o broju pristupa toj stranici od strane svakog korisnika. Dakle, potrebno je uočiti razliku između više korisnika, što primer u odeljku 8.6 nije činio. Realizacija je jednostavna kada se koristi klasa HttpSession, koja opisuje korisničku sesiju. Ona služi kao kontejner za objekte koji opisuju datog korisnika. U taj kontejner se mogu smestiti objekti pod nekim imenom, a kasnije se tim objektima može pristupiti na osnovu tog imena. Za potrebe brojanja pristupa nekoj stranici koristićemo objekte klase SessionCounter. class SessionCounter { public int getcount() { return count; public void setcount(int c) { count = c; public void inc() { count++; private int count = 0; Sada sledi programski kod servlet klase. import javax.servlet.*; import javax.servlet.http.*; import java.io.*; 106

112 public class SessionTest extends HttpServlet { public void doget(httpservletrequest req, HttpServletResponse res) throws IOException, ServletException { // pokupimo session objekat HttpSession session = req.getsession(true); // probamo da pokupimo brojač pristupa u ovoj sesiji SessionCounter sc = (SessionCounter)session.getValue("brojac"); res.setcontenttype("text/html"); PrintWriter out = res.getwriter(); out.println("<html><body>"); // ispiši ID sesije out.println("<b>sesija ID:" + session.getid() + "</b>"); // ako je getvalue vratio null, onda je ovo prvi // pristup toj stranici, inače je u pitanju neki sledeći if (sc!= null) { sc.inc(); out.println(", ukupno pristupa:" + sc.getcount() + ".<br>"); else { out.println(", prvi pristup.<br>"); sc = new SessionCounter(); sc.inc(); session.putvalue("brojac", sc); out.println("</body></html>"); Posmatrajmo šta se dešava prilikom prvog pristupa servletu. Prva stvar koja se uradi unutar doget metode je preuzimanje HttpSession objekta. Preporuka je da se ovo radi kao prva stvar u okviru doget metode, čak i pre poziva setcontenttype. Dobijeni objekat odgovara sesiji korisika čiji zahtev upravo obrađujemo za to se pobrinuo Web server pomoću cookie mehanizma. Zatim se nad tim objektom poziva metoda getvalue, što predstavlja pokušaj da se pristupi objektu koji je ranije smešten u kontejner pod nazivom brojac. U pitanju je objekat klase SessionCounter. Ukoliko poziv metode getvalue ima za rezultat null, to znači da niko ranije nije već smestio objekat u kontejner pod datim imenom. Drugim rečima, u pitanju je prvi pristup servletu. U tom slučaju se kreira novi SessionCounter objekat, koji se smesti u kontejner pod imenom brojac. U suprotnom slučaju koristi se postojeći SessionCounter objekat, izvrši se njegovo inkrementiranje i u stranicu se ugradi izveštaj o broju pristupa. Slično ovom primeru, svi servleti kod kojih je potrebno pristupati informacijama o korisničkoj sesiji imali bi rukovanje HttpSession objektom kao što je ovde prikazano. Ista korisnička sesija bi delila isti kontejner za objekte u različitim servletima. 107

113 8.8 Preuzimanje podataka sa HTML formi HTML forme su jedini način da korisnik unosi neke podatke koristeći Web čitač. Preuzimanje podataka iz forme je neophodno kako bi se ti podaci negde smestili radi trajnog čuvanja. Slika 8.7 prikazuje izgled jedne HTML stranice sa formom za unos imena i prezimena korisnika, i izgled stranice na koju se upućuje Web čitač prilikom klika na dugme Pošalji. a) b) Slika 8.7. a) stranica sa HTML formom b) stranica na koju se Web čitač upućuje nakon klika na dugme Pošalji Prva stranica je statička HTML stranica, čiji sadržaj sledi (elementi forme su naglašeni, ostatak predstavlja formatiranje): <HTML> <HEAD> <TITLE>Primer sa formom</title> </HEAD> <BODY> <h1>unesite podatke</h1> <form action="formtest"> <table cellspacing=0 cellpadding=3 border=0> <tr> <td align=right>ime:</td> <td><input type="text" name="ime"></td> </tr> <tr> <td align=right>prezime:</td> <td><input type="text" name="prezime"></td> </tr> <tr> <td align=right> </td> <td><input type="submit" value=" Posalji "></td> </tr> </table> </form> </body> </html> Atribut action taga form koji obuhvata elemente forme (polja za unos i dugme) navodi stranicu na koju će se preći kada korisnik klikne na dugme Pošalji. U pitanju je naziv servleta koji će prikazati narednu stranicu. Zahtev koga će Web 108

114 čitač poslati u tom trenutku imaće ugrađene i podatke iz forme. Podaci će biti navedeni u sledećem obliku: ime=branko&prezime=milosavljevic Dakle, vrednosti u pojedinim poljima se navode kao parovi ime=vrednost, gde je ime naziv polja, a vrednost sadržaj koji je korisnik uneo. Više ovakvih parova se razdvaja ampersand znakom (&). Može se reći da stranica na koju se upućuje Web čitač prilikom klika na dugme ima parametre; ima ih onoliko koliko ima polja u HTML formi prethodne stranice GET i POST zahtevi Postoji više načina da se parametri, tj. sadržaj popunjene forme, prenese novoj stranici. Ukoliko Web čitač novu stranicu zahvata GET komandom, tada se parametri dodaju na kraj adrese nove stranice iza jednog upitnika. Sledeći primer predstavlja zahtev čitača u tom slučaju. GET /kurs/formtest?ime=branko&prezime=milosavljevic HTTP/ Druga mogućnost je da se parametri pošalju kao deo zahteva koji sadrži POST komandu: POST /kurs/formtest HTTP/ ime=branko&prezime=milosavljevic Razlika je, sa stanovišta korisnika, vidljiva u adresi stranice koja se vidi u okviru čitača. Slika 8.8 prikazuje varijante kada se koristi GET i POST komanda. a) b) Slika 8.8. a) stranica dobijena GET zahtevom b) stranica dobijena POST zahtevom 109

115 Podaci uneti u formi su vidljivi u adresi stranice kada se koristi GET zahtev, što može biti neprikladno u slučaju da su podaci poverljivi. Iz tog razloga se najčešće i koristi POST metod za prenos parametara. Mesto gde se navodi metod prenosa parametara je polazna HTML stranica. Tag form ima atribut method za tu namenu. Atribut može imati vrednosti get i post, a ako se izostavi podrazumeva se vrednost get. Sledi primer: <form action="formtest" method="post"> Sadržaj popunjenih polja forme se šalje, kroz parametre, novoj stranici. Ta stranica može biti statička HTML stranica, ali ona tada ne može imati nikakve koristi od tih parametara; da bi se parametri na neki način interpretirali potrebna je dinamička stranica koju možemo generisati odgovarajućim servletom. Stranica sa slike 8.7.b je upravo takva stranica koju je generisao sledeći servlet. import javax.servlet.*; import javax.servlet.http.*; import java.io.*; public class FormTest extends HttpServlet { // obrada POST zahteva public void dopost( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // preuzimamo vrednost parametra "ime" String ime = request.getparameter("ime"); // preuzimamo vrednost parametra "prezime" String prezime = request.getparameter("prezime"); response.setcontenttype("text/html"); PrintWriter out = response.getwriter(); out.println("<html><body><h1>evo sta ste uneli:</h1>"); out.println("ime: "+ime+"<br>"); out.println("prezime: "+prezime+"<br>"); out.println("</body></html>"); out.close(); // obrada GET zahteva public void doget( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { dopost(request, response); Vidimo da se parametrima stranice može pristupiti pomoću metode getparameter objekta request. Vrednosti tih parametara mogu se koristiti kasnije 110

116 na proizvoljan način. Ovde su upotrebljene tako da su ugrađene u tekst rezultujuće HTML stranice; na primer, moguće je smestiti ove podatke u tekuću sesiju pomoću HttpSession objekta, koji je opisan u odeljku 8.7. Ovaj servlet redefiniše metode doget i dopost, kako bi mogao da odgovori na obe vrste zahteva. Metoda doget samo poziva metodu dopost, čime se postiže da servlet jednako reaguje na POST i GET zahteve klijenta. 8.9 Pristup bazama podataka iz servleta Za pristup bazama podataka iz servleta koristi se JDBC interfejs, opisan u poglavlju 6. Korišćenje JDBC interfejsa unutar servleta ne razlikuje se ni na koji način od korišćenja unutar klasične Java aplikacije. Sledi primer servleta koji pristupa bazi podataka radi listanja svih registrovanih nastavnika (u pitanju je šema baze podataka korišćena u poglavlju 6). Rezultat rada servleta je HTML stranica sa listom svih nastavnika pobrojanih u tabeli nastavnici. import javax.servlet.*; import javax.servlet.http.*; import java.sql.*; import java.util.*; import java.io.*; public class DBServlet extends HttpServlet { /** Inicijalizacija servleta: otvaranje veze sa bazom */ public void init(servletconfig config) throws ServletException { super.init(config); try { Class.forName("oracle.jdbc.driver.OracleDriver"); conn = DriverManager.getConnection( "jdbc:oracle:thin:@branko.tmd.ns.ac.yu:1526:vta", "vta", "vta"); catch (Exception ex) { ex.printstacktrace(); /** Uništavanje servleta: zatvaranje veze sa bazom */ public void destroy() { try { conn.close(); catch (SQLException ex) { ex.printstacktrace(); public void doget(httpservletrequest req, 111

117 HttpServletResponse res) throws ServletException, IOException { try { // postavljanje upita String query = "SELECT ime, prezime FROM nastavnici"; Statement stmt = conn.createstatement(); ResultSet rset = stmt.executequery(query); Vector imena = new Vector(); Vector prezimena = new Vector(); while (rset.next()) { imena.addelement(rset.getstring(1)); prezimena.addelement(rset.getstring(2)); rset.close(); stmt.close(); // generisanje HTML stranice res.setcontenttype("text/html"); PrintWriter out = res.getwriter(); out.println("<html><body>"); out.println("<h3>nastavnici u bazi:</h3>"); out.println("<pre>"); for (int i = 0; i < imena.size(); i++) out.println( (String)(imena.elementAt(i)) + " " + (String)(prezimena.elementAt(i))); out.println("</pre></body></html>"); out.flush(); catch (Exception ex) { // generisanje HTML stranice sa opisom greške res.setcontenttype("text/html"); PrintWriter out = res.getwriter(); out.println("<html><body><pre>"); out.println("dogodila se greska:<br> " + ex.tostring() + "</pre></body></html>"); out.flush(); /** Konekcija sa bazom podataka */ private Connection conn; Ovaj servlet ima redefinisanu metodu init, u okviru koje se učitava JDBC drajver i otvara konekcija sa bazom podataka. Ova konekcija je atribut klase, tako da je dostupna iz svih metoda, uključujući i doget. U okviru metode destroy konekcija se zatvara. Ovakav koncept znači da će jedan servlet koristiti tačno jednu konekciju za sve zahteve. To može biti rešenje koje je zgodno naročito kada se softver za upravljanje bazom podataka licencira po aktivnoj konekciji u ovom slučaju neograničen broj korisnika Web sajta sa ovim servletom imao bi 112

118 pristup bazi podataka preko samo jedne konekcije. Međutim, treba imati u vidu da su moguće situacije kada se ista konekcija koristi za operacije nad bazom podataka iz više programskih niti. Neki JDBC drajveri, kao što je Oracle, ne dopuštaju izvršavanje DML operacija iz više niti istovremeno preko iste konekcije, tako da ovo rešenje ima smisla samo kada se postavljaju upiti (oni se mogu paralelno izvršavati iz više niti). Alternativa ovom rešenju je da se prilikom svake obrade GET zahteva otvara nova konekcija, koja se odmah zatim i zatvara. Ova varijanta je izuzetno neefikasna, jer je otvaranje konekcije sa bazom podataka dugotrajna operacija. Još jedno rešenje ovog problema biće prikazano u okviru poglavlja

119 Poglavlje 9 Java Server Pages 9.1 JSP koncept Prethodno poglavlje predstavlja kratak pregled mogućnosti i načina upotrebe servlet tehnologije za dinamičko generisanje HTML stranica. Koncept servleta ima dobrih osobina, npr. prenosivost servleta na različite računarske platforme i Web servere, efikasno izvršavanje, itd. Međutim, osnovna mana servleta je što je generisanje HTML teksta smešteno unutar servlet klase. To znači da je teško razdvojiti posao Web dizajnera i programera: obe vrste autora moraju da modifikuju iste fajlove sa Java izvornim kodom. Veliki broj Web dizajnera nije vičan programiranju u Javi (ili programiranju uopšte), što drastično otežava njihov rad u okviru projekata koji koriste servlete. Pored toga, svaka promena u izgledu stranice zahteva izmenu HTML teksta koji taj izgled opisuje. Kako je kompletan HTML tekst koji se generiše smešten unutar servleta, to svaka izmena dizajna stranice zahteva izmenu i ponovno prevođenje servleta što dodatno komplikuje njihovo korišćenje. Ideja koja se nalazi u osnovi Java Server Pages (JSP) tehnologije je da se omogući paralelan, ili bar nezavisan, rad Web dizajnera i programera. JSP stranice su tekstualne datoteke koje sadrže HTML dokumente. Pri tome se za pisanje takvih dokumenata mogu koristiti standardni HTML elementi, ali i posebni tagovi koji omogućavaju dodavanje dinamičkih elemenata u stranicu. Sledi primer fragmenta jedne takve stranice (dinamički elementi su naglašeni). <html>... <h4>dobrodošli, <%= username %></h4> Danas je <%= new java.util.date() %>.... </html> Na mestu gde se nalazi specijalni tag <%=username%> biće ugrađeno korisničko ime tekuće prijavljenog korisnika, na primer. Realizacija JSP tehnologije je posebno zanimljiva: ovako napisana JSP stranica će poslužiti da se na osnovu nje generiše servlet koji će proizvesti upravo onakvu HTML stranicu kako je to specificirano u JSP stranici. Takav servlet se 114

120 generiše kao klasična datoteka sa izvornim Java kodom. Nakon generisanja servleta, vrši se prevođenje servlet klase u Java byte-code. Tako prevedeni servlet se može koristiti na poznati način da proizvede rezultujuću HTML stranicu. Sekvenca događaja je, tačnije, sledeća: autor JSP stranice smešta datu stranicu u odgovarajući direktorijum Web servera. Kada neki Web klijent prvi put zatraži datu stranicu, Web server će na osnovu nje automatski generisati odgovarajući servlet, prevesti ga i zatim pokrenuti. Prilikom narednih zahteva za tom JSP stranicom biće dovoljno samo pozvati odgovarajuću metodu servleta. Da li će izvorni kod generisanog servleta biti dostupan ili ne zavisi od Web servera. 9.2 Vrste dinamičkih elemenata Ovaj odeljak prikazuje nekoliko vrsta dinamičkih elemenata koje uvodi JSP Izrazi JSP izrazi su elementi koji se nalaze između znakova <%= i %>. Sadržaj ovog elementa može biti proizvoljan Java izraz. Treba obratiti pažnju na to da se izrazi ne završavaju znakom tačka-zarez. Izrazi mogu biti proizvoljnog tipa. Za izraze koji nisu tipa String poziva se metoda tostring kako bi se dobila odgovarajuća string reprezentacija koja će se ugraditi u stranicu. test.jsp <html> <head> <title>jsp izrazi</title> </head> <body> <h3>primeri JSP izraza</h3> Danasnji datum: <%= new java.util.date() %> </body> </html> Izraz new java.util.date() predstavlja kreiranje novog objekta klase Date. Takav objekat se inicijalizuje na tekući datum i vreme u trenutku kreiranja. Kako je u pitanju izraz koji nije tipa String, prilikom ugradnje ove vrednosti u stranicu biće pozvana metoda tostring klase Date koja će obezbediti odgovarajuću string reprezentaciju ovog objekta. Konačan rezultat je stranica koja će prilikom svakog pristupa prikazati datum i vreme kada je pristup izvršen Skriptleti JSP skriptleti su elementi koji se pojavljuju između znakova <% i %>. Njihov sadržaj je proizvoljan segment Java programskog koda. Ovako ugrađen programski kod direktno se ugrađuje u kod generisanog servleta na odgovarajuće mesto! Sledi primer jedne JSP stranice: <html>... <% if (Math.random() < 0.5) { %> Dobar dan! <% else { %> 115

121 Dobro veče! <% %>... </html> Iz primera se vidi da segment Java koda koji je sadržaj skiptleta ne mora predstavljati validan Java iskaz, već samo njegov fragment. Evo kako bi se ovakva JSP stranica prevela u servlet (ugrađeni fragmenti su naglašeni): class GenerisaniServlet extends HttpServlet { public void doget(...) {... out.println("<html>");... if (Math.random() < 0.5) { out.println("dobar dan!"); else { out.println("dobro veče!");... out.println("</html>"); Može se reći da se svaki red JSP stranice koji sadrži samo klasične HTML oznake konvertuje u jedan out.println(...) iskaz u servletu. JSP skriptleti se ugrađuju u servlet na odgovarajućem mestu direktnim kopiranjem datog teksta. Jedna od posledica ovakvog tretiranja skriptleta je i da opseg važenja promenljivih definisanih u skriptletima može da se proteže kroz više skriptleta. Sledi primer koji ilustruje ovu osobinu: <table border=1> <% String names[] = { "Bata", "Pera", "Mika", "Laza", "Sima" ; for (int i = 0; i < names.length; i++) { %> <tr> <td><%= i %></td> <td><%= names[i] %></td> </tr> <% %> </table> Gornji primer proizvodi HTML tabelu koja ima onoliko redova koliko je elemenata niza names. Promenljiva names i brojač petlje i dostupni su i u narednim skriptletima. Generisani HTML kod koga će primiti Web čitač izgledao bi ovako: <table border=1> <tr> <td>0</td> <td>bata</td> </tr> <tr> <td>1</td> 116

122 <td>pera</td> </tr> <tr> <td>2</td> <td>mika</td> </tr> <tr> <td>3</td> <td>laza</td> </tr> <tr> <td>4</td> <td>sima</td> </tr> </table> Deklaracije JSP deklaracije su elementi koji se pojavljuju između znakova <%! i %>. Deklaracije sadrže tekst koji će u rezultujući servlet biti smešten na mestu atributa ili metode servlet klase. Na primer, deklaracija <%! int hitcount = 0; %> proizvešće sledeći atribut servlet klase: class GenerisaniServlet extends HttpServlet {... int hitcount = 0; Ovakav atribut servlet klase je dostupan u višestrukim pozivima doget ili dopost metode servleta. Primer u odeljku 8.6 ilustrovao je upotrebu ovakvog atributa. Ovde navodimo primer koji sličan efekat postiže u JSP okruženju. <%! int hitcount = 0; %> <html> <body> <h3>primer JSP deklaracije</h3> Ovoj stranici je ukupno pristupano <%= ++hitcount %> puta. </body> </html> Ovaj primer ne koristi sinhronizovan pristup atributu hitcount zbog jednostavnosti. Metoda inc primera iz odeljka 8.6 se takođe može dodati kao JSP deklaracija. Položaj JSP deklaracije u okviru JSP stranice nije bitan Direktive JSP direktive su elementi smešteni između znakova <%@ i %>. Namenjene su za obavljanje nekih specifičnih zadataka u okviru JSP stranice. Ovde ćemo navesti neke primere. <%@ page import="java.util.*" %> 117

123 Dodavanje odgovarajuće import deklaracije na početak generisanog servleta. Nakon ovakve direktive ne mora se više pisati, na primer, java.util.date nego samo Date za naziv klase. page contenttype="text/plain" %> Ekvivalentno je pozivu setcontenttype metode response objekta u servletu. <%@ include file="included.jsp" %> Uključuje kompletan sadržaj stranice included.jsp u tekuću stranicu. Uključena stranica može biti JSP stranica, pri čemu će se ona posebno interpretirati i takav sadžaj biti uključen u tekuću stranicu. Može biti i statička HTML stranica. 9.3 Predefinisane promenljive U okviru JSP stranica moguće pristupati izvesnom broju unapred definisanih promenljivih. Te promenljive su nabrojane u tabeli 9.1. Ime promenljive Tip promenljive request HttpServletRequest response HttpServletResponse out JspWriter session HttpSession application ServletContext config ServletConfig pagecontext PageContext page (this) Tabela 9.1. Predefinisane promenljive u JSP stranicama Najčešće se koristi request promenljiva koju smo često sretali i u prethodnom poglavlju. Sledi jedan primer upotrebe ove promenljive: <html>... <% if (request.getparameter("username")!= null) { %> Vrednost parametra: <%= request.getparameter("username") %> <% %>... </html> U primeru se pristupa parametrima stranice na isti način kako se to čini i unutar klasičnog servleta. 9.4 Skladištenje podataka i JavaBeans Podaci iz HTML formi koje unosi korisnik prenose se na način kako je to opisano u odeljku 8.8. JSP omogućava jednostavno preuzimanje parametara stranice i njihovo smeštanje u svojstva (properties) neke JavaBean komponente. Posmatrajmo HTML stranicu sa formom kao na slici

124 Slika 9.1 HTML forma Forma sadrži dva polja čiji su nazivi, recimo, username i password. Sadržaj ovih polja biće prenet kroz parametre novoj stranici nakon klika na dugme Pošalji. U okviru te nove stranice možemo smestiti ove podatke u sledeću JavaBean komponentu: public class User { public void setusername(string x) { username = x; public void setpassword(string x) { password = x; public String getusername() { return username; public String getpassword() { return password; private String username; private String password; Evo kako bi mogla da izgleda JSP stranica na koju se prelazi klikom na dugme Pošalji: <jsp:usebean id="user" class="somepackage.user"/> <jsp:setproperty name="user" property="username" param="username"/> <jsp:setproperty name="user" property="password" param="password"/> <html>... </html> Prvi specijalni tag, jsp:usebean, deklariše objekat sa nazivom user klase somepackage.user. Sledeći specijalni tag, jsp:setproperty, postavlja vrednost svojstva username objekta user na vrednost parametra stranice koji se zove username. Treći specijalni tag radi istu stvar za svojstvo password. Objekat user je dostupan u ostatku stranice (slično kao da je u pitanju JSP deklaracija). Na primer: <html>... <% if (user.login()) { %> Uspešno ste se prijavili! <% else { %> Niste se uspešno prijavili! 119

Osnove programskog jezika C# Čas 4. Nasledjivanje 2. deo

Osnove programskog jezika C# Čas 4. Nasledjivanje 2. deo Osnove programskog jezika C# Čas 4. Nasledjivanje 2. deo Nasledjivanje klasa Modifikator new class A { public virtual void F() { Console.WriteLine("I am A"); } } class B : A { public override void F()

More information

Osnove programskog jezika C# Čas 5. Delegati, događaji i interfejsi

Osnove programskog jezika C# Čas 5. Delegati, događaji i interfejsi Osnove programskog jezika C# Čas 5. Delegati, događaji i interfejsi DELEGATI Bezbedni pokazivači na funkcije Jer garantuju vrednost deklarisanog tipa. Prevodilac prijavljuje grešku ako pokušate da povežete

More information

PREDMET. Osnove Java Programiranja. Čas JAVADOC

PREDMET. Osnove Java Programiranja. Čas JAVADOC PREDMET Osnove Java Programiranja JAVADOC Copyright 2010 UNIVERZITET METROPOLITAN, Beograd. Sva prava zadržana. Bez prethodne pismene dozvole od strane Univerziteta METROPOLITAN zabranjena je reprodukcija,

More information

Svi Java tipovi imaju ekvivalentan tip u jeziku Scala Većina Scala koda se direktno preslikava u odgovarajući Java konstrukt

Svi Java tipovi imaju ekvivalentan tip u jeziku Scala Većina Scala koda se direktno preslikava u odgovarajući Java konstrukt Funkcionalno programiranje Interoperabilnost jezika Scala i Java Prevođenje u Java bajt kod Svi Java tipovi imaju ekvivalentan tip u jeziku Scala Većina Scala koda se direktno preslikava u odgovarajući

More information

Programiranje III razred

Programiranje III razred Tehnička škola 9. maj Bačka Palanka Programiranje III razred Naredbe ciklusa for petlja Naredbe ciklusa Veoma često se ukazuje potreba za ponavljanjem nekih naredbi više puta tj. za ponavljanjem nekog

More information

Uputstvo za korišćenje logrotate funkcije

Uputstvo za korišćenje logrotate funkcije Copyright AMRES Sadržaj Uvod 3 Podešavanja logrotate konfiguracionog fajla 4 Strana 2 od 5 Uvod Ukoliko je aktivirano logovanje za RADIUS proces, može se desiti da posle određenog vremena server bude preopterećen

More information

PROGRAMIRANJE. Amir Hajdar

PROGRAMIRANJE. Amir Hajdar PROGRAMIRANJE Amir Hajdar Teme 2 Klase i objekti u Javi Primjer kroz klasu Krug Atributi i metode Inicijalizacija objekata (konstruktori) Polymorphism Statičke varijable i metode This Klase i objekti u

More information

pojedinačnom elementu niza se pristupa imeniza[indeks] indeks od 0 do n-1

pojedinačnom elementu niza se pristupa imeniza[indeks] indeks od 0 do n-1 NIZOVI Niz deklarišemo navođenjemtipa elemenata za kojim sledi par srednjih zagrada[] i naziv niza. Ako je niz višedimenzionalni između zagrada[] se navode zarezi, čiji je broj za jedan manji od dimenzija

More information

GUI - događaji (Events) i izuzeci. Bojan Tomić

GUI - događaji (Events) i izuzeci. Bojan Tomić GUI - događaji (Events) i izuzeci Bojan Tomić Događaji GUI reaguje na događaje (events) Događaj je neka akcija koju korisnik programa ili neko drugi izvrši korišćenjem perifernih uređaja (uglavnom miša

More information

Programske paradigme Funkcionalna paradigma

Programske paradigme Funkcionalna paradigma Programske paradigme Funkcionalna paradigma 1. čas: Uvod u funkcionalno programiranje. Programski jezik Haskel. Upoznavanje sa razvojnim okruženjem. Tipovi podataka. Funkcionalno programiranje Stil u programiranju

More information

NIZOVI.

NIZOVI. NIZOVI LINKOVI ZA KONZOLNI C# OSNOVNO http://www.mycity.rs/net/programiranje-u-c-za-osnovce-i-srednjoskolce.html http://milan.milanovic.org/skola/csharp-00.htm Niz deklarišemo navođenjem tipa elemenata

More information

Projektovanje Namenskih Računarskih Struktura 1. Sistemi zasnovani na Androidu

Projektovanje Namenskih Računarskih Struktura 1. Sistemi zasnovani na Androidu Univerzitet u Novom Sadu Fakultet tehničkih nauka Odsek za računarsku tehniku i računarske komunikacije Projektovanje Namenskih Računarskih Struktura 1 Sistemi zasnovani na Androidu Objektno orijentisani

More information

PITANJA ZA II KOLOKVIJUM NASLJEĐIVANJE, VIRTUELNE FUNKCIJE I POLIMORFIZAM

PITANJA ZA II KOLOKVIJUM NASLJEĐIVANJE, VIRTUELNE FUNKCIJE I POLIMORFIZAM PITANJA ZA II KOLOKVIJUM NASLJEĐIVANJE, VIRTUELNE FUNKCIJE I 1. Definicija svake klase sadrzi kljucnu rec iza koje se navodi ime klase: class public extends 2. Kada je funkcija clanica definisana izvan

More information

Uvod u programiranje - vežbe. Kontrola toka izvršavanja programa

Uvod u programiranje - vežbe. Kontrola toka izvršavanja programa Uvod u programiranje - vežbe Kontrola toka izvršavanja programa Naredbe za kontrolu toka if, if-else, switch uslovni operator (?:) for, while, do-while break, continue, return if if (uslov) naredba; if

More information

VRIJEDNOSTI ATRIBUTA

VRIJEDNOSTI ATRIBUTA VRIJEDNOSTI ATRIBUTA Svaki atribut (bilo da je primarni ključ, vanjski ključ ili običan atribut) može i ne mora imati ograničenja na svojim vrijednostima. Neka od ograničenja nad atributima: Null / Not

More information

Java. Ugnježdeni tipovi IMI PMF KG OOP 09 AKM. najveći deo teksta je preuzet sa slajdova Prof. Dragana Milićeva (ETF Bg) namenjenih pedmetu OOP2

Java. Ugnježdeni tipovi IMI PMF KG OOP 09 AKM. najveći deo teksta je preuzet sa slajdova Prof. Dragana Milićeva (ETF Bg) namenjenih pedmetu OOP2 Java IMI PMF KG OOP 0 AKM 1 Ugnježdeni tipovi najveći deo teksta je preuzet sa slajdova Prof. Dragana Milićeva (ETF Bg) namenjenih pedmetu OOP2 Ugneždeni tipovi IMI PMF KG OOP 0 AKM 2 Unutrašnje klase

More information

Uputstvo za podešavanje mail klijenta

Uputstvo za podešavanje mail klijenta Uputstvo za podešavanje mail klijenta 1. Podešavanje Thunderbird mail klijenta 1.1 Dodavanje mail naloga Da biste podesili Vaš mail klijent (u ovom slučaju Thunderbird) da prima i šalje mail-ove potrebno

More information

PITANJA ZA II KOLOKVIJUM KLASE I OBJEKTI

PITANJA ZA II KOLOKVIJUM KLASE I OBJEKTI PITANJA ZA II KOLOKVIJUM KLASE I OBJEKTI 1. Enkapsulacija je podataka. skrivanje apstrakcija nasledivanje 2. Unutar deklaracije klase navode se: definicije funkcija clanica prototipovi (deklaracije) funkcija

More information

VHDLPrimeri Poglavlje5.doc

VHDLPrimeri Poglavlje5.doc 5. VHDL opis kola koja obavljaju osnovne aritmetičke funkcije Sabirači Jednobitni potpuni sabirač definisan je tablicom istinitosti iz Tabele 5.1. Tabela 5.1. cin a b sum cout 0 0 0 0 0 0 0 1 1 0 0 1 0

More information

CSS CSS. selector { property: value; } 3/20/2018. CSS: Cascading Style Sheets

CSS CSS. selector { property: value; } 3/20/2018. CSS: Cascading Style Sheets CSS CSS CSS: Cascading Style Sheets - Opisuje izgled (appearance) i raspored (layout) stranice - Sastoji se od CSS pravila, koji defini[u skup stilova selector { property: value; 1 Font face: font-family

More information

Računarske osnove Interneta (SI3ROI, IR4ROI)

Računarske osnove Interneta (SI3ROI, IR4ROI) Računarske osnove terneta (SI3ROI, IR4ROI) Vežbe MPLS Predavač: 08.11.2011. Dražen Drašković, drazen.draskovic@etf.rs Autori: Dražen Drašković Naučili ste na predavanjima MPLS (Multi-Protocol Label Switching)

More information

Događaj koji se javlja u toku izvršenja programa i kvari normalno izvršenje. Kada se desi izuzetak, sistem pokušava da pronađe način da ga obradi.

Događaj koji se javlja u toku izvršenja programa i kvari normalno izvršenje. Kada se desi izuzetak, sistem pokušava da pronađe način da ga obradi. Obrada izuzetaka Šta je izuzetak? Događaj koji se javlja u toku izvršenja programa i kvari normalno izvršenje. Kada se desi izuzetak, sistem pokušava da pronađe način da ga obradi. Prosleđuje izuzetak,

More information

PRINCIPI SOFTVERSKOG INŽENJERSTVA TIM NAZIV_TIMA

PRINCIPI SOFTVERSKOG INŽENJERSTVA TIM NAZIV_TIMA PRINCIPI SOFTVERSKOG INŽENJERSTVA TIM NAZIV_TIMA SPECIFIKACIJA BAZE PODATAKA ZA PROJEKAT NAZIV_PROJEKTA Veb knjižara - Specifikacija baze podataka 1 10.04.2017. Verzija V 1.0 Datum: 20. mart 2017. Istorija

More information

OBJEKTNO ORIJENTISANO PROGRAMIRANJE

OBJEKTNO ORIJENTISANO PROGRAMIRANJE OBJEKTNO ORIJENTISANO PROGRAMIRANJE PREDAVANJE 12: NASLEĐIVANJE Miloš Kovačević Đorđe Nedeljković 1 /17 OSNOVNI KONCEPTI - Statički i dinamički tipovi podataka - Prepisivanje metoda superklase - Polimorfizam

More information

Microsoft Hyper-V Server 2016 radionica EDU IT Pro, Zagreb,

Microsoft Hyper-V Server 2016 radionica EDU IT Pro, Zagreb, Microsoft Hyper-V Server 2016 radionica EDU IT Pro, Zagreb, 13.04.2017. Podešavanje Hyper-V Servera 2016 za RSAT upravljanje Dario Štefek Lokacije za preuzimanje: Microsoft Hyper-V Server 2016 https://www.microsoft.com/en-us/evalcenter/evaluate-hyper-v-server-2016

More information

Vežbe - XII nedelja PHP Doc

Vežbe - XII nedelja PHP Doc Vežbe - XII nedelja PHP Doc Dražen Drašković, asistent Elektrotehnički fakultet Univerziteta u Beogradu Verzija alata JavaDoc za programski jezik PHP Standard za komentarisanje PHP koda Omogućava generisanje

More information

UNIVERZITET U BEOGRADU ELEKTROTEHNIČKI FAKULTET

UNIVERZITET U BEOGRADU ELEKTROTEHNIČKI FAKULTET UNIVERZITET U BEOGRADU ELEKTROTEHNIČKI FAKULTET Katedra za elektroniku Računarska elektronika Grupa br. 11 Projekat br. 8 Studenti: Stefan Vukašinović 466/2013 Jelena Urošević 99/2013 Tekst projekta :

More information

Prirodno-matematički fakultet u Nišu Departman za fiziku. dr Dejan S. Aleksić Programiranje u fizici

Prirodno-matematički fakultet u Nišu Departman za fiziku. dr Dejan S. Aleksić Programiranje u fizici Programiranje u fizici Prirodno-matematički fakultet u Nišu Departman za fiziku dr Dejan S. Aleksić Programiranje u fizici 7-8 Definicija, inicijalizacija promenljivih 2/21 u C-u Program napisan u programskog

More information

TEHNIKA I INFORMATIKA U OBRAZOVANJU

TEHNIKA I INFORMATIKA U OBRAZOVANJU TEHNIKA I INFORMATIKA U OBRAZOVANJU Konferencija 32000 Čačak 9-11. Maja 2008. UDK: 004 : 371 Stručni rad VEZA ZAVISNOSTI ACCESS Momčilo Vujičić 1, Munir Šabanović 2 Rezime: U radu je opisana veza zavisnosti

More information

Rekurzivne metode. Posmatrajmo rekurzivan metod kojim u objektu listbox1 klase ListBox upisujemo sve prirodne brojeve od 1 do datog n.

Rekurzivne metode. Posmatrajmo rekurzivan metod kojim u objektu listbox1 klase ListBox upisujemo sve prirodne brojeve od 1 do datog n. Rekurzivne metode Rekurzivan metod je onaj metod koji u nekoj svojoj instrukciji sadrži poziv samog sebe. Svakako prilikom kreiranja rekurzivnog metoda moramo voditi računa da ne dodje do beskonačne rekurzije

More information

Programiranje III razred

Programiranje III razred Tehnička škola 9. maj Bačka Palanka Programiranje III razred Konverzija tipova Konverzija tipova Prilikom komunikacije aplikacije sa korisnikom, korisnik najčešće unosi ulazne podatke koristeći tastaturu.

More information

Jezik Baze Podataka SQL. Jennifer Widom

Jezik Baze Podataka SQL. Jennifer Widom Jezik Baze Podataka SQL SQL o Jezik koji se koristi u radu sa relacionim bazama podataka o Nije programski jezik i manje je kompleksan. o Koristi se isključivo u radu za bazama podataka. o SQL nije case

More information

Oracle Proprietary Joins Za upite nad više od jedne tabele korišćenjem Oracle proprietary sintakse koristiti join uslov u WHERE izrazu:

Oracle Proprietary Joins Za upite nad više od jedne tabele korišćenjem Oracle proprietary sintakse koristiti join uslov u WHERE izrazu: Database Programming with SQL kurs 2017 database design and programming with sql students slajdovi 7-1 Oracle Equijoin and Cartesian Product Prethodna sekcija se bavila upitima preko više od jedne tabele

More information

Vidljivost TipPovratneVrednosti ImeFunkcije (NizParametara) { TeloFunkcije }

Vidljivost TipPovratneVrednosti ImeFunkcije (NizParametara) { TeloFunkcije } 1. FUNKCIJE I STRUKTRUE PROGRAMA Složeni problemi lakše se rašavaju ako se podele na manje celine koje mogu nezavisno da se rešavaju. Rešenje celokupnog složenog problema dobija se kombinovanjem rešenja

More information

Sberbank Business Online na Mozilla FireFox

Sberbank Business Online na Mozilla FireFox Sberbank Business Online na Mozilla FireFox Verzija 1.6 Srpanj 2016. Sberbank d.d. Stranica 1 SADRŽAJ 1 INSTALACIJA... 2 2 POKRETANJE MOZILLE FIREFOX... 3 2.1 IMPORT SECURITY MODULA... 4 2.2 AUTOMATSKI

More information

Modbus TCP i dva PLC S7 1200

Modbus TCP i dva PLC S7 1200 Industrijski sistemi i protokoli Modbus TCP i dva PLC S7 1200 1 Modbus TCP i dva PLC S7 1200 Laboratorijski deo - obavezno: Detaljno proučiti i testirati već napravljeni projekat za PLC-ove, koji se nalazi

More information

12. Uskladištene procedure (Stored Procedures)

12. Uskladištene procedure (Stored Procedures) 12. Uskladištene procedure (Stored Procedures) Uskladištena procedura je skup SQL iskaza koji su kompajlirani i sačuvani u trenutku njenog kreiranja. Veoma su moćne i preko njih mogu da se izvršavaju sve

More information

24/03/2018. Deklaracija promenljivih. Inicijalizacija promenljivih. Deklaracija i inicijalizacija promenljivih

24/03/2018. Deklaracija promenljivih. Inicijalizacija promenljivih. Deklaracija i inicijalizacija promenljivih Deklaracija promenljivih Inicijalizacija promenljivih Deklaracija promenljive obuhvata: dodelu simboličkog imena promenljivoj i određivanje tipa promenljive (tip određuje koja će vrsta memorijskog registra

More information

Dežurni nastavnik: Kolokvijum traje 1.5 sat, prvih sat vremena nije dozvoljeno napuštanje kolokvijuma. Upotreba literature nije dozvoljena.

Dežurni nastavnik: Kolokvijum traje 1.5 sat, prvih sat vremena nije dozvoljeno napuštanje kolokvijuma. Upotreba literature nije dozvoljena. Dežurni nastavnik: Elektrotehnički fakultet u Beogradu Katedra za računarsku tehniku i informatiku Predmet: Testiranje Softvera (SI3TS) Nastavnik: doc. dr Dragan Bojić Asistent: dipl. ing. Dražen Drašković

More information

Algoritmi i strukture podataka 2. Čas, Uvod u C++

Algoritmi i strukture podataka 2. Čas, Uvod u C++ Algoritmi i strukture podataka 2. Čas, Uvod u C++ Aleksandar Veljković 2017/2018 1 Uvod Jezik C++ je jezik koji pripada objektno orijentisanoj paradigmi, ipak, u okviru ovog kursa naglasak neće biti na

More information

f2() f6() main() f3() f7() f4()

f2() f6() main() f3() f7() f4() VI Potprogrami i funkcije Uobičajeno je da se pri pisanju programa koji treba da reše složene probleme, problemi razlažu na niz jednostavnijih(elementarnih) delova Za njihovo rešavanje se pišu nezavisni

More information

Tema 8: Koncepti i teorije relevantne za donošenje odluka (VEŽBE)

Tema 8: Koncepti i teorije relevantne za donošenje odluka (VEŽBE) Tema 8: Koncepti i teorije relevantne za donošenje odluka (VEŽBE) SISTEMI ZA PODRŠKU ODLUČIVANJU dr Vladislav Miškovic vmiskovic@singidunum.ac.rs Fakultet za računarstvo i informatiku 2013/2014 Tema 8:

More information

Izrada VI laboratorijske vježbe

Izrada VI laboratorijske vježbe Izrada VI laboratorijske vježbe 1. Programirati proceduru koja se aktivira sa Standard palete alatki klikom na button Fajlovi. Prilikom startovanja procedure prikazuje se forma koja sadrži jedan list box

More information

Lekcija 02 Uslovni iskazi i petlje, Funkcije. Miljan Milošević

Lekcija 02 Uslovni iskazi i petlje, Funkcije. Miljan Milošević Lekcija 02 Uslovni iskazi i petlje, Funkcije Miljan Milošević USLOVNI ISKAZI I PETLJE, FUNKCIJE 01 02 03 04 Uvod Uslovni iskazi i Ciklusi Operatori skoka Funkcije u C-u grananja Uslovni iskaz if Uslovni

More information

Uputstva za instaliranje čitača Datalogic Skorpio u operativnom sistemu Windows 7 i višim POM-NA-XX-46, V3.0

Uputstva za instaliranje čitača Datalogic Skorpio u operativnom sistemu Windows 7 i višim POM-NA-XX-46, V3.0 POM - Pomoć korisnicima Uputstva za instaliranje čitača Datalogic Skorpio u operativnom sistemu Windows 7 i višim POM-NA-XX-46, V3.0 IZUM, 2016 COBISS, COMARC, COBIB, COLIB, IZUM su zaštićeni znaci u posedu

More information

public static void main(string []args) { System.out.println("Hello World"); /* prints Hello World */

public static void main(string []args) { System.out.println(Hello World); /* prints Hello World */ Java Uvod Hello world primer Java program predstavlja skup objekata koji prozivaju jedni drugima metode i tako komuniciraju. Izvorni kod se uvek čuva u datotekama sa ekstenzijom.java. Ispod je predstavljen

More information

Windows Server 2012, VDI Licenciranje najprodavanijeg servera, što je novo, VDI licenciranje. Office 2013 / Office 365

Windows Server 2012, VDI Licenciranje najprodavanijeg servera, što je novo, VDI licenciranje. Office 2013 / Office 365 Windows 8 Licenciranje, razlike u verzijama Windows Server 2012, VDI Licenciranje najprodavanijeg servera, što je novo, VDI licenciranje Serverski proizvodi Server 2012, System centar 2012, SQL 2012, Sharepoint

More information

Sveučilište u Zagrebu PMF Matematički odsjek. Mreže računala. Vježbe 08. Zvonimir Bujanović Slaven Kožić Vinko Petričević

Sveučilište u Zagrebu PMF Matematički odsjek. Mreže računala. Vježbe 08. Zvonimir Bujanović Slaven Kožić Vinko Petričević Sveučilište u Zagrebu PMF Matematički odsjek Mreže računala Vježbe 08 Zvonimir Bujanović Slaven Kožić Vinko Petričević Uvod: (X)HTML i CSS Na ovim i idućim vježbama naučit ćemo osnove jezika za opisivanje

More information

Učitati cio broj n i štampati njegovu recipročnu vrijednost. Ako je učitan broj 0, štampati 1/0.

Učitati cio broj n i štampati njegovu recipročnu vrijednost. Ako je učitan broj 0, štampati 1/0. Kontrolne naredbe Primjeri: Opšti oblik razgranate strukture (if sa ) if (uslov) Naredba 1 ili blok naredbi1 Naredba 2 ili blok naredbi2 Učitati broj x i štampati vrijednost double x, z; Scanner in=new

More information

Cjenovnik usluga informacionog društva

Cjenovnik usluga informacionog društva Cjenovnik usluga informacionog društva Verzija: 01/2018 Sadržaj 1 Web hosting 3 2 Registracija domena 3 3 Internet marketing 3 4 E mail paketi 4 5 Virtuoz 4 6 Internet Security servis 5 7 Kolokacija servera

More information

Mašinska vizija. Dr Nenad Jovičić tnt.etf.rs/~mv

Mašinska vizija. Dr Nenad Jovičić tnt.etf.rs/~mv Mašinska vizija Dr Nenad Jovičić 2017. tnt.etf.rs/~mv Linearne 2D geometrijske transformacije 2D geometrijske transformacije Pretpostavka: Objekti u 2D prostoru se sastoje iz tačaka i linija. Svaka tačka

More information

Sadržaj. Verzija 03/2017 Primjenjuje se od 20. novembra godine

Sadržaj. Verzija 03/2017 Primjenjuje se od 20. novembra godine Sadržaj 1 Web hosting 3 2 Registracija domena 3 3 Internet marketing 3 4 E mail paketi 4 5 Virtuoz 4 6 Internet Security servis 5 7 Kolokacija servera 6 8 Cloud usluge 6 9 Aktivni servisi koji nijesu u

More information

VMware Workstation. VMwareWorkstation ESX ($) (vmotion, DRS, HA, Storage vmotion) vcenter Server ($) Server. Guest OS

VMware Workstation. VMwareWorkstation ESX ($) (vmotion, DRS, HA, Storage vmotion) vcenter Server ($) Server. Guest OS VMware Workstation ESX ($) vcenter Server ($) (license manager) Server hardware (vmotion, DRS, HA, Storage vmotion) ESXi (freeware) (ESXi freeware is managed by the Virtual Infrastructure (or vsphere)

More information

UPUTSTVO ZA KORIŠĆENJE NOVOG SPINTER WEBMAIL-a

UPUTSTVO ZA KORIŠĆENJE NOVOG SPINTER WEBMAIL-a UPUTSTVO ZA KORIŠĆENJE NOVOG SPINTER WEBMAIL-a Webmail sistem ima podršku za SSL (HTTPS). Korištenjem ovog protokola sva komunikacija između Webmail sistema i vašeg Web čitača je kriptovana. Prilikom pristupa

More information

b) program deljiv3; uses wincrt; var i:integer; begin i:=3; while i<100 do begin write(i:5); i:=i+3; end; end.

b) program deljiv3; uses wincrt; var i:integer; begin i:=3; while i<100 do begin write(i:5); i:=i+3; end; end. NAREDBA CIKLUSA SA PREDUSLOVOM WHILE 1.Odrediti vrednosti s i p nakon izvrsenja sledecih naredbi za dato a=43, a=34, a=105 program p1; var a,s,p:integer; write('unesite a:');readln(a); p:=a; s:=0; while

More information

Prva recenica. Druga recenica.

Prva recenica. Druga recenica. Algoritmi i programiranje Predavanje 4 METODE LOKALNE, GLOBALNE VARIJABLE I KONSTANTE METODA je imenovani izdvojeni slijed naredbi koji rješava određeni zadatak i po potrebi se poziva jednom ili više puta

More information

Informatika Uvod u C#,.NET Framework i Visual Studio... nastavak...

Informatika Uvod u C#,.NET Framework i Visual Studio... nastavak... Informatika Uvod u C#,.NET Framework i Visual Studio... nastavak... Prof. dr. sc. Tomislav Pribanić Izv. prof. dr. sc. Vedran Podobnik Doc. dr. sc. Marija Seder Sveučilište u Zagrebu Fakultet elektrotehnike

More information

Marko Milošević.

Marko Milošević. Marko Milošević marko643@gmail.com marko.milosevic@pmf.edu.rs ESPB 8 Bodovanje Domaći Kolokvijumi 2x10 2x20 Završni ispit 40 Konsultacije sreda 13-14 četvrtak 16-17 Šabloni dizajna (Design Patterns) Metrika

More information

Programiranje Programski jezik C. Sadržaj. Datoteke. prof.dr.sc. Ivo Ipšić 2009/2010

Programiranje Programski jezik C. Sadržaj. Datoteke. prof.dr.sc. Ivo Ipšić 2009/2010 Programiranje Programski jezik C prof.dr.sc. Ivo Ipšić 2009/2010 Sadržaj Ulazno-izlazne funkcije Datoteke Formatirane datoteke Funkcije za rad s datotekama Primjeri Datoteke komunikacija između programa

More information

VDSL modem Zyxel VMG1312-B10A/B30A

VDSL modem Zyxel VMG1312-B10A/B30A VDSL modem Zyxel VMG1312-B10A/B30A Default Login Details LAN IP Address http://192.168.2.1 User Name user Password 1234 Funkcionalnost lampica Power lampica treperi kratko vrijeme nakon uključivanja modema,

More information

2. Linijska algoritamska struktura

2. Linijska algoritamska struktura Univerzitet u Nišu Građevinsko-arhitektonski fakultet Informatika 2 2. Linijska algoritamska struktura Milica Ćirić Blokovi za prikaz algoritma Algoritam se vizuelno može prikazati pomoću blok dijagrama,

More information

VB komande. Programiranje 1

VB komande. Programiranje 1 VB komande Programiranje 1 Zadatak 1: Sastaviti program koji se sastoji iz jedne ListBox kontrole, jedne Textbox kontrole i dva komandna dugmeta. Klikom na prvo komandno dugme umeće se u ListBox sadržaj

More information

Veliki računski zadaci mogu se razbiti u manje delove i time se omogućava ljudima da iskoriste ono što su neki drugi već uradili, umesto da počinju

Veliki računski zadaci mogu se razbiti u manje delove i time se omogućava ljudima da iskoriste ono što su neki drugi već uradili, umesto da počinju Staša Vujičić Čas 9 Veliki računski zadaci mogu se razbiti u manje delove i time se omogućava ljudima da iskoriste ono što su neki drugi već uradili, umesto da počinju sve od početka. Odgovarajuće funkcije

More information

PARALELNO PROGRAMIRANJE

PARALELNO PROGRAMIRANJE Predavanje 09 Odjel za matematiku 1 PARALELNO PROGRAMIRANJE POSIX threadovi za C++ Predavanje 09 Odjel za matematiku 2 Programske niti (thread) unutar procesa Danas ćemo se upoznati s POSIX thread bibliotekom

More information

Nasleđivanje i izvedene klase u jeziku C++

Nasleđivanje i izvedene klase u jeziku C++ Tema 08 Nasleđivanje i izvedene klase u jeziku C++ dr Vladislav Miškovic vmiskovic@singidunum.ac.rs Fakultet za informatiku i računarstvo - Tehnički fakultet OBJEKTNO ORIJENTISANO PROGRAMIRANJE 2016/2017

More information

VHDLPrimeri Poglavlje3.doc. end process seq; Slika 3.1: Anatomija osnovne definicije test bench-a

VHDLPrimeri Poglavlje3.doc. end process seq; Slika 3.1: Anatomija osnovne definicije test bench-a 3. Verifikacija projekta - Test bench entity TestBench is end entity TestBench; architecture TB_Arhitektura of TestBench is component UUT (Arhitektura_UUT) port( end component UUT; prazan entitet -- deklarisanje

More information

JavaScript i HTML DOM

JavaScript i HTML DOM 4. vježbe iz WEB programiranja četvrtak, 22. ožujka 2012. JavaScript 1. dio JavaScript i Što je DOM? Kako JS koristi DOM? Pristup elementima dokumenta Promjena i učitavanje vrijednosti tagova Primjer 1.

More information

var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); begin ListBox1.Items.LoadFromFile('d:\brojevi.

var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); begin ListBox1.Items.LoadFromFile('d:\brojevi. 1 PANEL komponenta kontejnerska, slična GropBox. Roditeljska komponenta za komp. postavljene na nju. Zajedno se pomeraju. Caption svojstvo za naziv; Alighment pomera svojstvo Caption levo i desno; Align

More information

Java IMI PMF KG OOP 09 AKM. Objekti i klase

Java IMI PMF KG OOP 09 AKM. Objekti i klase Java 1 Objekti i klase Usage Modifiers 2 Uz varijable je moguće koristiti modifikatore static -označava varijablu koja je zajednička svim objektima koji su instance date klase final -definiše konstante

More information

[] znači opciono; znači ili. Strana 3 od 5

[] znači opciono; znači ili. Strana 3 od 5 Database Programming with SQL kurs 2017 database design and programming with sql students slajdovi 2-1 Columns Characters and Rows Concatenation (pridruživanje) stanje povezanosti kao kod lanca; unija

More information

Uvod u relacione baze podataka

Uvod u relacione baze podataka Uvod u relacione baze podataka Ana Spasić 5. čas 1 Podupiti, operatori exists i in 1. Izdvojiti imena i prezimena studenata koji su položili predmet čiji je identifikator 2001. Rešenje korišćenjem spajanja

More information

operativni sistem part 2

operativni sistem part 2 operativni sistem part 2 zagrevanje... update komandna linija, nastavak... mnoštvo programa (jezik se zaboravlja ako se ne govori) scripting, bash, sh malo uvoda u Python, IDLE, idle malo C (ni)malo IDE,

More information

PROGRAMIRANJE. Teme. Packages Reference objekata Inheritance nasljeđivanje Exceptions. Amir Hajdar

PROGRAMIRANJE. Teme. Packages Reference objekata Inheritance nasljeđivanje Exceptions. Amir Hajdar PROGRAMIRANJE Amir Hajdar Teme 2 Packages Reference objekata Inheritance nasljeđivanje Exceptions Packages API Application Programmer Interface Sve klase ponuđene u sklopu Java jezika, uključujući i kompajler

More information

Projektovanje namenskih računarskih struktura

Projektovanje namenskih računarskih struktura Univerzitet u Novom Sadu Fakultet tehničkih nauka Odsek za računarsku tehniku i računarske komunikacije Projektovanje namenskih računarskih struktura Mehanizam JNI i upotreba u Androidu i aplikacijama

More information

Programski jezici. leto

Programski jezici. leto Programski jezici leto 2010-11 Grafički programi Koriste grafičke mogućnosti: boje, fontove, geometrijske oblike, slike,... Komuniciraju sa korisnikom preko grafičkog korisničkog interfejsa koji se sastoji

More information

Numerical Computation

Numerical Computation GNU Octave Numerical Computation vrlo često u tehnici retko stvarni problemi imaju closed-form solution čak i kad imaju, pitanje upotrebljivosti mnogo detalja numerički pristup u početku tretirano kao

More information

Programski jezik JAVA PREDAVANJE

Programski jezik JAVA PREDAVANJE Programski jezik JAVA PREDAVANJE 8 2018 www.etf.ac.me Polja za potvrdu i Radio tasteri Polja za potvrdu i radio tasteri nijesu uzajamno isključivi, što znači da ako imate pet polja za potvrdu u jednom

More information

Objektno orijentisano programiranje

Objektno orijentisano programiranje Matematički fakultet, Univerzizet u Beogradu Katedra za računarstvo i informatiku Objektno orijentisano programiranje vežbe Biljana Stojanović Nemanja Mićović Nikola Milev 1 Stringovi String literali i

More information

KOMPAJLIRANJE IZVORNOG KODA U UPRAVLJIVE MODULE SOURCE CODE COMPILATION INTO MANAGED MODULES

KOMPAJLIRANJE IZVORNOG KODA U UPRAVLJIVE MODULE SOURCE CODE COMPILATION INTO MANAGED MODULES TEHNOLOGIJA, INFORMATIKA I OBRAZOVANJE ZA DRUŠTVO UČENJA I ZNANJA 6. MeĎunarodni Simpozijum, Tehnički fakultet Čačak, 3 5. jun 2011. TECHNOLO GY, INFO RM ATICS AND EDUCATION FOR LEARNING AND KNOWLEDGE

More information

Visoka tehnička škola Niš

Visoka tehnička škola Niš Visoka tehnička škola Niš Studijski program: Savremene računarske tehnologije Internet programiranje (7) Nasleđivanje klasa u Javi Prof. dr Zoran Veličković, dipl. inž. el. Novembar, 2017. Nasleđivanje

More information

Univerzitet u Nišu Građevinsko-arhitektonski fakultet. 4. Ciklična algoritamska struktura 5. Jednodimenzionalno polje.

Univerzitet u Nišu Građevinsko-arhitektonski fakultet. 4. Ciklična algoritamska struktura 5. Jednodimenzionalno polje. Univerzitet u Nišu Građevinsko-arhitektonski fakultet Informatika 2 4. Ciklična algoritamska struktura 5. Jednodimenzionalno polje Milica Ćirić Ciklična algoritamska struktura Ciklična struktura (petlja)

More information

Bežična topologija. Kategorije bežičnih mreža po površini pokrivanja

Bežična topologija. Kategorije bežičnih mreža po površini pokrivanja Danas su bežične mreže sastavni deo društva i njegov veliki činilac u delu razmene podataka i informacija. Bežične mreže za razliku od ostalih tipova mreža nemaju ograničenja u smislu vezanosti za mrežne

More information

namespace spojneice { public partial class Form1 : Form { public Form1() { InitializeComponent(); }

namespace spojneice { public partial class Form1 : Form { public Form1() { InitializeComponent(); } Spojnice using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.IO;

More information

Informacioni sistemi i baze podataka

Informacioni sistemi i baze podataka Fakultet tehničkih nauka, Novi Sad Predmet: Informacioni sistemi i baze podataka Dr Slavica Kordić Milanka Bjelica Vojislav Đukić Rad u učionici (1/2) Baze podataka (db2015): Studentska korisnička šema

More information

Osnove programskog jezika C#

Osnove programskog jezika C# Deklaracija i inicijalizacija promenljive u C# Osnove programskog jezika C# Deklaracija: int x; // samo deklaracija Inicijalizacija: x = 10; Deklaracija sa inicijalizacijom: int x = 10; Inicijalizcija

More information

Programski jezik JAVA

Programski jezik JAVA Programski jezik JAVA 1.1. L i teratu ra 1. L. Lemay, Ch.L. Perkins, Teach Yourself JAVA in 21 Days, Sums- Net, 1996. 2. P.Niemeyer, J. Peck, Exploring Java, O Reilly & Associates, Inc.1996. 3. K. Arnold,

More information

Visoka tehnička škola Niš

Visoka tehnička škola Niš Visoka tehnička škola Niš Studijski program: Savremene računarske tehnologije.net tehnologije (7) Klase, objekti i svojstva u C#-u Prof. dr Zoran Veličković, dipl. inž. el. Novembar, 2017. Osnovni pojmovi

More information

4. Fajlovi i direktorijumi

4. Fajlovi i direktorijumi 4.2 stat, fstat i lstat funkcije 4. Fajlovi i direktorijumi int stat(const char *path, struct stat *buf); int fstat(int fd, struct stat *buf); int lstat(const char *path, struct stat *buf); Ove 3 funkcije

More information

VEŽBA 5 do while petlja, switch case

VEŽBA 5 do while petlja, switch case VEŽBA do while petlja, switch case Petlja sa ulaznim uslovom do while U slučaju do while petlje obavezno izvršavanje bar jedne iteracije se postiže tako što je upravljački izraz petlje na samom dnu petlje.

More information

1/42 SQL DDL. CREATE ALTER DROP Schema Table Tablespace Index View Domain Constraint... DECLARE TABLE (DB2)

1/42 SQL DDL. CREATE ALTER DROP Schema Table Tablespace Index View Domain Constraint... DECLARE TABLE (DB2) 1/42 SQL DDL CREATE ALTER DROP Schema Table Tablespace Index View Domain Constraint... DECLARE TABLE (DB2) 2/42 SQL DDL: CREATE SCHEMA CREATE SCHEMA ime-sheme [ AUTHORIZATION ime-vlasnika-sheme] [ CREATE

More information

KLASIFIKACIJA JELENA JOVANOVIĆ. Web:

KLASIFIKACIJA JELENA JOVANOVIĆ.   Web: KLASIFIKACIJA JELENA JOVANOVIĆ Email: jeljov@gmail.com Web: http://jelenajovanovic.net PREGLED PREDAVANJA Šta je klasifikacija? Binarna i više-klasna klasifikacija Algoritmi klasifikacije Mere uspešnosti

More information

Ovde će se raditi na funkcijama konverzija: konverzija tipa datuma u znak tip i obrnuto, konverzija broja u karakter tip i obrnuto

Ovde će se raditi na funkcijama konverzija: konverzija tipa datuma u znak tip i obrnuto, konverzija broja u karakter tip i obrnuto Database Programming with SQL kurs 2017 database design and programming with sql students slajdovi 5-1 Conversion Functions U db formatiranje i promene izgleda se izvode pomoću funkcija konverzija Ove

More information

Lekcija 4. Java programiranje sa bazama podataka. dr Svetlana Cvetanović

Lekcija 4. Java programiranje sa bazama podataka. dr Svetlana Cvetanović Lekcija 4 Java programiranje sa bazama podataka dr Svetlana Cvetanović JAVA PROGRAMIRANJE SA BAZAMA PODATAKA Uvod 01 02 03 04 Uvod JDBC Interfejsi Vežba: Preduslovi za pisanje Java koda Zaključak Kreiranje

More information

Ciljevi. Poslije kompletiranja ove lekcije trebalo bi se biti u mogućnosti: Opisati ograničenja Generisati i održavati ograničenja u bazi

Ciljevi. Poslije kompletiranja ove lekcije trebalo bi se biti u mogućnosti: Opisati ograničenja Generisati i održavati ograničenja u bazi Ograničenja Ciljevi Poslije kompletiranja ove lekcije trebalo bi se biti u mogućnosti: Opisati ograničenja Generisati i održavati ograničenja u bazi Generisati i održavati ograničenja u bazi podataka Uvod

More information

Programiranje 1 Programski jezik C 2. čas. Mirko Spasić

Programiranje 1 Programski jezik C 2. čas. Mirko Spasić Programiranje 1 Programski jezik C 2. čas Mirko Spasić Operatori U C-u postoji veliki broj operatora. Mogu biti unarni (imaju jedan argument) i binarni (dva argumenta). Unarni operatori mogu biti prefiksni

More information

Lekcija 07 C++ funkcije, stringovi, imenski prostor, memorija i fajlovi. Miljan Milošević

Lekcija 07 C++ funkcije, stringovi, imenski prostor, memorija i fajlovi. Miljan Milošević Lekcija 07 C++ funkcije, stringovi, imenski prostor, memorija i fajlovi Miljan Milošević C++ FUNKCIJE, STRINGOVI, IMENSKI PROSTOR, UPRAVLJANJE MEMORIJOM I FAJLOVI 01 02 03 04 Uvod Reference Funkcije u

More information

Korisničko uputstvo za instalaciju i podešavanje securew2 programa za pristup eduroam servisu

Korisničko uputstvo za instalaciju i podešavanje securew2 programa za pristup eduroam servisu Korisničko uputstvo za instalaciju i podešavanje securew2 programa za pristup eduroam servisu Termin supplicant se koristi u IEEE 802.1X standardu. U širem značenju, ovaj termin predstavlja entitet (korisnik

More information

Java Server Pages. 31-Dec-12

Java Server Pages. 31-Dec-12 Java Server Pages 31-Dec-12 Prednosti JSP Pomoću JSP se mogu uraditi iste stvari kao i pomoću servleta, ali korišćenje JSP olakšava pisanje samog HTML koda čitanje i održavanje HTML koda U odnosu na korišćenje

More information

Lekcija 01 Uvodna razmatranja, Uvod u C. Miljan Milošević

Lekcija 01 Uvodna razmatranja, Uvod u C. Miljan Milošević Lekcija 01 Uvodna razmatranja, Uvod u C Miljan Milošević UVODNA RAZMATRANJA, UVOD U C 01 02 03 04 Uvod Uvodna razmatranja Faze generisanja programa Osnovna anatomija C programa Program sa više fajlova

More information

IV SQL. Slika 1. SQL*Plus ikona. Slika 2. Dijalog provere identifikacije korisnika. Slika 3. Prozor SQL*Plus programa

IV SQL. Slika 1. SQL*Plus ikona. Slika 2. Dijalog provere identifikacije korisnika. Slika 3. Prozor SQL*Plus programa IV SQL SQL (Structured Query Language) je jezik koji je Američki Institut za Nacionalne Standarde (ANSI - American National Standards Institute) prihvatio kao standardni jezik za relacione baze podataka.

More information