Områdesoberoende tillgång till resurser

  • Översikt
  • Resurser, namn ochkontexter
  • Systemresurser
  • Resurser som inte är systemresurser
  • Resursnamn
  • Användning av metoder i java.lang.Class
  • Användningsmetoder för java.lang.ClassLoader
  • Säkerhet
  • Exempel

Översikt

En resurs är data (bilder, ljud, text och så vidare) som ett program behöver få tillgång till på ett sätt som är oberoende av programkodens placering. Java-program kan använda två mekanismer för att få tillgång till resurser: Applets använder Applet.getCodeBase()för att få fram bas-URL för appletkoden och utökar sedan bas-URL med en relativ sökväg för att ladda den önskade resursen, till exempel med Applet.getAudioClip(url). Program använder ”välkända platser” somSystem.getProperty("user.home") ellerSystem.getProperty("java.home"), lägger sedan till”/lib/resource” och öppnar den filen.

Metoder i klasserna Class ochClassLoader ger ett platsoberoende sätt att lokalisera resurser. De gör det till exempel möjligt att lokalisera resurser för:

  • En applet som laddas från Internet med hjälp av flera HTTP-anslutningar.
  • En applet som laddas med hjälp av JAR-filer.
  • En Java Bean som laddas eller installeras i CLASSPATH.
  • En ”biblioteksfil” som installeras i CLASSPATH.

De här metoderna ger inget specifikt stöd för att lokalisera lokaliserade resurser. Lokaliserade resurser stöds av internationaliseringsmöjligheterna.

Resurser, namn och sammanhang

En resurs identifieras av en sträng som består av en sekvens av understrängar, avgränsade av snedstreck (/), följt av ett resursnamn.Varje understräng måste vara en giltig Java-identifierare. Resursnamnet är av formen shortName ellershortName.extension. Både shortName och extension måste vara Java-identifierare.

Namnet på en resurs är oberoende av Javaimplementationen; i synnerhet är sökvägsseparatorn alltid ett snedstreck (/). Java-implementationen kontrollerar dock detaljerna för hur innehållet i resursen mappas till en fil, en databas eller ett annat objekt som innehåller den faktiska resursen.

Tolkningen av ett resursnamn är relativ till en klassinläsningsinstans. Metoder som implementeras av klassenClassLoader gör denna tolkning.

Systemresurser

En systemresurs är en resurs som antingen är inbyggd i systemet eller hålls av värdimplementationen i till exempel ett lokalt filsystem. Program har tillgång till systemresurser genom metoderna ClassLoader getSystemResource och getSystemResourceAsStream.

För att hitta en systemresurs i en viss implementering kan det till exempel handla om att söka i posterna i CLASSPATH. MetodernaClassLoader söker i varje katalog, ZIP-fil eller JAR-fil i CLASSPATH efter resursfilen och, om den hittas, returnerar de antingen en InputStream eller resursnamnet. Om den inte hittas returnerar metoderna noll. En resurs kan hittas i en annan post i CLASSPATH än den plats där klassfilen laddades.

Non-System Resources

Implementationen av getResource på en klass som laddas beror på detaljerna i ClassLoader-klassen. Exempel: AppletClassLoader:

  • Försöker först hitta resursen som en systemresurs, sedan, om den inte hittas,
  • söker bland resurserna i arkiv (JAR-filer) som redan har laddats i den här CODEBASE, och sedan, om den inte hittas,
  • använder CODEBASE och försöker hitta resursen (vilket kan innebära att man kontaktar en avlägsen plats).

Alla klassinläsare söker först efter en resurs som systemresurs, på samma sätt som när man söker efter klassfiler. Denna sökregel tillåter att alla resurser skrivs över lokalt. Klienter bör välja ett resursnamn som är unikt (till exempel genom att använda företags- eller paketnamnet som prefix).

Resursnamn

