URLtyper i Java Hva er en classloader Kompilert






![Bravo. interpret() URLClass. Loader ucl = null; String[] lines = input. split("#"); for(int i=0; Bravo. interpret() URLClass. Loader ucl = null; String[] lines = input. split("#"); for(int i=0;](https://slidetodoc.com/presentation_image_h2/d105db4f4ddb9c1b91294de40896a3db/image-7.jpg)









![public class Hello. World{ public static void main(String[] args){ System. out. println("Hello World!"); } public class Hello. World{ public static void main(String[] args){ System. out. println("Hello World!"); }](https://slidetodoc.com/presentation_image_h2/d105db4f4ddb9c1b91294de40896a3db/image-17.jpg)























- Slides: 40
URL-typer i Java
Hva er en classloader? • Kompilert Java-kode er i et plattform-uavhengig format (en class-fil). • Et Java-program er ikke én eksekverbar fil, men består av mange class-filer. • Class-filer lastes på forespørsel fra programmet. Classloaderen er det objektet som er ansvarlig for utføring av denne jobben.
Standard classloading-struktur i J 2 SE Bootstrap classloader | Standard extensions classloader | System classloader | - - - - - Network classloader
Lasting av typer Alle typer må forstås navngitt i to faser: Lokasjon + Typenavn Fullt kvalifisert typenavn: foo. Bar Lokasjon: c: javamyclasses Lokasjon: c: javamyclasses. jar Fordeler: - Enkelt å skrive henvisninger da navnene blir relativt korte. - Ikke behov for rekompilering da man endrer miljøvariabelen CLASSPATH til å henvise til riktig lokasjon (eventuelt benytter extensions).
Bakgrunn for problemstilling • Alfa sender en melding til Bravo som sier at Bravo skal laste en klasse Help. • Bravo er avhengig av at lokasjonen til denne typen er inkludert i en av dens aktuelle classloadere. • Alfa er ikke sikker på at dette er tilfelle, og sender derfor lokasjonen først, og deretter typen som skal lastes.
Alfa. main() Socket s = new Socket(hostname, port); Print. Writer w = new Print. Writer(s. get. Output. Stream(), true); w. println("u http: //foo. org/#l Help"); w. close(); s. close();
Bravo. interpret() URLClass. Loader ucl = null; String[] lines = input. split("#"); for(int i=0; i<lines. length; i++){ char command = lines[i]. char. At(0); String param = lines[i]. split(" ")[1]; if(command == 'u'){ ucl = new URLClass. Loader(new URL[]{new URL(param)}); }else if(command == 'l'){ Class clas = null; if(ucl != null)clas = ucl. load. Class(param); else clas = Class. for. Name(param); Object o = clas. new. Instance(); } }
Help (ver. 1) Denne versjonen refererer til core API klassene: • java. lang. System • java. io. Print. Stream • java. lang. String public class Help{ public Help(){ System. out. println(”Instance created”); } }
Help (ver. 2) Denne versjonen refererer til klassene: • java. lang. System • java. io. Print. Stream • java. lang. String • equipment. Radio (http: //foo. org/) public class Help{ public Help(){ equipment. Radio. send. SOS(); System. out. println(”Instance created and SOS sent”); } }
Oppsummering • Konseptet med den underforståtte bruken av CLASSPATH + typenavn i en situasjon der adaptive programmer skal utveksle kommandoer og tilpasse seg hverandre, dekker ikke alle behov. • Forutsetningen om at programmereren kan sette CLASSPATH når det trengs, er ikke lenger levedyktig. Det blir nødvendig å uttrykke typehenvisninger som inneholder navn og informasjon om lokasjon.
Løsning: Innføre URL-typer • En URL-type inneholder navn og lokasjon. http: //foo. org/equipment. Radio r = new equipment. Radio(); • Målet med en slik løsning er å gjøre CLASSPATH-informasjon overflødig.
Krav I: Flyttbarhet • Ved representasjon av URL-typer i class-filen er det viktig at man forholder seg til JVMspesifikasjonen, slik at flyttbarheten blir sikret. • Til tross for at man benytter URL-typer i en classloader-struktur som ikke er modifisert, er det krav om at det skal være mulig å laste og kjøre refererende typer.
Class-filen: Generelt • Inneholder definisjonen av én klasse eller interface. • En gyldig representasjon av en klasse eller et interface uavhengig av form. • Inneholder en strøm av 8 -bit bytes • JVM-spesifikasjonen, bruke typenavnene u 1, u 2 og u 4 for å representere henholdsvis unsigned en-, to-, eller fire-byte kvantiteter. (En signed byte har verdiområde fra -127. En bit benyttes til å indikere hvorvidt tallet er positivt eller ikke. En unsigned byte har derimot verdiområde fra 0 -255, ingen bit benyttes for å indikere fortegn. )
Class-filen: Struktur • Det er ikke mulig å direkte adressere dens elementer. • Enkelte strukturer har ikke faste størrelser, men holder selv orden på sine lengder. • For å lese informasjon fra slutten av classfilen, må den traverseres rekursivt.
Class-filen: Struktur Class. File{ u 4 magic; u 2 minor_version; u 2 major_version; u 2 constant_pool_count; cp_info constant_pool[constants_pool_count-1]; u 2 access_flags; u 2 this_class; u 2 super_class; u 2 interfaces_count; u 2 interfaces[interfaces_count]; u 2 fields_count; field_info fields[fields_count]; u 2 methods_count; method_info methods[methods_count]; u 2 attributes_count; attribute_info attributes[attributes_count]; }
public class Hello. World{ public static void main(String[] args){ System. out. println("Hello World!"); } } ca 00 00 56 75 6 e 2 f 72 6 f 17 6 f 48 61 6 a 01 6 f 13 72 15 69 00 00 01 0 b 00 00 00 fe 10 16 01 6 d 01 53 63 72 0 c 72 65 2 f 61 00 2 f 6 a 65 28 6 e 02 01 00 00 00 0 a 01 ba 00 01 00 62 00 74 65 6 c 00 6 c 6 c 6 c 76 03 50 61 61 4 c 67 00 00 0 a 0 c 09 00 00 be 11 00 04 65 16 72 46 64 18 64 6 c 61 61 6 f 72 76 6 d 6 a 3 b 01 01 00 00 b 2 00 0 d 00 08 06 43 72 28 69 69 2 e 00 21 6 f 6 e 2 f 75 69 61 01 61 29 00 00 00 01 00 00 00 3 c 6 f 54 5 b 6 e 6 c 6 a 19 07 57 67 6 c 74 6 e 2 f 00 76 56 07 00 00 00 02 0 a 00 00 12 69 64 61 4 c 67 65 61 01 00 6 f 2 f 61 01 74 69 07 61 00 00 00 06 09 12 00 00 31 0 a 6 e 65 62 6 a 3 b 01 76 00 1 a 72 4 f 6 e 00 53 6 f 70 2 f 21 08 05 00 00 03 02 02 00 00 69 01 6 c 61 29 00 61 0 c 0 c 6 c 62 67 15 74 2 f 72 6 c 00 00 2 a 01 00 b 6 00 00 1 d 13 74 00 65 76 56 0 f 0 c 48 00 64 6 a 2 f 4 c 72 50 69 61 05 01 b 7 00 00 0 e 0 a 00 3 e 0 f 01 61 01 48 00 65 1 b 01 65 53 6 a 65 72 6 e 6 e 00 00 25 04 00 00 14 01 4 c 00 2 f 00 65 07 6 c 00 00 63 79 61 61 69 74 67 06 09 01 00 00 b 1 03 06 07 00 69 04 6 c 0 a 6 c 00 6 c 1 c 10 74 73 76 6 d 6 e 6 c 2 f 00 00 b 1 01 02 00 00 03 6 e 6 d 61 53 6 c 08 6 f 01 6 a 01 74 61 3 b 74 6 e 53 00 00 00 08 0 f 15 28 65 61 6 e 6 f 6 f 07 20 00 61 00 65 2 f 01 53 01 74 00 00 00 09 01 00 00 09 07 29 4 e 69 67 75 57 00 57 0 a 76 10 6 d 69 00 74 00 72 00 1 d 00 00 00 01 04 Êþº¾. . . 1. . . . <init>. . . () V. . . Code. . . Line. N umber. Table. . . mai n. . . ([Ljava/lang /String; )V. . . Sou rce. File. . . Hello. W orld. java. . . . Hello W orld!. . . Hello. World. . . jav a/lang/Object. . . java/lang/System. . . out. . . Ljava/i o/Print. Stream; . . . java/io/Print. St ream. . . println. . . (Ljava/lang/Str ing; )V. !. . . . *·. . ±. . . . %. . . . ². . ¶. . ±. . . .
Opprinnelig løsningsstrategi: Kodete URL-navn Et gyldig typenavn er bygd opp av bokstaver og sifre, samt tegnene ’_’ og ’$’. Dersom en CONSTANT_Class_info henviser til et ugyldig navn, vil java. lang. Class. Format. Error kastes.
Class-filen: Attributter • JVM-spesifikasjonen definerer flere forskjellige attributter. • JVM-implementasjon må ignorere alle attributter den ikke gjenkjenner. – Dette gjør det mulig å definere nye attributter for å støtte leverandør-spesifikk debugging, eventuelt å pakke utvidet informasjon inn i class-filen.
URLType_attribute{ u 2 attribute_name_index; u 4 attribute_length; u 2 typename_ index; u 2 location_index; } attribute_name_index -> CONSTANT_Utf 8_info = ’URLType’ Attribute_length = 4 typename_index -> CONSTANT_Utf 8_info = … location_index -> CONSTANT_Utf 8_info = …
Fullt kvalifisert typenavn: Foo Lokasjonsinformasjon, som er http: //www. bar. org/foobar. jar. ca 00 00 56 75 6 e 2 f 72 6 f 17 6 f 48 61 6 a 01 6 f 13 72 15 69 01 77 61 00 00 01 0 b 00 00 fe 10 16 01 6 d 01 53 63 72 0 c 72 65 2 f 61 00 2 f 6 a 65 28 6 e 00 77 72 02 01 00 00 00 0 a 02 1 e ba 00 01 00 62 00 74 65 6 c 00 6 c 6 c 6 c 76 03 50 61 61 4 c 67 03 77 2 e 00 00 0 a 0 c 09 00 00 00 be 11 00 04 65 16 72 46 64 18 64 6 c 61 61 6 f 72 76 6 d 6 a 3 b 46 2 e 6 a 01 01 00 00 b 2 00 0 d 1 f 00 08 06 43 72 28 69 69 2 e 00 21 6 f 6 e 2 f 75 69 61 01 61 29 6 f 62 61 00 00 00 3 c 6 f 54 5 b 6 e 6 c 6 a 19 07 57 67 6 c 74 6 e 2 f 00 76 56 6 f 61 72 07 00 00 00 02 0 a 00 00 12 69 64 61 4 c 67 65 61 01 00 6 f 2 f 61 01 74 69 07 61 01 01 72 00 00 00 06 09 12 00 00 31 0 a 6 e 65 62 6 a 3 b 01 76 00 1 a 72 4 f 6 e 00 53 6 f 70 2 f 00 00 2 e 21 08 05 00 00 03 02 02 00 00 69 01 6 c 61 29 00 61 0 c 0 c 6 c 62 67 15 74 2 f 72 6 c 07 1 d 6 f 00 00 2 a 01 00 b 6 00 00 20 13 74 00 65 76 56 0 f 0 c 48 00 64 6 a 2 f 4 c 72 50 69 61 55 68 72 05 01 b 7 00 00 0 e 0 a 00 3 e 0 f 01 61 01 48 00 65 1 b 01 65 53 6 a 65 72 6 e 6 e 52 74 67 00 00 25 04 00 00 00 14 01 4 c 00 2 f 00 65 07 6 c 00 00 63 79 61 61 69 74 67 4 c 74 2 f 06 09 01 00 00 b 1 03 1 d 06 07 00 69 04 6 c 0 a 6 c 00 6 c 1 c 10 74 73 76 6 d 6 e 6 c 2 f 54 70 66 00 00 b 1 01 02 00 00 00 03 6 e 6 d 61 53 6 c 08 6 f 01 6 a 01 74 61 3 b 74 6 e 53 79 3 a 6 f 00 00 00 08 00 0 f 15 28 65 61 6 e 6 f 6 f 07 20 00 61 00 65 2 f 01 53 01 74 70 2 f 6 f 00 00 00 09 01 00 00 00 09 07 29 4 e 69 67 75 57 00 57 0 a 76 10 6 d 69 00 74 00 72 65 2 f 62 00 1 d 00 00 00 01 04 04 Êþº¾. . . 1. . . . <init>. . . () V. . . Code. . . Line. N umber. Table. . . mai n. . . ([Ljava/lang /String; )V. . . Sou rce. File. . . Hello. W orld. java. . . . Hello W orld!. . . Hello. World. . . jav a/lang/Object. . . java/lang/System. . . out. . . Ljava/i o/Print. Stream; . . . java/io/Print. St ream. . . println. . . (Ljava/lang/Str ing; )V. . . URLType. . . Foo. . . http: // www. bar. org/foob ar. jar. !. . . . *·. . ±. . . . %. . . . ². . ¶. . ±. . . . .
Egenskrevet bytekode-manipulator Fordeler med egenskrevet løsning: • Kan skalere løsningen etter oppgaven • Størrelse på ca. 2 -4% av BCEL og Javassist • Raskere enn BCEL og Javassist da enkelte interne struktures ignoreres
Egenskrevet bytekode-manipulator Ved testing av prototypen viste løsningen seg å være tregere enn BCEL og Javassist. Flaskehalsen var følgende kode: int length = input. read. Unsigned. Short(); byte[] bytes = new byte[length]; input. read(bytes); value = new String(bytes, "UTF-8"); Den ble byttet med: value = input. read. UTF()
Krav II: Særegne versjoner • Hvis man forener dynamisk lasting og et ikke-forgrenet classloading-design, vil ikke navneunikhet være tilstrekkelig. • SAAPP Alfa bes laste: – http: //foo. org/Class. A – http: //bar. org/Class. B refererer til en gammel versjon av Class. C. Når den symbolske referansen fra Class. B skal oppklares, viser det seg imidlertid at Class. A har kommet Class. B i forkjøpet med å laste en nyere versjon av Class. C. Den refererte typen ligger da i namespace og Alfa vil få denne returnert ved oppklaring.
Web-tjeneren Tomcat Løsning som omgår standard foreldre-barn delegerings policy: Bootstrap | System | Common / Catalina Shared / Webapp 1 Webapp 2. . .
Modifisert modell Bootstrap | Extensions | System | ----------Common - - - - - / SAAPP 1 SAAPP 2. . .
Egenskaper til løsningsstrategi • Typer som er tilgjengelig gjennom system classloader og overliggende classloadere vil være endelige. En SAAPP vil ikke kunne få lastet sin særegne versjon av en type dersom en annen versjon er tilgjengelig gjennom system classloader eller overliggende classloadere. Dette gjør at man må være bevisst på hvilke class-filer man gjør tilgjengelig gjennom CLASSPATH eller extensions classloader. • Common har lokasjoner til typer som skal gjøres tilgjengelig for alle underliggende classloadere og som hver underliggende classloader skal ha mulighet til å laste sin egen versjon av.
Krav III: Fellesgjøring Alfa har mottatt melding fra DBs agent: the Text = new http: //www. db. no/Text(“db. no/sporten”); Alfa vil hente tilsvarende informasjon fra VG: http: //www. vg. no/Text. Analyzer. get. Info((Text)the Text()); • I uttrykket ovenfor castes objektet som returneres fra ”the Text()” til Text. • JVM identifiserer en type med dens fullt kvalifiserte navn, samt tilhørende classloader. • I uttrykket ovenfor må instansen av Text som det castes til, være lastet av samme classloader som objektet ”the Text()” henviser til, hvis ikke vil Class. Cast. Exception kastes.
Identifisering av typer JVM identifiserer en klasse med dens fullt kvalifiserte navn, samt tilhørende classloader. Dette betyr at to classloadere kan laste samme type, men ved sammenligning vil disse regnes som ulike. Typisk kode som vil fremprovosere en feilsituasjon: My. Class. Loader mcl = new My. Class. Loader(); Class clas = mcl. load. Class(”Foo”); Object object = clas. new. Instance(); Foo foo=(Foo)object;
Testscenario oppsett 1/3 • To meldinger fra forskjellige avsendere blir sendt til Alfa. Den første meldingen ber om at en type ved navn TMP 1 skal lastes. Dette er en klasse som skal simulere resultatet av kompilering av en mottatt melding. Den eksekverer følgende kodelinje i konstruktøren: Class. A a = new Class. A(); • Den andre meldingen henviser til TMP 2, som wrapper følgende kodelinje: Class. B b = new Class. B(); • Begge TMP-klassene er modifisert med informasjon om URL-typer.
Testscenario oppsett 2/3 Class. A oppretter et objekt av Class. C i konstruktøren, og legger en beskjed inn i det. Videre registreres objektet av Class. C i rammeverket, slik at det kan deles med andre SAAPP’er. public Class. A(){ //the common. C = new Class. C(); Class. C c = new Class. C(); c. set. String("This message is set by: " +this); Object. Mediator. X. add. Object(this, new Reference. Wrapper(Class. C. class, "shared. C", null), c); }
Testscenario oppsett 3/3 Class. B vil på sin side hente ut det innlagte Class. C objektet fra rammeverket. public Class. B(){ try { Class. C c = (Class. C)(Object. Mediator. X. invoke. Ref(this, new Reference. Wrapper(Class. C. class, "shared. C", null))); } catch (Exception e) {} }
Testscenario suksesskriterier • Class. B må hente ut det samme objektet av Class. C, shared. C, som Class. A la inn i rammeverket. Dette har rammeverket ansvar for. • For at Class. B skal kunne bruke objektet som rammeverket returnerer, må det castes til Class. C. For å unngå feil ved castingprosessen, må classloaderen som laster Class. C ved eksekvering av Class. B sin kode, være den samme som lastet Class. C ved eksekvering av Class. A sin kode. Dette har classloader-strukturen ansvar for.
Løsningsstrategi: Skille mellom URL-typer og vanlige typer • Når man uttrykker lokasjon i en URL-type, er man som programmerer mer spesifikk og i en viss grad overstyrende i forhold til hvordan egne og andres program skal hente typen. • En vanlig type vil virke som en type hvis opphav er åpent. Den vil være ubestemt i forhold til hvor den skal lastes fra. Som programmerer vil man overlate til applikasjonen å finne frem til typen som skal benyttes. Dersom typen tas i bruk i en applikasjon hvor den opprinnelige programmereren ikke har kontroll over tilgjengelige lokasjoner, vil den åpne referansen kunne føre til bruk av en allerede lastet type med oppgitt navn.
Hva er en URL-type? • En URL-type består av lokasjon og fullt kvalifisert typenavn. • Det er ikke en statisk tilstand. En type deklareres ikke i sin egen kildekode som en URL-type, men tilstanden bestemmes av konteksten. Det er en situasjonsbestemt tilstand som gis av refererende type. Dersom en type refererer til Foo, og har informasjon om lokasjonen til Foo, er Foo i dette tilfellet en URL-type.
URLType. Class. Loader Innfører én classloader per URL. Fordeler: • To agenter vil kunne spesifisere at de skal bruke samme versjon av en type for å kunne utveksle informasjon. Ved casting imellom objektene til disse to agentene vil det ikke oppstå Class. Cast. Exception da typen i begge tilfeller lastes fra samme classloader. • Vil være mulig at én agent kan bruke forskjellige versjoner av samme type. Dette krever imidlertid at deres refererende typer lastes i forskjellige classloadere. • Dersom en agent har flere lokasjoner å laste fra, er det mulig at riktig versjon ikke lastes dersom man bare bruker én classloader per samtalepartner. Tilfeller hvor dette kan oppstå er når forskjellige versjoner av typen er tilgjengelig på flere enn én av URL'ene i URL-lista. Da vil URL'en som først ble lagt til bli benyttet. Denne muligheten for feil vil ikke være tilstede med den nye løsningsstrategien.
URLType. Class. Loader. load. Class() Class c = find. Loaded. Class(name); if(c == null){ try{ c = find. System. Class(name); }catch(Class. Not. Found. Exception e 1){ URLType. Class. Loader cl = (URLType. Class. Loader)url. Types. get(name); if(cl != null) c = cl. load. Class. Locally(name); else{ String pkgname = get. Pkg. Name(name); cl = (URLType. Class. Loader)url. Packages. get(pkgname); if(cl != null) c = cl. load. Class. Locally(name); else{ Package pkg = find. Package(pkgname); if(pkg != null) c = find. Class(name); else{ try{ c = delegator. load. Class(name, this); }catch(Class. Not. Found. Exception e 2){ c = find. Class(name); } } }
CLDelegator. load. Class() public Class load. Class(String name, URLType. Class. Loader classloader)throws Class. Not. Found. Exception{ Class clas = common. get. Loaded. Class(name); if(clas == null){ Enumeration cls = classloaders. elements(); while(cls. has. More. Elements()){ URLType. Class. Loader cl = (URLType. Class. Loader)cls. next. Element(); if(cl != classloader) clas = cl. get. Loaded. Class(name); if(clas != null)return clas; } } if(classloader != common){ try{ return common. load. Class. Locally(name); }catch(Class. Not. Found. Exception e 1){ return classloader. load. Class. Locally(name); } } return null; }
Modell av classloading-struktur Bootstrap | Extensions | System | ----------Common / | SAAPP 1 URL 1 | URL 2 SAAPP 2. . .
Problemer / begrensinger • Ikke mulig å isolere typer fra andre aktører. • Problemer med pakketilgang grunnet runtime-packages. • Bryter med innført foreldre-barn delegerings-policy. • Classloaderen er avhengig av CLDelegator for å fungere • Strukturen er ”låst”.