370 likes | 456 Views
Mrezno racunarstvo. glava 7 URLs and URIs. klasa URL. klasa URL je najjednostavniji na čin da Java program locira i dobije podatke sa mreže ne treba brinuti o protokolu koji se koristi niti o formatu dobijenih podataka, kao ni o tome kako se komunicira sa serverom
E N D
Mrezno racunarstvo glava 7 URLs and URIs
klasa URL • klasa URL je najjednostavniji način da Java program locira i dobije podatke sa mreže • ne treba brinuti o protokolu koji se koristi niti o formatu dobijenih podataka, kao ni o tome kako se komunicira sa serverom • prosto se Javi kaže URL i ona dobije podatke za nas. • u narednim poglavljima se opisuje kako instalirati nove content i protocol handler-e i proširiti Javine mogućnosti da uključe nove protokole i nove tipove podataka. Takođe, i kako se otvaraju soketi i komunicira direktno sa različitim vrstama servera • sada, pogledajmo koliko se može učiniti sa minimumom rada
java.net.URL • je apstrakcija Uniform Resource Locator-a poput http://hamsterdance.com/ ili ftp://ftp.redhat.com/pub/ • nasleđuje java.lang.Object i final je (ne može se koristiti kao bazna za neku novu klasu) • iako bi čuvanje URL-a kao String-a bilo trivijalno, korisno je misliti o URL-ovima kao objektima čija polja uključuju shemu (protokol), hostname, port, putanju, query string i fragment (ref) od kojih svako može biti nezavisno postavljeno. • upravo tako je ova klasa i organizovana, s tim da detalji variraju u zavisnosti od verzija Jave
polja ove klase su vidljiva samo drugim članovima java.net paketa, dok im klase koje nisu članice ovog paketa ne mogu pristupati direktno • ipak, moguće je postaviti ova polja korišćenjem URL konstruktora i dobiti njihove vrednosti korišćenjem različitih get*() metoda (getHost(), getPort()...) • URL je efektivno nepromenljiv. Nakon kreiranja URL objekta, njegova polja se ne menjaju. Bočni efekat je da su thread-safe
Kreiranje novih URL-ova • moguće je kreirati instance klase java.net.URL • postoji nekoliko konstruktora • svi oni izbacuju MalformedURLException ako pokušamo da kreiramo URL za nepodržani protokol ili ako je URL sintaksno neispravan • Koji su tačno protokoli podržani zavisi od platforme • jedini protokoli koji su dostupni u svim osnovnim VM su http i file • Java 1.5 takođe zahteva da VMpodržava https, jar i ftp • većina VM takođe podržava ftp, mailto i gopher kao i protokole poput doc, netdoc, systemresource i verbatim koje Java interno koristi • Microsoft VM podržava http, file, ftp, https, mailto, gopher, doc i systemresource, ali ne telnet, netdoc, jar ili verbatim • Podrška za sve ove protokole je u apletima ograničena security policy-jem. • Npr. samo zato što nepoverljivi aplet može konstruisati URL objekat od URL-a fajla ne znači da aplet zaista može i čitati taj fajl • Ako protokol koji nam treba nije podržan od strane određene VM, možemo instalirati protocol handler za tu shemu. To je praktično samo za aplikacije (ne i za aplete, jer je predmet brojnih sigurnosnih provera)
Osim provere da li prepoznaje URL shemu, Java ne vrši nikakve provere ispravnosti URL-a koji konstruiše • Programer je odgovoran za ispravnost URL-ova. • npr. Java ne proverava da hostname u HTTP URL-u ne sadrži beline ili da li je query string x-www-form-URL-encoded. ne proverava da mailto URL zaista sadrži email adresu. ne proverava da li URL pokazuje na postojeći host itd. • moguće je kreirati URL-ove za host-ove koji ne postoje ili koji postoje, ali nije dopušteno konektovati se na njih
Konstruisanje URL-a od String-a • jedini argument – String sa apsolutnim URL-om • public URL(String url) throws MalformedURLException • try{ URL u = new URL(”http://www.audubon.org/”); }catch(MalformedURLException ex){ System.err.println(ex); } • primer 1 • jednostavan program zaodređivanje koje protokole podržava VM. Pokušava da konstruiše URL objekat za svaki od 14 protokola (8 standardnih, 3 custom protokola za različite Java API-je i 4 nedokumentovana koje interno koristi HotJava) Ako konstruktor uspe, znamo da je protokol podržan. Inače, izbacuje se MalformedURLException i znamo da protokol nije podržan.
Konstruisanje URL-a od komponenti • od 3 stringa koja zadaju protokol, hostname i file • public URL(String protocol, String hostname, String file) throws MalformedURLException • ovaj konstruktor postavlja port na -1 tako da će biti korišćen podrazumevani port za protokol • argument file treba da počinje sa / i da uključi putanju, ime fajla i opciono fragment. Zaboravljanje početnog / je uobičajena greška koja se ne uočava lako • try{ URL u = new URL(”http”, ”www.eff.org”, ”/blueribbon.html#intro”); } catch(MalformedURLException ex){ // All VMs should recognize http } • ovim se kreiraobjekatkojipokazujenahttp://www.eff.ofg/blueribbon.html#introkojikoristipodrazumevani port za HTTP protokol (port 80). Specifikacijafajlauključuje referencu na imenovano sidro
U retkim situacijama kada podrazumevani port nije ispravan, sledeći konstruktor dopušta da se port eksplicitno zada kao int: • public URL(String protocol, String host, int port, String file) throws MalformedURLException • try{ URL u = new URL(”http”, ”fourier.dur.ac.uk”, 8000, ”/~dma3mjh/jsci/”); }catch(MalformedURLException ex){ System.err.println(ex); } • kreira URL kojipokazujenahttp://fourier.dur.ac.uk:8000/~dma3mjh/jscigde je port 8000 eksplicitnozadat
Konstruisanje relativnih URL-ova • Konstruktorgradiapsolutni URL odrelativnog URL ibaznog URL: • public URL(URL base, String relative) throws MalformedURLException • npr. ako parsiramo HTML dokument na http://www.ibiblio.org/javafaq/index.html i nađemo link na fajl mailinglists.html bez daljih kvalifikujućih informacija, koristimo URL dokumenta koji sadrži link kako bismo obezbedili informacije koje nedostaju
try{ URL u1 = new URL(”http://www.ibiblio.org/javafaq/index.html”); URL u2 = new URL(u1, ”mailinglists.html”); }catch(MalformedURLException ex){ System.err.println(ex); } • Imefajla se uklanjaizputanje u1, a zatim se nadovezujeimefajla mailinglists.html ipravi u2. • ovajkonstruktor je posebnokoristankadaželimo da prolazimo kroz listu fajlova koji su svi u istom direktorijumu. Može se kreirati URL za prvi fajl, a potom koristiti za kreiranje URL objekata drugih fajlova zamenom njihovih imena. • ovaj konstruktor se takođe koristi kada se želi kreirati URL relativan u odnosu na document base ili code base apleta, koji se mogu dobiti sa getDocumentBase() i getCodeBase() klase JApplet. • primer 2 • jednostavan aplet koji koristi getDocumentBase() za kreiranje novog URL objekta • kada se koristi ovaj konstruktor sa getDocumentBase(), često se poziv getDocumentBase() smešta unutar konstruktora: • URL relative = new URL(this.getDocumentBase(), ”mailinglists.html”);
Zadavanje URLStreamHandler-a • 2 konstruktora dopuštaju zadavanje protocol handler-a koji se koristi za URL • public URL(URL base, String relative, URLStreamHandler handler) throws MalformedURLException • public URL(String protocol, String host, int port, String file, URLStreamHandler handler) throws MalformedURLException • Svi URL objekti imaju URLStreamHandler objekte koji rade posao za njih. Ovi konstruktori su korisni za rad sa URL-ovima čije sheme nisu podržane u određenoj VM, kao i za dodavanje funkcionalnosti koje podrazumevani stream handler ne pruža, poput traženja korisničkog imena i šifre korisnika
Drugi izvori URL objekata • Osim opisanih konstruktora, brojni drugi metodi Javine biblioteke klasa vraćaju URL objekte • getDocumentBase() klase JApplet • getCodeBase() – vraća URL samog apleta umesto URL-a stranice koja sadrži aplet • toURL() metod klase java.io.File vraća URL fajla. Tačan format vraćenog URL-a fajla platformski je zavisan. U praksi, file URL-ovi su jako platformski i programski zavisni.
Loaderi klasa ne učitavaju samo klase, već i resurse poput slika i audio fajlova. Statički metod ClassLoader.getSystemResource(String name) vraća URL pojedinačnog resursa. • ClassLoader.getSystemResources(String name) vraća Enumeration koja sadrži listu URL-ova sa kojih imenovani resurs može biti pročitan • instancni metod getResource(String name)pretražuje putanju koju koristi loader klase kako bi pronašao URL imenovanog resursa
URI može biti konvertovan u URL korišćenjem metoda toURL() • Postoji još nekolicina metoda koji vraćaju URL objekte, ali to su uglavnom prosti getter metodi koji samo vraćaju URL koji verovatno već znamo jer smo ga koristili za konstruisanje objekta: getPage() klase java.swing.JEditorPane i getURL() klase java.net.URLConnection
Rastavljanje URL-a na delove • URL se sastoji iz 5 delova: • shema ili protokol • authority • path • fragment/section/ref • query string • http://www.ibiblio.org/javafaq/books/jnp/index.html?isbn=1565922069#toc • shema je http • authority www.ibiblio.org • path /javafaq/books/jnp/index.html • fragment toc • query string isbn=1565922069 • Međutim, nemaju svi URL-ovi sve ove delove
authority može dalje biti podeljen na user info, host i port • http://admin@www.blackstar.com:8080/ • authority je admin@www.blackstar.com:8080 • user info je admin • host www.blackstar.com • port 8080
pristup za čitanje ovih delova URL-a obezbeđen je sa sledećih 5 public metoda: • getFile(), getHost(), getPort(), getProtocol() i getRef() • getQuery(), getPath(), getUserInfo(), getAuthority() • primeri korišćenja su ubačeni u primer2
getProtocol() vraća String: ”http”, ”https” ili ”file” • getHost() vraća String koji sadrži hostname URL-a • getPort() vraća broj porta zadatog u URL-u kao int. Ako nije zadat port, vraća -1, da označi da URL ne zadaje port eksplicitno i da će biti korišćen podrazumevani port za protokol • getDefaultPort() vraća podrazumevani port koji koristi protokol URL-a. Ako za protokol nije definisan podrazumevani port, metod vraća -1
getFile() vraća String koji sadrži deo URL-a koji se odnosi na putanju. Java ne razbija URL u posebne delove za putanju i ime fajla. Sve od prvog / nakon hostname-a pa do karaktera koji prethodi # kojim počinje fragment smatra se delom fajla. Ako URL nema taj deo, metod vraća prazan string • getPath() skoro sinonim za getFile(), tj. vraća String koji sadrži putanja i fajl deo URL-a. Ipak, za razliku od getFile(), ne uključuje query string u String koji vraća, već samo putanju • primedba: ni getFile() ne vraća samo ime fajla, ni getPath() ne vraća samo putanju, kao što bi se dalo očekivati. Oba vraćaju punu putanju i ime fajla. Razlika je samo u tome što getFile() vraća i query string, a getPath() ne
getRef() vraća fragment deo URL-a, ako URL nema taj deo, metod vraća null • getQuery() vraća query string URL-a, ako ga nema u URL, metod vraća null • getUserInfo() – neki URL-ovi uključuju i korisničko ime, a povremeno i informaciju o šifri. Ovi delovi idu nakon sheme, a pre host-a i razdvojeni su simbolom @. • http://elharo@java.oreilly.com – user info je elharo • ftp://mp3:secret@ftp.example.com/%3a/stuff/mp3 user info je mp3:secret. Veći deo vremena uključivanje šifre u URL je bezbednosni rizik. Ako URL nema user info, metod vraća null • mailto URL-ovi se mogu ponašati drugačije nego što očekujemo: u URL-u poput mailto:elharo@metalab.unc.eduelharo@metalab.unc.edu je putanja, a ne user info i host. • getAuthority() – između sheme i putanje URL-a nalazi se authority. To je autoritet koji razrešava resurs. U najopštijem slučaju, autoritet uključuje user info, host i port. Međutim, nemaju svi URL-ovi sve delove
Dobijanje podataka iz URL-a • podaci sadržani u dokumentima na koje pokazuju URL-ovi • postoji nekoliko metoda za dohvatanje tih podataka iz URL-a • public InputStream openStream() throws IOException • public URLConnection openConnection() throws IOException • public URLConnection openConnection(Proxy proxy) throws IOException • public Object getContent() throws IOException • public Object getContent(Class[] classes) IOException • Ovimetodi se razlikujupo tome što vraćaju podatke sa URL-a kao instance različitih klasa
public final InputStream openStream() throws IOException • ovaj metod se konektuje na resurs referisan URL-om, vrši neophodan handshaking između klijenta i servera, i vraća InputStream iz koga se mogu čitati podaci. Podaci koji se mogu dobiti iz InputStream predstavljaju sirovi sadržaj fajla na koji referiše URL (ASCII ako čitamo ASCII fajl, HTML ako čitamo HTML fajl itd.) Oni ne uključuju nikakva HTTP zaglavlja i nikakve druge informacije vezane za protokol • Možemo čitati iz ovog InputStream kao i iz bilo kog drugog
try{ URL u = new URL(”http://www.hamsterdance.com”); InputStream in = u.openStream(); int c; while((c=in.read())!=-1) System.out.write(c); } catch(IOException ex){ System.err.println(ex); } MalformedURLException je potklasa od IOException (isti catch hvata oba)
primer 3 • čita URL iz komandne linije, otvara InputStream za taj URL, ulančava rezultujući InputStraam na InputStreamReader koristeći podrazumevano kodiranje i zatim koristi metod read() InputStreamReader-a da čita uzastopne karaktere iz fajla, od kojih svaki štampa na System.out. Tako, štampa sirove podatke smeštene na URL (ako URL referiše HTML fajl, izlaz programa je HTML) • ovaj program pretpostavlja da je udaljeni URL tekst, što nije nužno tačno. Može biti i GIF, JPEG ili MP3 ili nešto potpuno drugo. Čak i ako je tekst, kodiranje ne mora biti isto kao podrazumevano kodiranje na klijentskom sistemu. • HTTP zaglavlje koje prethodi dokumentu ima sopstvenu informaciju o kodiranju koja može biti potpuno suprotna onoj koju o sebi kaže dokument (npr. META tag za HTML). Ne možemo čitati ovo zaglavlje koristeći URL klasu, ali možemo URLConnection objektom koji vraća metod openConnection()
public URLConnection openConnection() throws IOException • otvara soket za zadati URL i vraća URLConnection objekat koji predstavlja otvorenu konekciju do mrežnog resursa • try{ URL u = new URL(”http://jennicam.org/”); try{ URLConnection uc = u.openConnection(); InputStream in = uc.getInputStream(); // read from the connection … }catch(IOException ex){ System.err.println(ex); } }catch(MalformedURLException ex){ System.err.println(ex); } • Ovaj metod se koristi kada se želi direktno komunicirati sa serverom. URLConnection nam daje pristup svemu što je server poslao dodatno uz sam dokument u neobrađenoj formi (HTML, plain text, binary image data itd) • Npr. ako je shema HTTP, URLConnection dopušta da pristupimo HTTP zaglavljima kao i HTML-u. • URLConnection takođe dopušta da se podaci pišu kao i da se čitaju iz URL-a, npr. u cilju da se pošalje email mailto URL-u ili da se postuju podaci iz forme. (URLConnection je osnovna tema poglavlja 15) • postoji i varijanta metoda koja zadaje proxy server kroz koji prolazi konekcija. Ako protocol handler ne podržava proxy-je argument se ignoriše i konekcija se pravi direktno, ako je moguće
public final Object getContent() throws IOException • dohvata podatke referisane URL-om i pokušava da ih pretvori u objekat nekog tipa • ako URL referiše na neki tekstualni objekat, poput ASCII ili HTML fajla, vraćeni objekat je obično neka vrsta InputStream-a. • ako URL referiše na sliku poput GIF ili JPEG fajla, metod obično vraća java.awt.ImageProducer (tj. instancu klase koja implementira ovaj interfejs) • Ove dve klase nisu stvari same po sebi, već sredstva pomoću kojih program može konstruisati stvar.
try{ URL u = new URL(”http://mesola.obspm.fr/”); Object o = u.getContent(); // cast the Object to the appropriate type // work with the Object … }catch(Exception ex){ System.err.println(ex); } • getContent() raditakošto gleda Content-type polje u MIME zaglavlju podataka koje dobija od servera. Ako server ne koristi MIME zaglavlja ili šalje nepoznati Content-type, getContent vraća neku vrstu InputStream-a iz kog mogu biti pročitani podaci. Izuzetak se izbacuje ako se ne može dohvatiti objekat • primer 4 • ovaj primer demonstrira veliki problem sa korišćenjem getContent(): teško je predvideti koji tip objekta ćemo dobiti. Provera tipa se jednostavno vrši instanceof operatorom.
public final Object getContent(Class[] classes) throws IOException • moguće je da content handler obezbedi različite prikaze objekta • metod dopušta da izaberemo kao objekat kojih klasa želimo da objekat bude vraćen • metod pokušava da vrati sadržaj URL-a redosledom korišćenim u nizu • onda se mora koristiti instanceof da bi se utvrdilo kog je stvarno tipa vraćeni objekat
URL u = new URL(”http://www.nwu.edu”); class[] types = new Class[3]; types[0] = String.class; types[1] = Reader.class; types[2] = InputStream.class; Object o = u.getContent(types); if(o instanceof String) System.out.println(o); else if(o instanceof Reader){ int c; Reader r = (Reader)o; while((c=r.read()) != -1) System.out.print((char)c); }else if(o instanceof InputStream){ int c; InputStream in = (InputStream)o; while((c=in.read()) != -1) System.out.write(c); }else System.out.println(“Error: unexpected type “ + o.getClass());
Utility metodi • za izvršavanje uobičajenih operacija nad URL-ovima • sameFile() određuje da li dva URL-a pokazuju na isti dokument • toExternalForm() konvertuje URL objekat u string koji se može koristiti u HTML linku ili Open URL dijalogu web browser-a.
public boolean sameFile(URL other) • poredi odgovarajuća polja na jednakost • utvrđuje samo da li su 2 hostname aliasi jedno za drugo • može reći da su http://www.ibiblio.org/ i http://metalab.unc.edu/ isti fajl • ali ne može reći da su http://www.ibiblio.org:80/ i http://metalab.unc.edu/ isti fajl ili • da su http://www.cafeonleche.org/ i http://www.cafeonleche.org/index.html isti fajl • metod je dovoljno pametan da ignoriše fragment deo URL-a • sameFile() metod je sličan equals() metodu klase URL. Glavna razlika je u tome što equals() razmatra fragment (ako postoji), dok sameFile() ne. Takođe, proizvoljan objekat može biti prosleđen kao argument metoda equals() dok samo URL objekti mogu biti prosleđeni metodu sameFile().
public String toExternalForm() • vraća čitljiv String koji predstavlja URL. Identičan je toString() metodu. Zapravo, toString vraća ono što vrati toExternalForm(). • Tako, ovaj metod je redundantan i retko se koristi
public URI toURI() throws URISyntaxException • konvertuje URL objekat u ekvivalentan URI objekat • Za operacije kao što su apsolutizacija i kodiranje, treba birati URI klasu, ako postoji mogućnost izbora. • URL klasa treba primarno da se koristi za stvarno download-ovanje sadržaja sa udaljenog servera
metodi klase Object • equals(), hashcode(), toString() • toString() – String je uvek apsolutni URL • equals() – objekat je jednak URL-u ako je takođe URL, oba pokazuju na isti fajl, što utvrđuje sameFile(), i oba URL-a imaju isti fragment (ili oba nemaju fragment). Pošto zavisi od sameFile() metoda, ima ista ograničenja kao i on. Npr. http://www.oreilly.com nije jednak sa http://www.oreilly.com/index.html. Takođe, ni http://www.oreilly.com:80/ nije jednak sa http://www.oreilly.com/. Da li ovo ima smisla zavisi od toga da li o URL-u mislimo kao o Stringu ili referenci na određeni Internet resurs. • hashCode() vraća int koji se koristi kada se URL objekti koriste kao ključevi u heš tabelama.
metodi za Protocol Handler-e • samo spominjemo, radi kompletnosti • public static synchronized void setURLStreamHandlerFactory(URLStreamHandlerFactory factory) • primarno ga koriste protocol handler-i odgovorni za nove sheme, ne programeri koji žele da dohvate podatke od URL-a. (poglavlje 16) • URLStreamHandler je odgovoran za parsiranje URL-a i zatim konstruisanja odgovarajućeg URLConnection objekta koji rukuje konekcijom sa serverom.