La plupart des programmes peuvent être configurés par leurs utilisateurs. Il doivent ensuite enregistrer les préférences définies, puis les restaurer au moment du redémarrage. Dans ce cas de figure, le programme est fourni avec un fichier de configuration que l'utilisateur peut éventuellement régler indépendamment du programme lui-même. Nous montrerons ici une approche simple permettant de stocker les informations de configuration que les applications Java adoptent généralement.
Une concordance de propriétés est une structure de données qui stocke les paires clé / valeur. Les concordances de propriétés permettent souvent de stocker des informations de configuration. Elles possèdent trois caractéristiques particulières :
La classe de la plate-forme Java qui implémente une concordance de propriété s'appelle java.util.Properties. Ainsi, les concordances de propriétés sont utiles pour spécifier des options de configuration pour les programmes. Voici un exemple qui permet à un utilisateur de configurer le titre du programme ainsi que le message d'invite. Pour cela, nous passerons par différentes phases :
Properties réglages = new Properties(); réglages.put("titre", "Intitulé de l'application"); réglages.put("invite", "Bienvenue à tous !");
La première chose à faire est de créer l'objet (réglages), représentant l'ensemble des propriétés de l'application et ensuite de spécifier chacune des clés avec la valeur associée au moyen de la méthode put().
Utilisez la méthode store() pour enregistrer cette liste de propriétés dans un fichier. Ici, nous enregistrons simplement la concordance de propriétés réglages dans le fichier de configuration réglages.properties :
FileOutputStream fichier = new FileOutputStream("réglages.properties"); réglages.store(fichier, "Réglages du logiciel");
Le deuxième argument de la méthode store() est un commentaire inclus en tête du fichier de configuration. Le jeu d'exemple donne le fichier de configuration suivant :
#Réglages du logiciel #Fri Sep 22 17:52:15 CEST 2006 invite=Bienvenue \! titre=Titre de l'application
Les fichiers de configuration en Java comporte généralement l'extension *.properties.
.
Une fois que le fichier de configuration est constitué, vous pouvez à tout moment récupérer son jeu de propriétés à partir de la méthode load() de la classe Properties. Ensuite, utilisez la méthode getProperty() pour atteindre la propriété désirée afin d'effectuer les réglages en conséquence :
import java.io.*; import java.util.Properties; public class Propriétés { public static void main(String[] args) throws IOException { // lecture du fichier de propriétés System.out.println("Lecture du fichier de propriétés..."); Properties lecture = new Properties(); lecture.load(new FileInputStream("réglages.properties")); System.out.println("Titre : "+lecture.getProperty("titre")); System.out.println("Message : "+lecture.getProperty("invite")); } }
Si l'utilisateur omet certains paramètres dans le fichier de configuration, il est possible de fournir des paramètres par défaut. La classe Properties possède deux mécanismes pour fournir les paramètres par défaut :
En partant du fichier de configuration réglages.properties suivant :
#Réglages du logiciel #Fri Sep 22 17:52:15 CEST 2006 invite=Bienvenue \!
Et à partir du programme suivant :
import java.io.*; import java.util.Properties; public class Propriétés { public static void main(String[] args) throws IOException { // création d'une concordance de propriété secondaire Properties parDéfaut = new Properties(); parDéfaut.put("titre", "Titre par défaut"); parDéfaut.put("invite", "Bienvenue à tous !"); // lecture du fichier de propriétés System.out.println("Lecture du fichier de propriétés..."); Properties lecture = new Properties(parDéfaut); // placer le tableau secondaire en paramètre du constructeur lecture.load(new FileInputStream("réglages.properties")); System.out.println("Titre : "+lecture.getProperty("titre")); System.out.println("Message : "+lecture.getProperty("invite")); } }
Voici ce que nous obtenons :
Le tableau secondaire doit toujours être placé en paramètre du constructeur de la classe Properties qui représente le fichier de configuration.
Afin de bien montrer l'intérêt de configurer un logiciel au travers de préférences définies par l'utilisateur, je vous propose de le visualiser au travers d'une étude traduite sous la forme d'une application graphique. A remarquer qu'il est possible de fabriquer son fichier de configuration manuellement. C'est ce qui a été réalisé dans cet exemple.
Ce logiciel comporte plusieurs classes ainsi qu'une image à faire afficher en papier peint. Par ailleurs le texte qui s'affiche est sensible au mouvement du curseur de la souris, puisque lorsque ce dernier se déplace sur le texte, celui-ci change alors de couleur. Le texte reprend ensuite sa couleur d'origine lorsque le curseur de la souris s'en va en dehors de la zone de texte.
Voici donc notre application Java, avec le résultat obtenu suivi de l'architecture de notre arborescence ainsi que le codage de l'ensemble de ces classes écrit dans le même fichier "Principal.java".
Principal.java |
---|
package texte; import java.awt.event.*; import java.io.*; import java.util.Properties; import javax.imageio.ImageIO; import javax.swing.*; import java.awt.*; public class Principal extends JFrame { private Properties réglages = new Properties(); public Principal() throws IOException { this.setDefaultCloseOperation(this.EXIT_ON_CLOSE); this.setSize(350, 250); réglages.load(new FileInputStream("réglages.properties")); this.setTitle(réglages.getProperty("titre")); this.getContentPane().add(new PanneauImage(réglages)); } public static void main(String[] args) throws IOException { new Principal().setVisible(true); } } class PanneauImage extends JPanel { private Image image; private Texte invite; public PanneauImage(Properties réglages) throws IOException { image = ImageIO.read(new File(réglages.getProperty("image"))); invite = new Texte(réglages.getProperty("message")); invite.setCouleurSurvol(Color.red); invite.setCouleurNormale(Color.blue); this.add(invite); } protected void paintComponent(Graphics g) { g.drawImage(image, 0, 0, this); } } class Texte extends JLabel implements MouseListener { private Color couleurSurvol, couleurNormale; public Texte(String invite) { super(invite); this.setFont(new Font("Verdana", Font.BOLD, 28)); this.addMouseListener(this); } public void setCouleurSurvol(Color couleur) { couleurSurvol = couleur; } public void setCouleurNormale(Color couleur) { this.setForeground(couleurNormale = couleur); } public void mouseEntered(MouseEvent e) { this.setForeground(couleurSurvol); } public void mouseExited(MouseEvent e) { this.setForeground(couleurNormale); } public void mouseClicked(MouseEvent e) {} public void mousePressed(MouseEvent e) {} public void mouseReleased(MouseEvent e) {} } |
Lorsque votre logiciel est relativement conséquent, généralement beaucoup de fichiers sont créés et utilisés. Il est préférable dans ce cas là de déployer votre application au moyen d'une archive jar. Comme nous l'avons découvert dans l'étude précédente, nous devons passer par le système de ressources afin de permettre la récupération de fichier connexes comme les images et les fichiers de configuration. Ainsi, vous disposez d'un seul fichier, qui plus est compressé, qui empaquette l'ensemble de l'application.
Pour en savoir plus sur les archives et les ressources, reportez-vous sur le cours précédent.
En reprenant l'exemple précédent, voici toute la procédure à suivre, des différentes lignes de code jusqu'à la création de l'archive et le lancement de l'application :
Principal.java |
---|
package texte; import java.awt.event.*; import java.io.*; import java.util.Properties; import javax.imageio.ImageIO; import javax.swing.*; import java.awt.*; public class Principal extends JFrame { private Properties réglages = new Properties(); public Principal() throws IOException { this.setDefaultCloseOperation(this.EXIT_ON_CLOSE); this.setSize(350, 250); réglages.load(this.getClass().getResourceAsStream("ressources/reglages.properties")); this.setTitle(réglages.getProperty("titre")); this.getContentPane().add(new PanneauImage(réglages)); } public static void main(String[] args) throws IOException { new Principal().setVisible(true); } } class PanneauImage extends JPanel { private Image image; private Texte invite; public PanneauImage(Properties réglages) throws IOException { image = ImageIO.read(this.getClass().getResource("ressources/"+réglages.getProperty("image"))); invite = new Texte(réglages.getProperty("message")); invite.setCouleurSurvol(Color.red); invite.setCouleurNormale(Color.blue); this.add(invite); } protected void paintComponent(Graphics g) { g.drawImage(image, 0, 0, this); } } class Texte extends JLabel implements MouseListener { private Color couleurSurvol, couleurNormale; public Texte(String invite) { super(invite); this.setFont(new Font("Verdana", Font.BOLD, 28)); this.addMouseListener(this); } public void setCouleurSurvol(Color couleur) { couleurSurvol = couleur; } public void setCouleurNormale(Color couleur) { this.setForeground(couleurNormale = couleur); } public void mouseEntered(MouseEvent e) { this.setForeground(couleurSurvol); } public void mouseExited(MouseEvent e) { this.setForeground(couleurNormale); } public void mouseClicked(MouseEvent e) {} public void mousePressed(MouseEvent e) {} public void mouseReleased(MouseEvent e) {} } |
Maintenant que nous connaissons la notion de concordance de propriétés, nous pouvons aller un peu plus loin. il existe, en effet, des propriétés bien particulières qui correspondent aux réglages du système d'exploitation. Il s'agit en réalité de variables d'environnement que nous applelons propriétés système.
Les informations de votre système sont effectivement concervées dans un objet Properties renvoyé par la méthode statique getProperties() de la classe System. Pour accéder à une seule clé, vous pouvez alors faire appel à la méthode getProperty(clé) de cette même classe.
Le tableau suivant résume les propriétés système obligatoirement définies dans tout environnement Java :
Propriétés système | Signification |
java.vendor |
Chaîne désignant le concepteur |
Votre application peut également définir ses propres propriétés système à l'aide de la méthode statique setProperty() de la classe System.
.
Voici un exemple de code très simple qui recense à l'écran l'ensemble des propriétés du système :
import java.io.IOException; import java.util.Properties; public class Principal { public static void main(String[] args) throws IOException { Properties propriétés = System.getProperties(); propriétés.store(System.out, "Propriétés du système"); } }
Et voici le résultat :
#Propriétés du système
#Mon Sep 25 16:44:44 CEST 2006
java.runtime.name=Java(TM) 2 Runtime Environment, Standard Edition
sun.boot.library.path=C\:\\Program Files\\Java\\jdk1.5.0_05\\jre\\bin
java.vm.version=1.5.0_05-b05
java.vm.vendor=Sun Microsystems Inc.
java.vendor.url=http\://java.sun.com/
path.separator=;
java.vm.name=Java HotSpot(TM) Client VM
file.encoding.pkg=sun.io
user.country=FR
sun.os.patch.level=Service Pack 2
java.vm.specification.name=Java Virtual Machine Specification
user.dir=L\:\\BTS IRIS\\TP Java\\Syst\u00E8me
java.runtime.version=1.5.0_05-b05
java.awt.graphicsenv=sun.awt.Win32GraphicsEnvironment
java.endorsed.dirs=C\:\\Program Files\\Java\\jdk1.5.0_05\\jre\\lib\\endorsed
os.arch=x86
java.io.tmpdir=C\:\\DOCUME~1\\HP_PRO~1\\LOCALS~1\\Temp\\
line.separator=\r\n
java.vm.specification.vendor=Sun Microsystems Inc.
user.variant=
os.name=Windows XP
sun.jnu.encoding=Cp1252
java.library.path=C\:\\Program Files\\Java\\jdk1.5.0_05\\jre\\bin;.;C\:\\WINDOWS\\system32;
C\:\\WINDOWS;C\:\\WINDOWS\\System32\\Wbem;c\:\\Python22;
java.specification.name=Java Platform API Specification
java.class.version=49.0
sun.management.compiler=HotSpot Client Compiler
os.version=5.1
user.home=C\:\\Documents and Settings\\HP_Propri\u00E9taire
user.timezone=Europe/Paris
java.awt.printerjob=sun.awt.windows.WPrinterJob
file.encoding=Cp1252
java.specification.version=1.5
java.class.path=L\:\\BTS IRIS\\TP Java\\Syst\u00E8me\\build\\classes
user.name=HP_Propri\u00E9taire
java.vm.specification.version=1.0
java.home=C\:\\Program Files\\Java\\jdk1.5.0_05\\jre
sun.arch.data.model=32
user.language=fr
java.specification.vendor=Sun Microsystems Inc.
awt.toolkit=sun.awt.windows.WToolkit
java.vm.info=mixed mode
java.version=1.5.0_05
java.ext.dirs=C\:\\Program Files\\Java\\jdk1.5.0_05\\jre\\lib\\ext
sun.boot.class.path=C\:\\Program Files\\Java\\jdk1.5.0_05\\jre\\lib\\rt.jar;C\:\\Program Files\\Java\\jdk1.5.0_05\\jre\\lib\\i18n.jar;C\:\\Program Files\\Java\\jdk1.5.0_05\\jre\\lib\\sunrsasign.jar;C\:\\Program Files\\Java\\jdk1.5.0_05\\jre\\lib\\jsse.jar;
java.vendor=Sun Microsystems Inc.
file.separator=\\
java.vendor.url.bug=http\://java.sun.com/cgi-bin/bugreport.cgi
sun.io.unicode.encoding=UnicodeLittle
sun.cpu.endian=little
sun.desktop=windows
sun.cpu.isalist=