Stedafhængig adgang til ressourcer

  • Overblik
  • Ressourcer, navne og kontekster
  • Systemressourcer
  • Systemressourcer
  • Ressourcer uden for systemet
  • Ressource-navne
  • Anvendelse af metoder i java.lang.Class
  • Brug af metoder fra java.lang.ClassLoader
  • Sikkerhed
  • Eksempler

Overblik

En ressource er data (billeder, lyd, tekst osv.), som et program har brug for at få adgang til på en måde, der er uafhængig af programkodens placering. Java-programmer kan bruge to mekanismer til at få adgang til ressourcer: Applets bruger Applet.getCodeBase() til at få basis-URL’en for appletkoden og udvider derefter basis-URL’en med en relativ sti for at indlæse den ønskede ressource, f.eks. med Applet.getAudioClip(url). Applikationer bruger “velkendte steder” somSystem.getProperty("user.home") ellerSystem.getProperty("java.home"), og tilføjer derefter”/lib/resource” og åbner denne fil.

Metoder i klasserne Class ogClassLoader giver en steduafhængig måde at lokalisere ressourcer på. De gør det f.eks. muligt at lokalisere ressourcer til:

  • En applet, der er indlæst fra internettet ved hjælp af flere HTTP-forbindelser.
  • En applet, der er indlæst ved hjælp af JAR-filer.
  • En Java Bean, der er indlæst eller installeret i CLASSPATH.
  • Et “bibliotek”, der er installeret i CLASSPATH.

Disse metoder giver ikke specifik støtte til lokalisering af lokaliserede ressourcer. Lokaliserede ressourcer understøttes af faciliteterne til internationalisering.

Ressourcer, navne og kontekster

En ressource identificeres ved en streng, der består af en sekvens af understrenge, afgrænset af skråstreger (/), efterfulgt af et ressourcenavn.Hver understreng skal være en gyldig Java-identifikator. Ressourcensnavnet er af formen shortName ellershortName.extension. Både shortName og extension skal være Java-identifikatorer.

Ressourcens navn er uafhængigt af Java-implementeringen; især er stiseparatoren altid en skråstreg (/). Java-implementeringen styrer imidlertid detaljerne for, hvordan indholdet af ressourcen afbildes til en fil, database eller et andet objekt, der indeholder den faktiske ressource.

Interpretationen af et ressourcenavn er relativ i forhold til en classloader-instans. Metoder, der er implementeret afClassLoader-klassen, foretager denne fortolkning.

Systemressourcer

En systemressource er en ressource, der enten er indbygget i systemet eller opbevares af værtsimplementeringen i f.eks. et lokalt filsystem. Programmer får adgang til systemressourcer viaClassLoader-metoderne getSystemResource oggetSystemResourceAsStream.

For eksempel kan det i en bestemt implementering være nødvendigt at søge i posterne i CLASSPATH for at finde en systemressource. MetoderneClassLoader søger i hver enkelt mappe, ZIP-fil eller JAR-fil i CLASSPATH efter ressourcefilen, og hvis den findes, returnerer de enten et InputStream eller resourcenavnet. Hvis den ikke findes, returnerer metoderne null. En ressource kan findes i en anden post i CLASSPATH end det sted, hvor klassefilen blev indlæst.

Non-System Resources

Implementeringen af getResource ved indlæsning af en klasse afhænger af detaljerne i ClassLoader-klassen. Eksempelvis AppletClassLoader:

  • Først forsøges det at finde ressourcen som en systemressource; derefter, hvis den ikke findes,
  • Søger i ressourcerne i arkiver (JAR-filer), der allerede er indlæst i denne CODEBASE; derefter, hvis den ikke findes,
  • Anvender CODEBASE og forsøger at finde ressourcen (hvilket kan indebære, at der skal tages kontakt til et eksternt sted).

Alle class loaders vil først søge efter en ressource som systemressource på en måde, der svarer til søgning efter klassefiler. Denne søgningsregel tillader overskrivning lokalt af enhver ressource. Klienter bør vælge et ressourcenavn, der er entydigt (f.eks. ved at bruge firma- eller pakkenavnet som præfiks).

Ressourcenavne

En almindelig konvention for navnet på en ressource, der bruges af en klasse, er at bruge det fuldt kvalificerede navn på klassens pakke, menkonvertere alle punkter (.) til skråstreger (/) og tilføje et ressourcenavn af formen name.extension. For at understøtte dette og for at forenkle håndteringen af detaljerne i systemklasser (for hvilkegetClassLoader returnerer nul), tilbyder klassenClass to bekvemmelighedsmetoder, der kalder de relevante metoder i ClassLoader.

