Accès aux ressources indépendant de l’emplacement
- Aperçu
- Ressources, noms et contextes
- Ressources du système
- Ressources hors système
- Noms des ressources
- Utilisation des méthodes de java.lang.Class
- Utilisation des méthodes dejava.lang.ClassLoader
- Sécurité
- Exemples
Overview
Une ressource est une donnée (images, audio, texte, et ainsi de suite) à laquelle un programme doit accéder d’une manière indépendante de l’emplacement du code du programme. Les programmes Java peuvent utiliser deux mécanismes pour accéder aux ressources : Les applets utilisent Applet.getCodeBase()
pour obtenir l’URL de base du code de l’applet, puis étendent l’URL de base avec un chemin relatif pour charger la ressource souhaitée, par exemple avec Applet.getAudioClip(url)
. Les applications utilisent des « emplacements connus » tels queSystem.getProperty("user.home")
ouSystem.getProperty("java.home")
, puis ajoutent « /lib/resource », et ouvrent ce fichier.
Les méthodes des classes Class
etClassLoader
fournissent un moyen indépendant de l’emplacement pour localiser les ressources. Par exemple, elles permettent de localiser des ressources pour :
- Une applet chargée depuis Internet en utilisant des connexions HTTP multiples.
- Une applet chargée en utilisant des fichiers JAR.
- Un Java Bean chargé ou installé dans le CLASSPATH.
- Une « bibliothèque » installée dans le CLASSPATH.
Ces méthodes ne fournissent pas de support spécifique pour localiser des ressources localisées. Les ressources localisées sont prises en charge par les installations d’internationalisation.
Ressources, noms et contextes
Une ressource est identifiée par une chaîne de caractères constituée d’une séquence de sous-chaînes, délimitées par des barres obliques (/), suivie d’un nom de ressource.Chaque sous-chaîne doit être un identifiant Java valide. Le nom de la ressource est de la forme shortName
oushortName.extension
. shortName
et extension
doivent tous deux être des identificateurs Java.
Le nom d’une ressource est indépendant de l’implémentation Java ; en particulier, le séparateur de chemin est toujours une barre oblique (/). Cependant, l’implémentation Java contrôle les détails de la façon dont le contenu de la ressource est mappé dans un fichier, une base de données ou un autre objet contenant la ressource réelle.
L’interprétation du nom d’une ressource est relative à une instance de classloader. Les méthodes implémentées par la classeClassLoader
font cette interprétation.
Ressources système
Une ressource système est une ressource qui est soit intégrée au système, soit conservée par l’implémentation hôte dans, par exemple, un système de fichiers local. Les programmes accèdent aux ressources système par les méthodesClassLoader
getSystemResource
etgetSystemResourceAsStream
.
Par exemple, dans une implémentation particulière, la localisation d’une ressource système peut impliquer la recherche des entrées dans le CLASSPATH. Les méthodesClassLoader
recherchent chaque répertoire, fichier ZIP, ou entrée de fichier JAR dans le CLASSPATH pour le fichier de ressource, et, si trouvé, renvoie soit un InputStream
, soit le nom de la ressource. Si elles ne sont pas trouvées, les méthodes renvoient null. Une ressource peut être trouvée dans une entrée différente dans le CLASSPATH que l’emplacement où le fichier de classe a été chargé.
Ressources hors système
L’implémentation de getResource
sur un chargement de classe dépend des détails de la classe ClassLoader
. Par exemple, AppletClassLoader
:
- Tente d’abord de localiser la ressource en tant que ressource système ; puis,si elle n’est pas trouvée,
- Recherche parmi les ressources dans les archives (fichiers JAR) déjà chargées dans ce CODEBASE ; puis, si elle n’est pas trouvée,
- Utilise le CODEBASE et tente de localiser la ressource (ce qui peut impliquer de contacter un site distant).
Tous les chargeurs de classe rechercheront une ressource d’abord en tant que ressource système, d’une manière analogue à la recherche de fichiers de classe. Cette règle de recherche permet d’écraser localement n’importe quelle ressource. Les clients doivent choisir un nom de ressource qui sera unique (en utilisant le nom de la société ou du paquetage comme préfixe, par exemple).
Noms de ressources
Une convention commune pour le nom d’une ressource utilisée par une classe est d’utiliser le nom pleinement qualifié du paquetage de la classe, maisconvertit tous les points (.) en barres obliques (/), et ajoute un nom de ressource de la forme name.extension
. Pour supporter cela, et pour simplifier la manipulation des détails des classes système (pour lesquellesgetClassLoader
renvoie null), la classeClass
fournit deux méthodes de commodité qui appellent les méthodes appropriées dans ClassLoader
.
Le nom de ressource donné à une méthode Class
peut avoir une initiale commençant par « / » qui l’identifie comme un nom « absolu ».Les noms de ressources qui ne commencent pas par un « / » sont « relatifs ».
Les noms absolus sont dépouillés de leur « / » initial et sont passés, sans autre modification, à la méthodeClassLoader
appropriée pour localiser la ressource. Les noms relatifs sont modifiés selon la convention décrite précédemmentet sont ensuite passés à une méthode ClassLoader
.
Utilisation des méthodes de la classe java.lang.Class
La classe Class
implémente plusieurs méthodes pour charger des ressources.
La méthode getResource()
renvoie une URL pour la ressource. L’URL (et sa représentation) est spécifique à l’implémentation et à la JVM (c’est-à-dire que l’URL obtenue dans une instance de temps réel peut ne pas fonctionner dans une autre). Son protocole est généralement spécifique au ClassLoader
qui charge la ressource. Si la ressource n’existe pas ou n’est pas visible pour des raisons de sécurité, les méthodes renvoient null.
Si le code client veut lire le contenu de la ressource comme un InputStream
, il peut appliquer la méthodeopenStream()
sur l’URL. Ceci est suffisamment courant pour justifier l’ajout de getResourceAsStream()
àClass
et ClassLoader
.getResourceAsStream()
est identique à l’appel degetResource().openStream()
, sauf quegetResourceAsStream()
attrape les exceptions IO et retourne un InputStream
nul.
Le code client peut également demander le contenu de la ressource en tant qu’objet en appliquant la méthode java.net.URL.getContent()
sur l’URL. Ceci est utile lorsque la ressource contient les données d’une image, par exemple. Dans le cas d’une image, le résultat est un objet awt.image.ImageProducer
, et non un objetImage
.
Les méthodes getResource
etgetResourceAsStream
trouvent une ressource avec un nom donné. Elles renvoient null si elles ne trouvent pas de ressource avec le nom spécifié. Les règles de recherche des ressourcesassociées à une classe donnée sont mises en œuvre par leClassLoader de la classe. Les méthodes Class
délèguent aux méthodesClassLoader
, après avoir appliqué une convention de nommage : si le nom de la ressource commence par « / », il est utilisé tel quel.Sinon, le nom du paquet est ajouté au préalable, après avoir converti tous les points (.) en barres obliques (/).
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);}
La méthode resolveName
ajoute un préfixe de nom de paquet si le nom n’est pas absolu, et supprime tout « / » de tête si le nom est absolu. Il est possible, bien que peu fréquent, d’avoir des classesdans différents paquets partageant la même 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;}
Utilisation des méthodes de java.lang.ClassLoader
La classe ClassLoader
possède deux ensembles de méthodes pour accéder aux ressources. Un ensemble renvoie un InputStream
pour la ressource. L’autre ensemble renvoie une URL. Les méthodes qui renvoient un InputStream
sont plus faciles à utiliser et satisferont de nombreux besoins, tandis que les méthodes qui renvoient des URL permettent d’accéder à des informations plus complexes, comme une image et un clip audio.
La classe ClassLoader
modifie les ressources de façon similaire à la façon dont elle gère les classes. Un ClassLoader
contrôle la manière de faire correspondre le nom d’une ressource à son contenu. La classe ClassLoader
fournit également des méthodes d’accès aux ressources du système,analogues aux classes du système. La classe Class
fournit quelques méthodes de commodité qui délèguent la fonctionnalité aux méthodes ClassLoader
.
De nombreux programmes Java accéderont à ces méthodes indirectement par le biais des API I18N (localisation). D’autres y accéderont par le biais des méthodes de Class
. Quelques-uns invoqueront directement les méthodesClassLoader
.
Les méthodes dans ClassLoader
utilisent la chaîne donnée comme nom de la ressource sans appliquer de transformation absolue/relative (voir les méthodes dans Class). Le nom ne doit pas comporter un « / » en tête.
Les ressources système sont celles qui sont gérées directement par l’implémentation hôte. Par exemple, elles peuvent être situées dans leCLASSPATH.
Le nom d’une ressource est une séquence d’identifiants séparés par « / ». La classe Class
fournit des méthodes de commodité pour accéder aux ressources ; les méthodes mettent en œuvre une convention où le nom du paquet est préfixé au nom court de la ressource.
Les ressources peuvent être accédées comme un InputStream
, ou unURL.
La méthode getSystemResourceAsStream
renvoie unInputStream pour la ressource système spécifiée ou null si elle ne trouve pas la ressource. Le nom de la ressource peut être n’importe quelle ressource système.
La méthode getSystemResource
trouve une ressource système avec le nom spécifié. Elle renvoie une URL vers la ressourceou null si elle ne trouve pas la ressource. L’appel dejava.net.URL.getContent()
avec l’URL renverra un objet tel que ImageProducer
, AudioClip
, ou InputStream
.
La méthode getResourceAsStream
renvoie unInputStream
pour la ressource spécifiée ou null si elle ne trouve pas la ressource.
La méthode getResource
trouve une ressource avec le nom spécifié. Elle renvoie une URL vers la ressource ou null si elle ne trouve pas la ressource. L’appel dejava.net.URL.getContent()
avec l’URL renverra unobjet tel que ImageProducer
, AudioClip
, ou InputStream
.
Sécurité
Puisque getResource()
permet d’accéder à des informations, il doit avoir des règles de sécurité bien définies et fondées. Si les considérations de sécurité ne permettent pas à une ressource d’être visible dans un certain contexte de sécurité, la méthode getResource()
échouera (retournera null) comme si la ressource n’était pas présente du tout, ceci adresse les attaques d’existence.
Les chargeurs de classe ne peuvent pas fournir l’accès au contenu d’un fichier .class pour des raisons de sécurité et de performance. S’il estpossible d’obtenir une URL pour un fichier .class dépend des spécificités, comme indiqué ci-dessous.
Il n’y a pas de problèmes de sécurité ou de restrictions spécifiques concernant les ressources qui sont trouvées par un chargeur de classe non système.AppletClassLoader
fournit l’accès aux informations qui sont chargées à partir d’un emplacement source, soit individuellement, soit en groupe par le biais d’un fichier JAR ; ainsi AppletClassLoader
doit appliquer les mêmes règles checkConnect()
lorsqu’il traite les URL par le biais de getResource()
.
Le système ClassLoader
fournit l’accès aux informations dans le CLASSPATH. Un CLASSPATH peut contenir des répertoires et des fichiers JAR. Puisqu’un fichier JAR est créé intentionnellement, il a une signification différente de celle d’un répertoire où les choses peuvent se retrouver de manière plus occasionnelle. En particulier, nous sommes plus stricts sur l’obtention d’informations à partir d’un répertoire qu’à partir d’un fichier JAR.
Si une ressource est dans un répertoire:
-
getResource()
les invocations utiliserontFile.exists()
pour déterminer s’il faut rendre le fichiercorrespondant visible à l’utilisateur. Rappelons queFile.exists()
utilise la méthodecheckRead()
dans le gestionnaire de sécurité. - il en va de même pour
getResourceAsStream()
.
Si la ressource est dans un fichier JAR:
-
getResource()
les invocations réussiront pour tous les fichiers, que l’invocation soit faite à partir d’une classe système ou non système. -
getResourceAsStream()
les invocations réussiront pour les ressources non .class, ainsi que pourjava.net.URL.getContent()
sur les URL correspondantes.
Exemples
Cette section fournit deux exemples de code client. Le premierexemple utilise des noms de « ressources absolues » et des mécanismes traditionnels pour obtenir un objet Class
.
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. }}
Cet exemple utilise des noms de « ressources relatives » et le mécanisme disponible auprès du compilateur par le biais du drapeau -experimental
, pour obtenir un objet Class
.
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. }