En vanlig konvention för namnet på en resurs som används av en klass är att använda det fullt kvalificerade namnet på paketet för klassen, men att konvertera alla punkter (.) till snedstreck (/) och lägga till ett resursnamn av formen name.extension. För att stödja detta, och för att förenkla hanteringen av detaljerna i systemklasser (för vilkagetClassLoader returnerar null), tillhandahåller klassenClass två bekvämlighetsmetoder som anropar de lämpliga metoderna i ClassLoader.

Resursnamnet som ges till en Class-metod kan ha en initial start ”/” som identifierar det som ett ”absolut” namn.Resursnamn som inte börjar med ett ”/” är ”relativa”.

Absoluta namn saknar sitt inledande ”/” och skickas, utan ytterligare ändringar, till lämplig ClassLoader-metod för att lokalisera resursen. Relativa namn modifieras enligt den konvention som beskrivits tidigare och skickas sedan till en ClassLoader metod.

Användning av metoder i java.lang.Class

Klassen Class implementerar flera metoder för att ladda resurser.

Metoden getResource() returnerar en URL förresursen. URL:n (och dess representation) är specifik för implementationen och JVM:n (dvs. URL:n som erhålls i en runtimeinstans kanske inte fungerar i en annan). Dess protokoll är vanligtvis specifikt för ClassLoader som laddar resursen. Om resursen inte finns eller inte är synlig av säkerhetsskäl returnerar metoderna null.

Om klientkoden vill läsa innehållet i resursen som en InputStream kan den tillämpa openStream()-metoden på URL:en. Detta är tillräckligt vanligt för att motivera att getResourceAsStream() läggs till iClass och ClassLoader.getResourceAsStream() är samma sak som att anropagetResource().openStream(), förutom attgetResourceAsStream() fångar upp IO-undantag och returnerar en null InputStream.

Klientkoden kan också begära resurskällans innehåll som ett objekt genom att tillämpa java.net.URL.getContent()metoden på URL:en. Detta är till exempel användbart när resursen innehåller data för en bild. När det gäller en bild är resultatet ett awt.image.ImageProducer objekt, inte ettImage objekt.

Metoderna getResource och getResourceAsStream hittar en resurs med ett givet namn. De returnerar null om de inte hittar en resurs med det angivna namnet. Reglerna för att söka efter resurser som är associerade med en viss klass implementeras av klassens ClassLoader. Class-metoderna delegerar tillClassLoader-metoder efter att ha tillämpat en namngivningskonvention: om resursnamnet börjar med ”/” används det som det är.I annat fall läggs paketets namn till, efter att ha konverterat alla punkter (.) till snedstreck (/).

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 lägger till ett prefix för paketnamnet om namnet inte är absolut, och tar bort alla inledande ”/” om namnet är absolut. Det är möjligt, om än ovanligt, att ha klasser i olika paket som delar samma resurs.

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;}

Användning av metoder i java.lang.ClassLoader

Klassen ClassLoader har två uppsättningar metoder för att komma åt resurser. Den ena uppsättningen returnerar en InputStream för resursen. Den andra uppsättningen returnerar en URL. Metoderna som returnerar en InputStream är lättare att använda och uppfyller många behov, medan metoderna som returnerar URL:er ger tillgång till mer komplex information, till exempel en bild och ett ljudklipp.

ClassLoaderFörändrar resurser på samma sätt som den hanterar klasser. En ClassLoader styr hur namnet på en resurs ska kopplas till dess innehåll. ClassLoadertillhandahåller också metoder för åtkomst till systemresurser,analogt med systemklasserna. Classklassen tillhandahåller några bekvämlighetsmetoder som delegerar funktionalitet till ClassLoadermetoderna.

Många Javaprogram kommer att få tillgång till dessa metoder indirekt genom I18N (lokalisering) API:erna. Andra kommer att få tillgång till dem genom metoder i Class. Några få kommer att åberopa metoderna i ClassLoader direkt.