Ressourcenavnet, der gives til en Class-metode, kan have et indledende “/”, der identificerer det som et “absolut” navn.Ressourcenavne, der ikke begynder med et “/”, er “relative”.

Absolutte navne fratages deres indledende “/” og videregives uden yderligere ændringer til den relevanteClassLoader-metode til at finde ressourcen. Relative navne ændres i henhold til den tidligere beskrevne konvention og videregives derefter til en ClassLoader metode.

Anvendelse af metoder i java.lang.Class

Klassen Class implementerer flere metoder til indlæsning af ressourcer.

Metoden getResource() returnerer en URL for ressourcen. URL’en (og dens repræsentation) er specifik for implementeringen og JVM’en (det vil sige, at den URL, der er opnået i én runtimeinstans, muligvis ikke fungerer i en anden). Dens protokol er normalt specifik for den ClassLoader, der indlæser ressourcen. Hvis ressourcen ikke findes eller ikke er synlig på grund af sikkerhedshensyn, returnerer metoderne null.

Hvis klientkoden ønsker at læse indholdet af ressourcen som en InputStream, kan den anvendeopenStream()-metoden på URL’en. Dette er almindeligt nok til at retfærdiggøre tilføjelse af tilClass og ClassLoader. er det samme som at kaldegetResource().openStream(), bortset fra at fanger IO-undtagelser og returnerer en null InputStream.

Klientkode kan også anmode om indholdet af ressourcen som et objekt ved at anvende java.net.URL.getContent()-metoden på URL’en. Dette er nyttigt, når ressourcen f.eks. indeholder data for et billede. I tilfælde af et billede er resultatet et awt.image.ImageProducer objekt, ikke etImage objekt.

Metoderne getResource oggetResourceAsStream finder en ressource med et givet navn. De returnerer null, hvis de ikke finder en ressource med det angivne navn. Reglerne for søgning efter ressourcer, der er tilknyttet en given klasse, implementeres af klassens ClassLoader. Class-metoderne delegerer tilClassLoader-metoder efter at have anvendt en navngivningskonvention: Hvis ressourcens navn begynder med “/”, bruges det som det er, ellers tilføjes pakkens navn efter konvertering af alle punkter (.) til skråstreger (/).

