AWT (Abstract Window Toolkit) est l'ensemble des classes Java originales qui permet de faire des interfaces graphiques. Ces classes sont situées dans le package java.awt. AWT repose sur les widgets systèmes. Par widget on entend les boutons, les menus, etc...
Pour être portable au niveau également de l'apparence, et bien dégager la notion de modèle (par exemple une structure d'arbre) par rapport à son rendu (comment l'arbre va être affiché à l'écran), les classes Swing ont été créées. Ces classes sont dans le package javax.swing.
Le passage de AWT à Swing se fait facilement. Pour beaucoup de classes il suffit de rajouter un J devant le nom. Par exemple en AWT on dispose de Applet, Panel, Frame. Les classes équivalentes sont disponibles en Swing : JApplet, JPanel, JFrame. De plus on trouve des nouveaux composants très pratiques, comme par exemple : JTree pour afficher un arbre, JTabbedPane pour afficher des onglets.
Dans cette section plusieurs images proviennent de l'URL:
JApplet : Cette classe est une sous classe de java.applet.Applet. Elle permet de faire des applets où les composants sont des widgets Swing et non AWT. Son usage est similaire à celui de java.applet.Applet.
JDialog : C'est la classe swing qui permet de créer des dialogues sur mesure. Pour des dialogues simples on préfèrera utiliser la classe JOptionPane. Typiquement l'image ci-contre est obtenue à l'aire de JOptionPane. Il existe une classe toute faite pour obtenir une boite de dialogue permettant de choisir un fichier JFileChooser.
JFrame : C'est la classe qui remplace Frame dans l'AWT. Il s'agit d'une fenêtre avec les boutons standards.
JPanel : Il s'agit d'une classe destinée à contenir d'autres classes. Les attributs généralement modifiés sont la couleur du fond, les bords, ainsi que l'appel à la méthode void setLayout(LayoutManager mgr) pour gérer la manière dont les composants sont placés.
JScrollPane : Permet de visualiser un objet trop grand. Au lieu d'écrire directement dans un JPanel :
textArea = new JTextArea(5, 30); add(textArea, BorderLayout.CENTER);On peut le mettre préalablement dans un JScrollPane :
textArea = new JTextArea(5, 30); JScrollPane scrollPane = new JScrollPane(textArea); add(scrollPane, BorderLayout.CENTER);
JTabbedPane : Permet de mettre plusieurs JPanel dans des onglets. La méthode pour ajouter des onglets est add :
JTabbedPane tabbedPane = new JTabbedPane();
ImageIcon icon = createImageIcon("images/middle.gif");
JComponent panel1 = makeTextPanel("Panel #1");
tabbedPane.addTab("One", icon, panel1, "Does nothing");
...
JToolBar : Permet de créer une barre de boutons. Les boutons sont des instances de JButton. Un ActionListener leur est attribué. Il suffit de les ajouter dans la toolbar à l'aide de la commande add.
public class RecupereLesActions implements ActionListener {
public void actionPerformed(ActionEvent e) {
...
}
}
JToolBar toolBar = new JToolBar();
JButton button = new JButton();
RecupereLesActions recupereLesActions = new RecupereLesActions();
button.addActionListener(recupereLesActions);
toolBar.add(button);
JSplitPane : Permet d'affichier deux JPanels séparés verticalement ou horizontalement.
JSplitPane hSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
panel1,
panel2);
JInternalFrame : Permet d'affichier une fenêtre dans un JFrame.
JLayeredPane : Permet d'afficher des JPanels à différents niveaux.
JRootPane : C'est la structure à la base des composants Swing pouvant contenir des menus. Le JRootPane n'est pas l'objet dans lequel on ajoute des composants rootPane. add(child); est impossible, à la place on fera rootPane. getContentPane(). add(child);. Les JRootPane ne sont pas crées tout seuls, mais viennent en général avec des composants existants.
rootPane.getContentPane().setLayout(new BoxLayout());
JButton : représente les boutons. Cette classe partage la classe abstraite AbstractButton avec entre autres : JCheckBox, JRadioButton, JMenuButton, JCheckBoxMenuItem, JRadioButtonMenuItem.
public class ButtonDemo extends JPanel
implements ActionListener {
protected JButton b1, b2, b3;
public ButtonDemo() {
// ...
b1 = new JButton("MonBouton");
b1.setActionCommand("disable");
b1.setActionListener(this);
add(b1);
}
public void actionPerformed(ActionEvent e) {
if ("disable".equals(e.getActionCommand())) {
...
}
}
}
JComboBox : Permet de faire une liste dans laquelle l'utilisateur va pouvoir faire un seul choix. Il existe une forme éditable pour rajouter des items à la volée dans la liste.
JList : Permet d'afficher une liste d'objets, où l'utilisateur peut choisir plusieurs items.
JMenu : Permet de faire des menus. Les menus sont généralement ajoutés dans une barre de menus (JMenuBar) et comportent de items de type JMenuItem. L'exercice 1 détaille comment relier les menus aux actions à effectuer.
JSlider : Permet de rentrer une valeur numérique comprise entre deux bornes.
JSpinner : ressemble à une combo box mais sans partie dépliable qui peux recouvrir d'autres composants.
JTextField : permet de rentrer un champ texte.
JLabel : permet d'afficher une chaîne de caractères.
JProgressBar : Affiche une barre de progression.
JToolTip : Affiche des indications sur un composant.
JColorChooser : Dialogue permettant de choisir une couleur.
JFileChooser : Dialogue permettant de choisir un fichier. Une utilisation de cette classe est demandée dans l'exercice 1.
JTable : Permet d'afficher un tableau
JText :
JTree :
Plusieurs composants swing sont implémentés suivant l'architecture Model View Controler (MVC), c'est à dire que les fonctionnalités suivantes sont implémentées de manière séparées :
Les rôles view et controler sont souvent joués par les mêmes entités.
Le modèle s'obtient en général par la méthode getModel (par exemple dans JTree, JSlider, JTabbedPane ...).
Pour plus de détails :
L'exercice 2 donne une illustration d'un usage fréquent de l'architecture MVC.
Pour pouvoir gérer les évènements qui se produisent il faut implémenter l'interface correspondant à l'évènement.
class Toto implements java.awt.event.ActionListener {
public void actionPerformed(java.awt.event.ActionEvent e) {
// ...
}
}
et pour enregistrer une instance de Toto auprès
d'une instance de JTextField :
JTextField text = new JTextField(); Toto toto = new Toto(); text.addActionListener(toto);
class Toto implements javax.swing.event.ChangeListener {
public void stateChanged(javax.swing.event.ChangeEvent e) {
// ...
}
}
et pour enregistrer une instance de Toto auprès
d'une instance de JSlider :
JSlider slider = new JSlider(javax.swing.JSlider.HORIZONTAL,0,50,100); Toto toto = new Toto(); slider.addChangeListener(toto);
Voici une liste non exhaustive des évènements possibles:
Un tableau récapitulatif est présent à l'URL :
Voici les notions cryptographiques de base utilisées dans ce cours :
On va se servir de la classe KeyPairGenerator pour créer une clé RSA :
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(1024, new SecureRandom());
KeyPair pair = keyGen.generateKeyPair();
Les clés publiques et privées sont alors :
PublicKey pub = pair.getPublic();
PrivateKey priv = pair.getPrivate();
Pour sauver une clé (ou tout autre objet java sérialisable) on va utiliser un ObjectOutputStream dans le package java.io :
PublicKey pub = .... ;
FileOutputStream fout = new FileOutputStream("public.key");
ObjectOutputStream oos = new ObjectOutputStream(fout);
oos.writeObject(pub);
oos.close();
Pour la manipulation inverse où l'on créé l'objet pub
à partir du fichier public.key il suffit d'utiliser
un ObjectInputStream dans le package java.io :
FileInputStream fis = new FileInputStream("public.key");
ObjectInputStream ois = new ObjectInputStream(fis);
PublicKey pub = (PublicKey) ois.readObject();
ois.close();
Maintenant que nous avons les clés il faut créer un objet signature basé sur cette clé :
Signature rsa = Signature.getInstance("MD5withRSA");
rsa.initSign(priv);
L'initialisation à l'aide de la méthode initSign est réalisée
car on va signer le fichier. Si cela avait été pour vérifier
la signature on aurait appelé initVerify(pub)
où pub est la clé publique correspondant
à la clé privée générée.
Il faut alors faire ``passer'' tout le fichier à signer dans l'instance rsa :
FileInputStream fis = new FileInputStream(new File("nomdufichier"));
while (fis.available() != 0) {
rsa.update(fis.read());
}
fis.close();
Le résultat de la signature est alors obtenu par la commande :
byte [] sig = rsa.sign();
Pour l'exemple complet se réferrer à :
Java est pratique : on peut facilement télécharger du bytecode. Cependant dès lors que l'on télécharge du code que l'on ne connais pas, il est pratique de pouvoir restreindre les droits de ce dernier.
Considérons le code suivant d'une classe OpenFile qui affiche le contenu du fichier build.xml :
FileInputStream f = new FileInputStream ("build.xml");
int i=0;
byte [] b = new byte[1024];
while ((i=f.read(b))!=-1) {
System.out.println(new String(b));
}
Une fois compilé, ce code s'exécute sans problème avec par exemple
la commande : java OpenFile.
Rajoutons maintenant un fichier java.policy vide et lançons la ligne de commande :
java -Djava.security.manager -Djava.security.policy=java.policy OpenFileOn obtient alors l'erreur suivante :
java.security.AccessControlException: access denied
(java.io.FilePermission build.xml read)
Explication : le fichier java.policy vide ne donne aucun droit au code qui s'exécute. On dit que le code est contraint de jouer dans son bac à sable (ou sand box en anglais).
Le code réalisant ce test ainsi que le fichier ant correspondant sont téléchargeables à l'url :
Le code qui s'exécute peut obtenir des informations sur le SecurityManager (i.e., le bac à sable) dans lequel il s'exécute :
if (System.getSecurityManager()!=null) {
// alors il y a un security manager
java.security.AccessController.checkPermission
(new java.io.FilePermission("build.xml","write"));
}
Le code suivant génère une exception de type
java.security.AccessControlException si le code n'est pas autorisé
à écrire dans le fichier build.xml.
Si par exemple dans l'exemple précédent on veut donner seulement le droit de lire le fichier build.xml voici le contenu du fichier java.policy :
grant {
permission java.io.FilePermission "build.xml", "read";
};
Si on a vraiment confiance dans des classes situées dans un répertoire
donné on peut leur donner tous les privilèges :
grant codeBase "file:/chemin/vers/mes/classes/*" {
permission java.security.AllPermission;
};
Remarque : sous windows les chemins ne sont pas spécifiés
sous la forme file:/mon/chemin mais file:/C:/mon/chemin
pour c:\mon\chemin.
Pour plus de détails sur le fichier java.policy se reporter à l'url :
Plutôt que de stocker les clés dans des fichiers comme nous avons fait précédemment, java propose une interface manipulable en ligne de commande ou par un programme.
Cet endroit ou nous allons stocker les clés se nomme le keystore.
Il faut pour cela utiliser l'application keytool qui vient avec le JDK. L'option à rajouter sur la ligne de commande est -genkey, on peut en outre préciser le nom de clé générée (ici mykey), le type de clé (ici RSA), la taille (ici 1024) et le fichier de stockage (ici keystore) :
keytool -genkey -alias mykey -keyalg RSA -keysize 1024 -keystore keystore
Pour voir les clés qui sont stockées il suffit de taper :
keytool -list -keystore keystore
Si dans la liste on a une clé nommée mykey il suffit alors pour signer un fichier jar de taper :
jarsigner -keystore keystore monfichier.jar mykeyLes fichiers META-INF/MYKEY.SF et META-INF/MYKEY.DSA ont alors été rajoutés dans l'archive jar. Le fichier MANIFEST.MF a également été modifié, et contient en plus :
Name: ex1/ToDownload.class SHA1-Digest: Q4wliYWpbRKBTzUICVWjuo0+6fc=c'est à dire la liste des classes ainsi que leur signature par la clé mykey.
Le certificat public peut être créé à l'aide de la commande :
keytool -export -keystore keystore -alias mykey -file derepas.cer
Si l'on dispose d'une source de confiance nommée par exemple mykey, on a envie d'écrire un fichier java.policy de la forme :
grant signedBy "mykey" {
permission java.security.AllPermission;
};
dont la sémantique est la suivante :
fait entièrement confiance au code situé
dans un fichier jar qui a été signé
par la clé privée correspondant au certificat
de la clé publique dans le registre de clé
pour l'entrée nommée mykey.
Il faut charger le bon certificat. Pour cela récupérer le certificat public, puis l'importer dans le KeyStore :
keytool -import -alias mykey -file derepas.cer
Pour plus d'informations :
Q1 Le but de cette question est de rajouter un menu qui permet de sortir. Il faut rajouter un menu Fichier avec un item Quitter qui permet de fermer.
On va pour cela créer une classe nommée DrawingPanel qui ``enrobe'' la classe Drawing. On utilisera le squelette suivant :
package ex1;
public class DrawingPanel extends javax.swing.JPanel
{
Drawing drawing = null;
class QuitAction extends javax.swing.AbstractAction {
QuitAction() { super("quit"); }
public void actionPerformed(java.awt.event.ActionEvent e) {
quit();
}
}
DrawingPanel() {
// ...
}
public void quit() {
System.exit(0);
}
public javax.swing.JMenuBar createMenuBar() {
// ...
}
public static void main(String [] argv) {
javax.swing.JFrame frame = new javax.swing.JFrame("Drawing");
frame.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
DrawingPanel d = new DrawingPanel();
frame.setContentPane((javax.swing.JComponent)d);
frame.setJMenuBar(d.createMenuBar());
frame.pack();
frame.setVisible(true);
}
}
Indications : dans la méthode createMenuBar on créé
une instance de javax.swing.JMenuBar dans laquelle
on a ajouté une instance de javax.swing.JMenu
dans laquelle on a ajouté une instance de javax.swing.JMenuItem.
On aura utilisé la méthde addActionListener sur l'instance
de javax.swing.JMenuItem pour associer l'action correspondante.
Q2 Ajouter un item ouvrir dans le menu pour ouvrir un fichier. Indication : utiliser la classe javax.swing.JFileChooser pour choisir le fichier à ouvrir, appeler la méthode loadImage de la classe ex1.Drawing pour charger l'image.
Q3 Si cela n'a pas déjà été fait à la question 1, mettre l'instance de ex1.Drawing dans un javax.swing.JScrollPane pour pouvoir visualiser les images de taille importantes.
L'idée de l'exercice est de montrer qu'il est facile de remplacer un modèle existant par un modèle ayant de nouvelles fonctionnalités.
Q1 Créer une classe ex2.CustomSlider qui permet de choisir un entier à l'aide d'une classe JSlider et affiche la valeur dans un JTextField, comme illustré ci-dessous.
Q2 On souhaite qu'une modification du JTextField permette de modifier la position du slider. Indication : utiliser la méthode addActionListener sur le JTextField pour récupérer les changements.
Q3 On souhaite maintenant que la partie modèle stocke un double et non un int.
Téléchargez la classe CustomRangeModel à l'url :
On remarquera que CustomRangeModel implémente BoundedRangeModel. On peut donc s'en servir comme modèle pour n'importe quel JSlider.Replacer le modèle du JSlider grâce au constructeur JSlider(BoundedRangeModel brm). Adapter les méthodes précédemment écrites pour pouvoir rentrer des données de type double dans le JTextField.
Q1 Ecrire une classe Signataire qui génère une clé RSA de 1024 bits et signe un fichier.
Q2 Ecrire une classe Chargeur qui vérifie la signature d'un fichier étant donné la clé publique utilisée pour générer la signature. Pour comparer les signatures on utilisera la méthode Signature.verify.
Ces classes peuvent ensuite être utilisées pour effectuer des téléchargements sûrs sur internet.
Q1 Récupérer le certificat :
et l'installer dans un keystore.
Q2 Téléchargez le fichier jar
l'exécuter sans politique de sécurité. L'exécuter avec une politique de sécurité interdisant tout.
Q3 Exécuter le fichier jar précédent avec une politique de sécurité autorisant l'écriture des classes certifiées par le certificat de la première question. Pour spécifier comment utiliser le keystore de la question 1, se reporter à l'url :