Penser en Java 2nde édition | - | Sommaire | Préface | Avant-propos | Chapitre : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | Annexe : A B C D | Tables des matières | - | Thinking in Java |
L'objet sessionest fourni par défaut, il est donc disponible sans code supplémentaire. Les appels de getID( ), getCreationTime( ) et getMaxInactiveInterval( ) servent à afficher des informations sur l'objet session.
Quand on ouvre la session pour la première fois on a, par exemple, MaxInactiveInterval égal à 1800 secondes (30 minutes). Ceci dépend de la configuration du conteneur JSP/servlet. MaxInactiveInterval est ramené à 5 secondes afin de rendre les choses intéressantes. Si on rafraîchit la page avant la fin de l'intervalle de 5 secondes, alors on voit :
Mais si on attend un peu plus longtemps, alors » Ralph « devient null.
Pour voir comment les informations de sessions sont répercutées sur les autres pages, ainsi que pour comparer le fait d'invalider l'objet session à celui de le laisser se terminer, deux autres JSP sont créées. La première (qu'on atteint avec le bouton » invalidate « de SessionObject.jsp) lit l'information de session et invalide explicitement cette session :
Pour tester cet exemple, rafraîchir SessionObject.jsp, puis cliquer immédiatement sur le bouton invalidate pour activer SessionObject2.jsp. À ce moment on voit toujours » Ralph, « immédiatement (avant que l'intervalle de 5 secondes ait expiré). Rafraîchir SessionObject2.jsp pour voir que la session a été invalidée manuellement et que Ralph a disparu.
En recommençant avec SessionObject.jsp, rafraîchir la page ce qui démarre un nouvel intervalle de 5 secondes, puis cliquer sur le bouton « Keep Around »], ce qui nous amène à la page suivante, SessionObject3.jsp, qui N'invalide PAS la session :
Dû au fait que cette page n'invalide pas la session, » Ralph « est toujours là aussi longtemps qu'on rafraîchit la page avant la fin de l'intervalle de 5 secondes. Ceci n'est pas sans ressembler à un » Tomagotchi], et » Ralph « restera là tant que vous jouerez avec lui, sinon il disparaîtra.
Chaque navigateur ayant sa manière de stocker les cookies, le résultat sera différent suivant le navigateur (ce qui n'est pas rassurant, mais peut-être réparerez-vous un certain nombre de bugs en lisant cela). Par ailleurs, il se peut aussi que l'on ait des résultats différents en arrêtant le navigateur et en le relançant, plutôt que de visiter une autre page puis de revenir à Cookies.jsp. Remarquons que l'utilisation des objets session semble plus robuste que l'utilisation directe des cookies.
Après l'affichage de l'identifiant de session, chaque cookie du tableau de cookies arrivant avec l'objet request object est affiché, ainsi que sa date d'expiration. La date d'expiration est modifiée et affichée à son tour pour vérifier la nouvelle valeur, puis un nouveau cookie est ajouté à la réponse. Toutefois, il est possible que votre navigateur semble ignorer les dates d'expiration ; il est préférable de jouer avec ce programme en modifiant la date d'expiration pour voir ce qui se passe avec divers navigateurs.
Cette section était un bref apperçu des JSP ; cependant avec les sujets abordés ici (ainsi qu'avec le langage Java appris dans le reste du livre, sans oublier votre connaissance personnelle du langage HTML) vous pouvez dès à présent écrire des pages Web sophistiquées via les JSP. La syntaxe JSP n'est pas particulièrement profonde ni compliquée, et si vous avez compris ce qui était présenté dans cette section vous êtes prêts à être productifs en utilisant les JSP. Vous trouverez d'autres informations dans la plupart des livres sur les servlets, ou bien à java.sun.com.
La disponibilité des JSP est très agréable, même lorsque votre but est de produire des servlets. Vous découvrirez que si vous vous posez une question à propos du comportement d'une fonctionnalité servlet, il est plus facile et plus rapide d'y répondre en écrivant un programme de test JSP qu'en écrivant une servlet. Ceci est dû en partie au fait qu'on ait moins de code à écrire et qu'on puisse mélanger le code Java et le code HTML, mais l'avantage devient particulièrement évident lorsqu'on voit que le Conteneur JSP se charge de la recompilation et du chargement du JSP à votre place chaque fois que la source est modifiée.
Toutefois, aussi fantastiques que soient les JSP, il vaut mieux garder à l'esprit que la création de pages JSP requiert un plus haut niveau d'habileté que la simple programmation en Java ou la simple création de pages Web. En outre, debugger une page JSP morcelée n'est pas aussi facile que débugger un programme Java, car (pour le moment) les messages d'erreur sont assez obcurs. Cela changera avec l'évolution des systèmes de développement, et peut-être verrons nous d'autres technologies construites au-dessus de Java plus adaptées aux qualités des concepteurs de site web.
Les approches traditionnelles pour exécuter des instructions à travers un réseau sur d'autres ordinateurs étaient aussi confuses qu'ennuyeuses et sujettes aux erreurs. La meilleure manière d'aborder ce problème est de considérer qu'en fait un objet donné est présent sur une autre machine, on lui envoie un message et l'on obtient le résultat comme si l'objet était instancié sur votre machine locale. Cette simplification est exactement celle que Java 1.1 Remote Method Invocation (RMI - Invocation de méthodes distantes) permet de faire. Cette section vous accompagne à travers les étapes nécessaires pour créer vos propres objets RMI.
RMI utilise beaucoup d'interfaces. Lorsque l'on souhaite créer un objet distant, l'implémentation sous-jacente est masquée en passant par une interface. Ainsi, lorsque qu'un client obtient une référence vers un objet distant, ce qu'il possède réellement est une référence intermédiaire, qui renvoie à un bout de code local capable de communiquer à travers le réseau. Mais nul besoin de se soucier de cela, il suffit de juste d'envoyer des messages par le biais de cette référence intermédiaire.
La création d'une interface distante doit respecter ces directives :
Voici une interface distante simple qui représente un service d'heure exacte :
Cela ressemble à n'importe quelle autre interface mis à part qu'elle hérite de Remote et que toutes ses méthodes émettent RemoteException. Rappelez vous qu'une interface et toutes ses méthodes sont automatiquement publiques.
Le serveur doit contenir une classe qui hérite de UnicastRemoteObject et qui implémente l'interface distante. Cette classe peut avoir aussi des méthodes supplémentaires, mais bien sûr seules les méthodes appartenant à l'interface distante seront disponibles pour le client puisque celui-ci n'obtiendra qu'une référence vers l'interface, et non vers la classe qui l'implémente.
Vous devez explicitement définir le constructeur de cet objet distant même si vous définissez seulement un constructeur par défaut qui appelle le constructeur de base. Vous devez l'écrire parce qu'il doit émettre RemoteException.
Voici l'implémentation de l'interface distante PerfectTimeI:
Ici, main( ) se charge de tous les détails de mise en place du serveur. Une application qui met en service des objets RMI doit à un moment :
Ici, vous pouvez voir un appel à la méthode statique Naming.bind( ). Toutefois, cet appel nécessite que le registre fonctionne dans un autre processus de l'ordinateur. Le nom du registre serveur est rmiregistry, et sous Windows 32-bit vous utiliserez :
pour démarrer celui-ci en fond. Sous Unix, ce sera :
Comme beaucoup d'applications réseau, le rmiregistry est localisé à l'adresse IP de la machine qui l'a démarré, mais il doit aussi écouter un port. Si vous invoquez le rmiregistry comme ci-dessus, sans argument, le port écouté par le registre sera par défaut 1099. Si vous souhaitez que ce soit un autre port, vous devez ajouter un argument à la ligne de commande pour le préciser. Dans cet exemple, le port sera 2005, ainsi le rmiregistry devra être démarré de cette manière sous Windows 32-bit :
ou pour Unix:
L'information concernant le port doit aussi être fourni à la commande bind( ), ainsi que l'adresse IP de la machine où se trouve le registre. Mais il faut mentionner que cela peut être un problème frustrant en cas de tests de programmes RMI en local (de la même manière que les programmes réseau testés plus loin dans ce chapitre). En effet dans le JDK version 1.1.1, il y a quelques problèmes : [69]
En ayant tout cela à l'esprit, la commande bind( ) devient :
Si vous utilisez le port par défaut 1099, nul besoin de préciser le port, donc vous pouvez dire :
Vous devriez être capable de réaliser un test local en omettant l'adresse IP et en utilisant simplement l'identifiant :
Le nom pour le service est arbitraire ; il se trouve que c'est PerfectTime ici, comme le nom de la classe, mais un tout autre nom conviendrait. L'important est que ce nom soit unique dans le registre, connu par le client pour qu'il puisse se procurer l'objet distant. Si le nom est déjà utilisé dans le registre, celui renvoie une AlreadyBoundException. Pour éviter cela, il faut passer à chaque fois par un appel à rebind( ) à la place de bind( ), en effet rebind( ) soit ajoute une nouvelle entrée, soit remplace celle existant déjà.
Durant l'exécution de main( ), l'objet a été créé et enregistré, il reste ainsi en activité dans le registre, attendant qu'un client arrive et fasse appel à lui. Tant que rmiregistry fonctionne et que Naming.unbind( ) n'est pas appelé avec le nom choisi, l'objet sera présent. C'est pour cela que lors de la conception du code, il faut redémarrer rmiregistry après chaque compilation d'une nouvelle version de l'objet distant.
rmiregistry n'est pas forcément démarré en tant que processus externe. S'il est sûr que l'application est la seule qui utilise le registre, celui peut être mis en fonction à l'intérieur même du programme grâce à cette ligne :
Comme auparavant, nous utilisons le numéro de port 2005 dans cet exemple. C'est équivalent au fait de lancer rmiregistry 2005 depuis la ligne de commande, mais c'est souvent plus pratique lorsque l'on développez son code RMI puisque cela élimine les étapes supplémentaires qui consistent à arrêter et redémarrer le registre. Une fois cette instruction exécutée, la méthode bind( ) de la classe Naming peut être utilisée comme précédemment.