public InputStream getResourceAsStream(String name) { name = resolveName(name); ClassLoader cl = getClassLoader(); if (cl==null) { return ClassLoader.getSystemResourceAsStream(name); // A system class. } return cl.getResourceAsStream(name);}public java.net.URL getResource(String name) { name = resolveName(name); ClassLoader cl = getClassLoader(); if (cl==null) { return ClassLoader.getSystemResource(name); // A system class. } return cl.getResource(name);}

Metoden resolveName tilføjer et præfiks for pakkens navn, hvis navnet ikke er absolut, og fjerner eventuelle indledende “/”, hvis navnet er absolut. Det er muligt, om end det er ualmindeligt, at have klasser i forskellige pakker, der deler den samme ressource.

private String resolveName(String name) { if (name == null) { return name; } if (!name.startsWith("/")) { Class c = this; while (c.isArray()) { c = c.getComponentType(); } String baseName = c.getName(); int index = baseName.lastIndexOf('.'); if (index != -1) { name = baseName.substring(0, index).replace('.', '/') + "/" + name; } } else { name = name.substring(1); } return name;}

Anvendelse af metoder i java.lang.ClassLoader

Klassen ClassLoader har to sæt metoder til at få adgang til ressourcer. Det ene sæt returnerer en InputStream for ressourcen. Det andet sæt returnerer en URL. Metoderne, der returnerer en InputStream, er lettere at bruge og opfylder mange behov, mens metoderne, der returnerer URL’er, giver adgang til mere komplekse oplysninger, f.eks. et billede og et lydklip.

ClassLoader ændrer ressourcer på samme måde som den måde, den administrerer klasser på. En ClassLoader styrer, hvordan navnet på en ressource skal knyttes til dens indhold. ClassLoadergiver også metoder til at få adgang til systemressourcer,analogt med systemklasserne. Class-klassen indeholder nogle bekvemmelighedsmetoder, der uddelegerer funktionalitet til ClassLoader-metoderne.

Mange Java-programmer vil få indirekte adgang til disse metoder gennem I18N (lokaliserings)-API’erne. Andre vil få adgang til dem via metoder i Class. Nogle få vil direkte påberåbe sig metoderne i ClassLoader.

Metoderne i ClassLoader anvender den givne String som navnet på ressourcen uden at anvende nogen absolut/relativ omdannelse (se metoderne i Class). Navnet bør ikke have et foranstillet “/”.

Systemressourcer er de ressourcer, der håndteres direkte af hostimplementationen. De kan f.eks. være placeret iCLASSPATH.

Navnet på en ressource er en “/”-separeret sekvens afidentifikatorer. Class-klassen indeholder bekvemmelighedsmetoder til at få adgang til ressourcer; metoderne implementerer en konvention, hvor pakkenavnet er præfikset med det korte navn på ressourcen.

Ressourcer kan tilgås som en InputStream eller en URL.

Metoden getSystemResourceAsStream returnerer enInputStream for den angivne systemressource eller nul, hvis den ikke finder ressourcen. Ressourcens navn kan være en hvilken som helst systemressource.

Metoden getSystemResource finder en systemressource med det angivne navn. Den returnerer en URL til ressourcen eller nul, hvis den ikke finder ressourcen. Ved at kaldejava.net.URL.getContent() med URL’en returneres et objekt, f.eks. ImageProducer, AudioClip eller InputStream.

Metoden getResourceAsStream returnerer enInputStream for den angivne ressource eller nul, hvis den ikke finder ressourcen.

Metoden getResource finder en ressource med det angivne navn. Den returnerer en URL til ressourcen eller nul, hvis den ikke finder ressourcen. Hvis du kalderjava.net.URL.getContent() med URL’en, returneres et objekt, f.eks. ImageProducer, AudioClip eller InputStream.

Sikkerhed

Da getResource() giver adgang til oplysninger, skal den have veldefinerede og velbegrundede sikkerhedsregler. Hvis sikkerhedshensyn ikke tillader, at en ressource er synlig i en eller anden sikkerhedskontekst, vil getResource()-metoden fejle (returnere null), som om ressourcen slet ikke var til stede, hvilket imødegår eksistensangreb.

Class loaders må ikke give adgang til indholdet af en .classfile af både sikkerheds- og ydelsesmæssige årsager. Hvorvidt det er muligt at få en URL for en .class-fil afhænger af de specifikke forhold, som vist nedenfor.

Der er ingen specificerede sikkerhedsproblemer eller begrænsninger vedrørenderessourcer, der findes af en klasselæsser uden for systemet.AppletClassLoader giver adgang til oplysninger, der er indlæst fra en kildeplacering, enten individuelt eller i en gruppe gennem en JAR-fil; derfor skal AppletClassLoader anvende de samme checkConnect()regler, når der behandles URL’er gennem getResource().

Systemet ClassLoader giver adgang til oplysninger i CLASSPATH. En CLASSPATH kan indeholde mapper og JAR-filer. Da en JAR-fil er oprettet med vilje, har den en anden betydning end en mappe, hvor tingene kan ende på en mere tilfældig måde. Vi er især mere strenge med hensyn til at få oplysninger fra en mappe end fra en JAR-fil.

Hvis en ressource befinder sig i en mappe:

  • getResource() vil
    • getResource()-opkald brugeFile.exists() til at afgøre, om den tilsvarende fil skal gøres synlig for brugeren. Husk, atFile.exists() anvender checkRead()-metoden i sikkerhedsadministratoren.
    • Det samme gælder for getResourceAsStream().

Hvis ressourcen er i en JAR-fil:

  • getResource() vil påkald lykkes for alle filer, uanset om påkaldet foretages fra en system- eller en ikke-systemklasse.
  • getResourceAsStream() påkald lykkes for ressourcer, der ikke er .class-ressourcer, og det samme gælder forjava.net.URL.getContent() på tilsvarende URL’er.

Eksempler

Dette afsnit indeholder to eksempler på klientkode. I det første eksempel anvendes “absolutte ressourcenavne” og traditionelle mekanismer til at hente et Class objekt.

package pkg;import java.io.IOException;import java.io.InputStream;import java.io.PrintStream;class Test { private static final String absName = "/pkg/mumble.baf"; public static void test1() { Class c=null; try { c = Class.forName("pkg.Test"); } catch (Exception ex) { // This should not happen. } InputStream s = c.getResourceAsStream(absName); // do something with it. } public void test2() { InputStream s = this.getClass().getResourceAsStream(absName); // do something with it. }}

Dette eksempel anvender “relative ressourcenavne” og den mekanisme, der er tilgængelig fra compileren via -experimentalflaget, til at hente et Class objekt.

package pkg;import java.io.IOException;import java.io.InputStream;import java.io.PrintStream;class Test { private static final String relName = "mumble.baf"; public static void test1() { InputStream s = Test.class.getResourceAsStream(relName); // do something with it.} public void test2() { InputStream s = Test.class.getResourceAsStream(relName); // do something with it. }

Skriv et svar

Din e-mailadresse vil ikke blive publiceret.