Metoderna i ClassLoader använder den givna strängen som namnet på resursen utan att tillämpa någon absolut/relativ omvandling (se metoderna i Class). Namnet bör inte ha ett inledande ”/”.

Systemresurser är sådana som hanteras direkt av värdimplementationen. De kan till exempel finnas iCLASSPATH.

Namnet på en resurs är en ”/”-separerad sekvens avidentifierare. Klassen Class tillhandahåller bekvämlighetsmetoder för åtkomst till resurser; metoderna implementerar en konvention där paketnamnet föregås av det korta namnet påresursen.

Resurser kan nås som en InputStream, eller enURL.

Metoden getSystemResourceAsStream returnerar enInputStream för den specificerade systemresursen eller noll om den inte hittar resursen. Resursnamnet kan vara vilken systemresurs som helst.

Metoden getSystemResource hittar en systemresurs med det angivna namnet. Den returnerar en URL till resursen eller noll om den inte hittar resursen. Om du anropar java.net.URL.getContent() med URL:en returneras ett objekt som ImageProducer, AudioClip eller InputStream.

Metoden getResourceAsStream returnerar en InputStream för den angivna resursen eller noll om den inte hittar resursen.

Metoden getResource hittar en resurs med det angivna namnet. Den returnerar en URL till resursen eller noll om den inte hittar resursen. Om du anroparjava.net.URL.getContent() med URL:en returneras ettobjekt som ImageProducer, AudioClip eller InputStream.

Säkerhet

getResource() ger tillgång till information måste den ha väldefinierade och välgrundade säkerhetsregler. Om säkerhetsöverväganden inte tillåter att en resurs är synlig i något säkerhetssammanhang, kommer getResource()-metoden att misslyckas (returnera null) som om resursen inte fanns alls, detta för att hantera existensattacker.

Klassinläsare får inte ge tillgång till innehållet i en .classfile av både säkerhets- och prestandaskäl. Huruvida det är möjligt att erhålla en URL för en .class-fil beror på de specifika omständigheterna, vilket visas nedan.

Det finns inga specificerade säkerhetsproblem eller begränsningar när det gällerresurser som hittas av en klassinläsare som inte tillhör systemet.AppletClassLoader ger tillgång till information som laddas in från en källplats, antingen individuellt eller i grupp genom en JAR-fil; därför bör AppletClassLoader tillämpa samma checkConnect()regler när det gäller URL:er genom getResource().

Systemet ClassLoader ger tillgång till information i CLASSPATH. En CLASSPATH kan innehålla kataloger och JAR-filer. Eftersom en JAR-fil skapas avsiktligt har den en annan betydelse än en katalog där saker och ting kan hamna på ett mer tillfälligt sätt. Vi är särskilt strängare när det gäller att få information från en katalog än från en JAR-fil.

Om en resurs finns i en katalog:

  • getResource() kommer anropen att användaFile.exists() för att avgöra om motsvarande fil skall göras synlig för användaren. Kom ihåg attFile.exists() använder checkRead()-metoden i säkerhetshanteraren.
  • Det samma gäller getResourceAsStream().

Om resursen finns i en JAR-fil:

  • getResource() kommer anrop att lyckas för alla filer, oavsett om anropet görs från en system- eller en icke-systemklass.
  • getResourceAsStream() anrop kommer att lyckas för resurser som inte är .class-resurser, och så även förjava.net.URL.getContent() på motsvarande URL:er.

Exempel

Detta avsnitt innehåller två exempel på klientkod. I det första exemplet används ”absoluta resursnamn” och traditionella mekanismer för att hämta ett 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. }}

Detta exempel använder ”relativa resursnamn” och den mekanism som finns tillgänglig från kompilatorn genom -experimentalflaggan, för att hämta ett 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. }

Lämna ett svar

Din e-postadress kommer inte publiceras.