Title: Approfondissement du Java
1Approfondissement du Java
- X. BLANC J. DANIEL
- Xavier.Blanc_at_lip6.fr , Jerome.Daniel_at_der.edf.fr
2Plan du cours
- Compléments sur la langage Java
- L'API Reflexion
- Le chargement de classes
- La sécurité dans Java
- Les interfaces natives
3Compléments sur la langage Java
- Approfondissement de Java
- X.BLANC J. DANIEL
4Commenter ses programmes Java
- Pour commenter les programmes Java, on peut
utiliser le système javadoc qui permet par
la suite la génération automatique de
documentations. - Format d'un commentaire javadoc
- /
- Placer ici le commentaire JavaDoc
- /
Le début du commentaire est obligatoirement /
5Les tags de JavaDoc
- Les tags identifient des sections afin de
structurer le commentaire. - Les tags disponibles sont
- author
- version
- param
- return
- exception
- see
- deprecated
- Chaque tag respecte la syntaxe suivante
- _at_tag valeur
6Génération des documentations
- L'utilitaire javadoc permet de générer les
documentations. - javadoc options fichiers sources
- La génération des documentations peut être
personnalisée à l'aide de doclet . - mise à disposition d'une API permettant de
récupérer les informations de commentaires, - utilisation de l'option -doclet
7Les attentes de signaux
- L'instruction wait bloque le thread courant.
- public void wait()
- public void wait( long timeout )
- L'instruction notify débloque un thread en
attente. - public void notify()
- L'instruction notifyAll débloque tous les
threads qui sont en attentes. - public void notifyAll()
L'objet sur lequel s'applique ces opérations
d'attentes est appelé un moniteur.
8Utilisation des moniteurs
- Utilisez la notion de moniteur pour développer
des opérations substituants suspend et
resume .
9Le clonage
- Le clonage permet la copie d'un objet java.
- Pour pouvoir être cloné, un objet doit implanter
l'interface java.lang.Cloneable . - La méthode clone de la classe objet permet le
clonage d'un objet champs par champs. - Les champs statiques ne sont pas clonés.
Si un objet clonable contient un autre objet
clonable, celui-ci ne sera pas automatiquement
cloné.
10Gestion des processus
- Avec Java, on peut gérer les processus
- création et exécution de processus,
- arrêt de processus
- Deux classes importantes sont à utiliser
- java.lang.Runtime
- java.lang.Process
- On récupère le Runtime via l'opération statique
getRuntime de l'interface Runtime - static public Runtime getRuntime()
11La classe java.lang.Runtime
- Cette classe permet entre autre d'obtenir des
informations sur l'environnement d'exécution - mémoire disponible freeMemory
- mémoire totale totalMemory
- On peut également créer de nouveau processus
- Process exec( String command )
- throws IOException
- Process exec( String command, String envp )
- throws IOException
12La classe java.lang.Process
- La classe Process symbolise un processus. Les
opérations disponibles sont - void destroy() supprime le processus
- int waitFor() suspend l'exécution du thread
courant jusqu'à la fin de ce processus ( avec
exception possible IllegalThreadStateException
) - int exitStatus() retourne le code d'arrêt du
processus - On peut aussi accéder aux flux d'entrées et de
sorties du processus - InputStream getInputStream( )
- OutputStream getOutputStream( )
- InputStream getErrorStream( )
13Utilisation des processus
- Mettre en place une application qui exécute trois
processus fils ou chaque fils effectue une simple
attente de 10 secondes. - Si au bout de 30 secondes, les processus fils ne
sont pas terminés, le père doit tuer tous ses
fils encore vivants.
14L'API Reflexion
- Approfondissement de Java
- X.BLANC J. DANIEL
15Une API réflexive !
- Java permet d'obtenir des informations de
descriptions sur les classes, les opérations, les
types, etc.. - Grâce à la réflexion, on peut analyser
dynamiquement un classe, mais également
l'utiliser. - Offre une grande souplesse d'utilisation des
applications java telle que la mobilité du code.
16Obtenir la description d'une classe Java
- Une classe est symbolisée par la classe
java.lang.Class - Chaque instance de classe peut retourner un
descripteur de sa classe par l'intermédiaire de
l'opération getClass - maClasse m new maClasse()
- java.lang.Class cl m.getClass()
- Chaque classe comporte également un attribut
appelé class pour récupérer sa description - java.lang.Class cl maClass.class
17Obtention dynamique d'une description !
- A partir du nom d'une classe, on peut récupérer
dynamiquement sa description en utilisant
l'opération statique forName - java.lang.Class cl java.lang.Class.forName("ex
emple.maClasse") - Attention, cette opération retourne l'exception
ClassNotFoundException
18La classe java.lang.Class
- La classe Class retourne toutes les
informations permettant de connaître la
description d'une classe - son nom ( getName ),
- son package ( getPackage ) ,
- ses constructeurs ( getConstructors ),
- ses méthodes ( getMethods ),
- ses attributs ( getFields ),
- son ancêtre ( getSuperclass ) ,
- les interfaces qu'elle implante ( getInterfaces
).
19Description d'un Package
- La description d'un package est offert par la
classe
java.lang.Package au moyen de l'opération
getPackage - java.lang.Package getPackage()
- Cette classe propose les opérations suivantes
- String getName() retourne le nom du package
- Package getPackage() retourne le package de ce
package - Package getPackages() retourne la liste des
packages de ce package.
20Description des constructeurs
- Pour décrire un constructeur, on utilise classe
java.lang.reflect.Constructor . Les descriptions
de constructeurs sont retournés par
getConstructors - java.lang.reflect.Constructor
getConstructors() - Les opérations de java.lang.reflect.Constructor
sont - String getName() retourne le nom du
constructeur - int getModifiers() retourne les modificateurs
qui s'appliquent au constructeur - java.lang.Class getExceptionType() retourne les
descriptions des exceptions lancées par le
constructeur
21Les modificateurs
- La classe java.lang.reflect.Modifier permet
la manipulation des modificateurs retournés par
les descriptions. - Cette classe propose un ensemble d'opérations
permettant de tester la validité d'un
modificateur ( final, abstract, public, private,
protected, static, transient, synchronized ). Ces
opérations respectent la syntaxe suivante - public static boolean isXXXXX( int modifier )
22Description des méthodes
- Afin de décrire une méthode, la classe
java.lang.reflect.Method est utilisée. Les
descriptions de méthodes sont retournées par
getMethods - java.lang.reflect.Method getMethods( )
- Les principales opérations de cette classe sont
- String getName() retourne le nom de la méthode
- int getModifier() retourne les modificateurs de
la méthodes - Class getExceptionType() la liste des
exceptions - Class getParamType() la liste des paramètres
- Class getReturnType() retourne le type de
retour de la méthode
23Description des attributs
- Pour décrire un attribut, la classe
java.lang.reflect.Field est utilisée. - Java.lang.reflect.Field getFields()
- Les principales opérations sont
- String getName() nom de l'attribut
- int getModifier() modificateur de l'attribut
- Class getType() type de l'attribut
- Pour savoir, si un type est un type primitif ,
on utilise l'opération isPrimitive .
24Description des interfaces
- Afin de décrire une interface, on emploi la
classe
java.lang.Class ! - java.lang.Class getInterfaces()
- Pour savoir si une classe Class décrie une
interface, on utilise l'opération isInterface
.
25Description des tableaux
- Une classe Class peut décrire un tableau.
Pour savoir, si c'est un tableau on utilise
l'opération isArray - Pour connaître le type du tableau, on emploi
l'opération getComponentType
- if ( cl.isArray() )
-
- java.lang.Class type cl.getComponentType()
-
26Création dynamique d'une instance de classe !
- On peut créer dynamiquement une instance de
classe à l'aide de l'opération newInstance - try
-
- java.lang.Class clz java.lang.Class.forName("ma
Classe") - java.lang.Object obj clz.newInstance()
- maClasse maC ( maClasse ) obj
-
- catch ( java.lang.Exception ex )
-
- ex.printStackTrace( )
La classe à instancier doit impérativement
comporter un constructeur sans paramètre.
27Utilisation dynamique de constructeurs
- Si une classe comporte un constructeur avec
paramètres, on doit utiliser l'opération
newInstance de la classe Constructor afin
d'en créer une instance - java.lang.Object newInstance ( java.lang.Object
params )
28Utilisation dynamique d'une classe !
- L'API reflexion permet une utilisation dynamique
des classes - auto-description,
- instanciation à la demande.
- Il est impératif de pouvoir effectuer des
invocations dynamiques sans utiliser directement
le type de la classe cible. - java.lang.Class clz java.lang.Class.forName("ma
Classe") - java.lang.Object obj clz.newInstance()
- maClasse maC ( maClasse ) obj
29Appel dynamique d'une opération
- Pour appeler dynamiquement une opération, on
emploi invoke - java.lang.Object invoke ( java.lang.Object cible,
java.lang.Object params ) - Si une exception se produit lors de l'invocation,
l'opération invoke génère
l'exception
java.lang.reflect.Invocatio
nTargetException - Parmi les opérations de cette exception, on a
- void printStackTrace()
- Throwable getTargetException()
30Utilisation dynamique d'un attribut
- La classe Field comporte plusieurs opérations
permettant l'accès aux valeurs des attributs. - Ainsi, les opérations suivantes sont définies
pour les types primitifs - void setXXXX( java.lang.Object cible, XXXXX value
) - XXXX getXXXX( java.lang.Object cible )
- Pour les types complexes on a
- void set( java.lang.Object cible,
java.lang.Object value ) - java.lang.Object get( java.lang.Object cible )
31Mise à l'épreuve...
- Développez une méthode qui décrie une classe
- affiche ses constructeurs
- affiche ses méthodes
- affiche ses attributs.
32Le chargement de classes
- Approfondissement de Java
- X.BLANC J. DANIEL
33Notion de ClassLoader
- Pour charger les classes, la machine virtuelle
utilise un ClassLoader . - L'utilisateur peut définir son propre chargeur de
classes en surchargeant le chargeur standard. - La classe java.lang.ClassLoader symbolise le
chargeur de classes. - Pour connaître le chargeur d'une classe, on
emploi la méthode getClassLoader de la
classe Class
La méthode getClassLoader renvoie NULL avec
le JDK 1.1.x si le chargeur utilisé n'est pas un
chargeur utilisateur.
34Le chargeur système
- La machine virtuelle permet de récupérer une
référence vers le chargeur du système. - Pour cela, on utilise la méthode statique
getSystemClassLoader de la classe ClassLoader
- public static java.lang.ClassLoader
getSystemClassLoader()
Cette méthode peut éventuellement renvoyer NULL !
35Fonctionnement d'un chargeur de classe
Classe Java
Application Java
Classe Java
Classe Java
Classe Java
Chargement des classes constituant l'application
Chargement direct
Chargeur
Chargeur système
Délégation du chargement
JVM
Classe Java
36Ecrire un chargeur de classe !
- Pour écrire son propre chargeur de classe on doit
- hériter de la classe java.lang.ClassLoader
- Surcharger la méthode findClass
- public java.lang.Class findClass( String name )
- Enfin, la méthode findClass doit
- récupérer le code correspondant à la classe,
- définir une classe ( passage du byte code à la
classe ). Pour ce faire, on utilise la méthode
defineClass - protected final java.lang.Class defineClass(
String name, byte b, int off, int len )
La méthode defineClass ne doit jamais être
appelée deux fois pour la même classe.
37Remarque sur le chargeur
- Lorsqu'une classe est chargée à partir d'un
chargeur utilisateur, toutes les classes qu'elle
utilise seront chargées par ce même chargeur. - Si le système demande le chargement de deux fois
la même classe, on peut vérifier que cela n'a
pas été déjà fait par - protected final java.lang.Class
findLoadedClass( String name ) - Pour pouvoir utiliser une classe chargée, on doit
la résoudre - protected final void resolveClass(
java.lang.Class class )
38La classe URLClassLoader
- Le JDK 1.2 propose un chargeur standard symbolisé
par la classe java.net.URLClassLoader
pour charger des classes à partir de sites
spécifiés via des URLs. - URLClassLoader( String URLs )
- Parmi les méthodes les plus utilisées de cette
classe, on distingue - void addURL( String )
- static URLClassLoader newInstance( String URLs
) - Pour déclencher le chargement d'une classe, on
doit pour tous les chargeurs appeler la méthode
loadClass - public java.lang.Class loadClass( String name )
throws ClassNotFoundException
39A vous...
- Ecrire son propre chargeur de classes en
récupérant depuis un fichier de propriétés le nom
du répertoire où se trouvent les fichiers sources.
40La sécurité dans Java
- Approfondissement de Java
- X.BLANC J. DANIEL
41La sécurité dans Java
- Les objectifs de la sécurité sont
- Fournir un environnement Java sécurisé de telle
sorte que les exécutions des applications java
seffectuent dune manière sécurisée. - Fournir un ensemble de mécanismes pour une
utilisation à grande échelle permettant un
contrôle de la sécurité.
42Le modèle du JDK 1.0
- Le modèle de sécurité du JDK 1.0 est connu sous
le nom de sandbox
Code distant
Code local
sandbox
J V M
Ressources ( fichiers, imprimantes, etc )
Accès très restreint pour le code distant (
Applet )
43Le modèle du JDK 1.1
- Le JDK 1.1 introduit la notion dapplet signée
qui est l association d un code distant (
Applet ) avec une signature.
Code distant
Code distant signé
Code local
sandbox
J V M
Ressources ( fichiers, imprimantes, etc )
Le code signé est utilisé comme un code local
trusted
44Le modèle du JDK 1.2
- Dans le JDK 1.2, les applications sexécutent
selon des règles ( policy ) énumérés
extérieurement.
Code local ou distant ( signé ou pas )
Règles
loader
sandbox
J V M
Ressources ( fichiers, imprimantes, etc )
Une gestion très fine de la sécurité.
45Classes, Domaines et Permissions
- Une permission est un droit daccès également
appelé privilège. - Un domaine est une entité soumis à plusieurs
permissions. - Un domaine regroupe plusieurs classes. Chaque
classe du domaine profite alors des permissions
de ce domaine. - Domaines des applications
- Domaines systèmes
46Gestion des permissions
- Une classe de permission permet davoir accès à
une ressource du système. - La classe java.security.Permission correspond
à la classe de base de toutes les permissions
Java. - Les permissions peuvent également être manipulées
sous forme dun ensemble ( de permissions
hétérogènes ) en utilisant la classe
java.security.Permissions
47Quelques types de permissions
- Permissions pour accéder à un fichier
- java.io.FilePermission
- Permissions pour utiliser les sockets
- java.net.SocketPermission
- Permissions pour utiliser les propriétés
- java.util.PropertyPermission
- Permissions pour utiliser le Runtime
- java.lang.RuntimePermission
- Permissions sur lAPI reflexion
- java.lang.reflect.ReflectPermission
- Permissions sur la sécurité
- java.security.SecurityPermission
48Les permissions sur les fichiers
- La classe java.io.FilePermission accorde les
droits suivants - lecture read
- écriture write
- suppression delete
- exécution execute
- Création d'une permission pour les fichiers
- java.io.FilePermission( chemin , droits )
- Exemple
- java.io.FilePermission perm
- new java.io.FilePermission("/tmp/", "read,
write")
49Contrôle daccès
- Pour gérer les permission, on utilise un
contrôleur d'accès symbolisé par la classe
java.security.AccessController - Pour vérifier une permission, on utilise
l'opération
checkPermission - java.io.FilePermission perm
- AccessController.checkPermission( perm )
- On peut aussi exécuter une opération selon un
privilège spéciale. On appel une telle opération
une action privilégiée.
50Les actions privilégiées
- Une action privilégiée est un ensemble de code
implantant l'interface java.security.PrivilegedA
ction - interface PrivilegedAction
-
- Object run( )
-
- Pour lancer une action privilégiée, on utilise
l'opération doPrivilege du
contrôleur d'accès -
- Object doPrivileged( PrivilegedAction action )
51Le gestionnaire de sécurité
- Un environnement Java est lié à un gestionnaire
de sécurité symbolisé par la classe
java.lang.SecurityManager . - Le gestionnaire de sécurité utilise un contrôleur
d'accès, ce qui permet de vérifier la validité
d'une permission. - ClassLoader loader this.getClass().getClassLoad
er() - if (loader ! null)
-
- SecurityManager security System.getSecurityMan
ager() - if (security ! null)
- security.checkRead("path/file")
-
- On peut surcharger le gestionnaire de sécurité
pour fournir sa propre gestion de la sécurité.
52Les fichiers de permissions
- On peut à l aide d un fichier de policy
énumérer plusieurs permissions - grant SignedBy xxxx
-
- permission permission_class_name options
- // autres permissions...
-
- Exemple
- grant
-
- permission java.io.FilePermission "/tmp/",
"read, write"
53Chargement sécurisé de classes
- En définissant ses propres chargeurs de classes,
lutilisateur peut violer la sécurité de
lenvironnement. - On peut pour résoudre ce problème, hériter de la
classe java.security.SecureCl
assLoader pour définir ses propres chargeurs. - Utilisation des permissions,
- Plus grandes libertés dans le cas dApplet
54Epilogue sur la sécurité
- Spécification de paramètres de sécurité depuis la
ligne de commande - java.security.manager
- java.security.policy
- Le JDK 1.2 augmente considérablement la gestion
de la sécurité dans Java. Mais certains travaux
restent à mettre en place comme la gestion de
l'identité et de l'authentification.
55Les interfaces natives
- Approfondissement de Java
- X.BLANC J. DANIEL
56Utiliser depuis Java un code non Java !
- Pour des besoins spécifiques, il est parfois
indispensable d'ajouter des éléments natifs aux
diverses classes Java. - Par exemple, on peut sous Windows imaginer une
classe qui permette de récupérer la valeur d'une
variable de l'environnement Windows. - Pour cela, on doit faire appel à des méthodes
natives. Plusieurs interfaces natives ont été
définies pour pouvoir utiliser depuis Java du
code non Java.
57Signaler qu'une méthode est native
- Pour indiquer depuis Java qu'une méthode est
native, on doit tout de même la déclarer et
utiliser le modificateur native . - Exemple
- public native void printMessage( String message
) - On doit également demander à Java de charger la
librairie qui contient le code de cette méthode
native. On utilise pour cela l'opération
loadLibrary de la classe System . - static
-
- System.loadLibrary("Exemple")
-
La librairie est une librairie partagée ( DLL
sous Windows ) qui doit être placée dans un
répertoire accessible depuis le PATH
58JNI Java Native Interface
- JNI à été ajoutée au JDK 1.1 pour permettre
l'appel de méthode native depuis Java. - L'utilitaire javah -jni xxxx permet la
conception d'un header C pour la définition du
code natif. - JNI fournie une API permettant de mettre en place
un wrapper pour interagir entre le C et les
différents types et objets de Java.
59Les difficultés de JNI
- On doit tout d'abord utiliser l'API de JNI pour
accéder à tous les éléments d'un objet Java. - L'écriture d'une application complexe vient tout
de suite très laborieuse à mettre en place. - Se méfier des accès concurrents dues à plusieurs
threads Java. - Interactions complexes avec le garbage collector !
60J/Direct
- J/Direct est une interface native proposée par
Microsoft, qui permet un accès facile aux
opérations de l'API Win 32. - On peut également utiliser J/Direct pour appeler
des opérations depuis d'autres DLL. - Ce mécanisme est plus lent que JNI ou RNI mais
s'avère très simple à mettre en uvre et ne
requiert pas d'adaptation (wrapper) entre les
deux environnements.
61Utilisation de J/Direct
- Dans J/Direct, on utilise un commentaire Javadoc
spécial pour importer une librairie ( DLL )
_at_dll.import - /
- _at_dll.import("Exemple")
- /
- private native void printMessage(String text )
_at_dll.import peut également s'appliquer à toute
une classe en faisant précéder la déclaration de
celle-ci par le commentaire adéquat.
62RNI ( Raw Native Interface )
- RNI est également une extension apportée par
Microsoft pour effectuer des appels natifs mais
cette fois-ci, c'est au développeur de
l'interface de gérer la phase de garbage
collection. - RNI s'utilise sur le même principe que JNI et
fournie essentiellement les même possibilités. - Par exemple, on doit utiliser msjavah à la
place de javah . - Dans RNI, on a directement accès à la
représentation binaire de l'objet ce qui permet
de manipuler directement les champs de celui-ci.
Le format binaire d'un objet n'est pas forcément
le même d'une machine virtuelle à l'autre...