Accès rapide : Le modèle de page web NWS Mise en oeuvre d'un WAR (Web ARchive) La classe de page associée Déploiement de l'application sur le serveur Premiers tests
Le framework NWS va vous permettre de mettre un oeuvre une application Web. Cette application sera constituée d'un ensemble de pages web. Chaque page web sera découpée en deux parties bien distinctes :
Cette approche permet de bien séparer l'affichage du code à proprement parler. Comme nous allons le voir, le framework NWS met l'accent sur une programmation événementielle. Ainsi, les gestionnaires d'événements seront localisés dans la classe de page. Les techniques de liaisons aux données permettront quand à elle de garantir que la page web ne contiendra aucune ligne de code.
CONTRAIREMENT A JSP, NWS NE PERMET PAS D'INJECTER DU CODE DIRECTEMENT DANS LA PAGE WEB, VIA UNE SEQUENCE <%= %> OU EQUIVALENT.
C'est la page web qui sera mise en relation avec la classe de page, néanmoins il ne s'agira pas d'un lien d'héritage. La page web est un document XML, elle est chargée par l'intermédiaire d'un DOM (Document Object Model). Elle ne servira pas à produire une classe de code Java qui aurait pu hériter de je ne sais quoi. Certains pourront insister sur le fait que de ne pas compiler la page web induit des performances moins intéressantes, néanmoins cela confère d'autres possibilités en termes de génération de tags en dynamique. Nous y reviendrons ultérieurement.
NWS s'appuie sur un moteur de servlets. En tant que tel, il peut être déployé sur n'importe quel serveur d'applications J2EE (JBoss, ...). Il est donc nécessaire que votre application respecte la notion de WAR (Web ARchive) définie dans J2EE (Java 2 Enterprise Edition).
Un WAR est une archive Java qui contient un ensemble de répertoires et des fichiers bien précis. Basons nous sur l'application de démonstration VirtualCaddy. Le diagramme présenté ci-contre montre la structure de répertoires utilisée par cette application.
Les pages web NWS (reconnaissables à l'extension .wp) doivent être placées directement dans le répertoire VirtualCaddy. Si votre application utilise des images, il vous est, pourquoi pas, possible de les placer dans un sous répertoire Images, mais cela n'est pas une obligation. Vous auriez pu placer vos images au même niveau que les pages web.
Le répertoire WEB-INF est très important. Il doit être obligatoirement orthographié en majuscules. Il contient l'ensemble des classes Java compilées (qu'elles soient archivées ou non). Les librairies Java devront être localisées dans le sous répertoire lib : il ne sera pas nécessaire de forcer la variable d'environnement CLASSPATH, car tout jar (Java ARchive) placé dans ce répertoire est implicitement accessible. Les fichiers .class, non archivés, devront quant à eux être placés dans le sous répertoire classes. Il n'est pas obligatoire de déployer les codes sources de l'application dans le WAR, pour qu'il fonctionne ! Néanmoins, je vous les fournis à titre pédagogique.
Le répertoire WEB-INF contient aussi un fichier de configuration de votre application Web : le fameux web.xml. Ce fichier est aussi appelé "descripteur de déploiement" (Deployment descriptor). L'utilisation d'un descripteur de déploiement XML est, elle aussi, imposée par le standard J2EE. Voici un exemple de contenu pour le fichier VirtualCaddy/WEB-INF/web.xml.
01 <?xml version="1.0" encoding="UTF-8"?> 02 <!DOCTYPE web-app PUBLIC 03 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" 04 "http://java.sun.com/dtd/web-app_2_3.dtd"> 05 06 07 <web-app> 08 09 <display-name>Virtual Caddy - NWS Sample</display-name> 10 <description>NWS Sample</description> 11 12 <context-param> 13 <param-name>TRACE_ENABLED</param-name> 14 <param-value>true</param-value> 15 </context-param> 16 <context-param> 17 <param-name>TRACE_LOCALHOST_ONLY</param-name> 18 <param-value>true</param-value> 19 </context-param> 20 <context-param> 21 <param-name>TRACE_URI</param-name> 22 <param-value>Trace.wp</param-value> 23 </context-param> 24 25 26 <servlet> 27 <servlet-name>NWS Servlet</servlet-name> 28 <servlet-class>corelib.services.web.server.ControllerServlet</servlet-class> 29 </servlet> 30 31 <servlet-mapping> 32 <servlet-name>NWS Servlet</servlet-name> 33 <url-pattern>*.wp</url-pattern> 34 </servlet-mapping> 35 36 </web-app>
Quelques explications ! On peut dire que ce fichier est constitué de trois parties bien distinctes. La première partie donne quelques informations générales sur l'application Web (son nom, ainsi qu'une description).
La seconde partie permet de configurer le module de traces intégré à NWS. Le module de traces est un outil de debug très performant permettant de consigner tous les détails des requêtes (sessions, paramètres, ...) émises au serveur. Ce module peut être activé ou non. C'est ce qu'indique le paramètre TRACE_ENABLED. Le troisième paramètre indique la terminaison de l'URL à invoquer pour obtenir l'historique des traces. Il vous faudra donc entrer l'url http://localhost:8080/VirtualCaddy/Trace.wp dans votre navigateur pour obtenir cet historique. La capture d'écran suivante montre un exemple de l'historique des traces obtenues.
Enfin, la troisième partie permet de mettre en place la servlet (un composant Web) qui répondra à toutes les requêtes se terminant par .wp. Cette servlet est proposée par le framework NWS. Notez bien que la classe de la servlet est mise en correspondance avec l'url-pattern par l'intermédiaire d'un nom : il doit bien entendu être le même dans les deux blocs (servlet et servlet-mapping).
En résumé, pour transformer un WAR en une application Web NWS, il faut donc déplacer le fichier nws.jar dans le répertoire WEB-INF/lib/. De plus il est nécessaire d'éditer le fichier web.xml convenablement, afin de monter en mémoire la servlet qui devra répondre aux requêtes des pages Web NWS.
Nous allons maintenant nous intéresser au codage d'une page Web à proprement parler. Pour ce faire il vous faut, nous l'avons vu plus haut dans ce document, éditer deux fichiers. Une classe de code Java et la page Web à proprement parler. Ce sont ces deux fichiers qui permettront à la page de correctement répondre aux requêtes HTTP. Nous allons comment commencer par étudier le contenu de la page NWS. Voici un petit exemple de page NWS.
01 <?xml version="1.0" encoding="ISO-8859-1" ?> 02 <web:Html xmlns:web="corelib.services.web.components" 03 codeBehind="corelib.services.web.samples.virtualcaddy.webpages.Login"> 04 <head> 05 <title>Logon screen</title> 06 <link rel="stylesheet" type="text/css" href="CssStyles.css" /> 07 </head> 08 <body> 09 <h1>Logon screen</h1> <br /> 10 11 <web:Form focus="txtLogin" method="post"> 12 <div align="center"> 13 Login : <web:TextBox id="txtLogin" value="Malone" /> 14 <web:RequiredValidator componentToValidate="txtLogin" 15 errorMessage="Value is required" cssClass="Validator" /> 16 <br/> 17 18 Password : 19 <web:TextBox id="txtPassword" value="P@ssw0rd" type="password" /> 20 <web:RequiredValidator componentToValidate="txtPassword" 21 errorMessage="Value is required" cssClass="Validator" /> 22 <br /> <br/> 23 24 <web:Button id="btnConnect" value="Connect" /> <br /> 25 <web:OutputText id="lblResult" /> <hr /> 26 27 <div id="divTime" runAt="server"></div> 28 </div> 29 </web:Form> 30 </body> 31 </web:Html>
Comme vous pouvez le voir, nous sommes face à un fichier XML qui contient néanmoins un ensemble de tags HTML pour définir la structure de la page. Mais si vous y regardez de plus près, il y a aussi d'autres tags.
Ces tags permettent de créer des composants NWS côté serveur, qui après le traitement de la page, généreront du HTML. Cette approche permettra de créer des composants Web réutilisables, qui supporteront notamment des événements ainsi qu'un modèle de liaison de données (nous y reviendrons ultérieurement). Néanmoins il faut que le framework NWS puisse faire le lien entre la classe Java du composant et le tag équivalant dans la page Web. Pour ce faire, deux techniques sont envisageables.
TECHNIQUE 1 : vous utilisez le concept de namespace XML pour y stocker le package contenant la classe considérée. Le tag <corelib.services.web.components:Button /> permettra ainsi d'instancier un composant de type corelib.services.web.components.Button.
TECHNIQUE 2 : c'est celle montrée dans l'exemple de page web précédent. Le langage XML permet de définir des alias sur les namespaces utilisés. Cela se fait traditionnellement sur le tag racine de votre document XML via la construction xmlns:alias="URI". Le framework NWS réutilise cette technique pour y définir des alias sur les packages utilisés. Ainsi, si l'on considère la page Web précédente, le tag <web:TextBox id="txtLogin" value="Malone" /> est basé sur l'alias web qui est mis en association (sur le tag <web:Html>) avec le package corelib.services.web.components. Bien entendu, ce package devra fournir une classe TextBox.
Quelque soit la technique utilisée, vous n'avez pas le choix sur le nom du tag. Si vous souhaitez créer un object de type Button, la partie suivant le caractère : devra obligatoirement être Button. Ensuite notez qu'une classe expose des propriétés : des méthodes d'accès aux attributs de la classe. En Java les accesseurs aux attributs respectent le modèle JavaBeans. NWS respecte ce standard. Ainsi, <web:Button value="Hello" /> permettra de créer en mémoire, au niveau du serveur Web, un objet de type corelib.services.web.components.Button sur lequel la méthode setValue sera invoquée pour mémoriser la valeur "Hello".
Contrairement à la mise en oeuvre d'une simple page Web, le framework NWS est très stricte. Si un composant Web NWS ne correspond pas très exactement à une classe ou si un des attributs du tag ne correspond pas à une des propriétés de la classe considérée, une erreur vous sera retournée.
Dans l'absolue, une page Web NWS n'est pas obligée d'être associée à une classe de page NWS. Si vous ne souhaitez pas lui associér de code, vous devez utiliser l'attribut codeBehind="corelib.services.web.server.WebPage" sur le tag <web:Html>. ATTENTION tout de même : si vous n'utilisez pas de classe de page, vous serez dans l'incapacité de définir des gestionnaires d'événements sur vos composants Web NWS !
Si au contraire vous souhaitez fournir une classe de page, commencez en premier lieu par la coder. Une page NWS possède un cycle de vie bien particulier induit par le fonctionnement interne du framework. Nous reviendrons ultérieurement sur les détails du cycle de vie d'une page NWS. Néanmoins, pour réagir aux différentes étapes de ce cycle de vie, vous devez redéfinir certaines méthodes. Ces méthodes sont en fait définies sur la classe corelib.services.web.server.WebPage : votre classe Java doit donc hériter de WebPage et redéfinir certaines méthodes clés. Voici un exemple de classe de page NWS.
01 package corelib.services.web.samples.virtualcaddy.webpages; 02 03 import corelib.services.web.components.Button; 04 import corelib.services.web.components.OutputText; 05 import corelib.services.web.components.TextBox; 06 import corelib.services.web.components.events.ActionEvent; 07 import corelib.services.web.components.events.ActionListener; 08 import corelib.services.web.samples.virtualcaddy.business.UserHome; 09 import corelib.services.web.server.WebPage; 10 import corelib.services.web.server.events.WebPageEvent; 11 12 public class Login extends WebPage { 13 14 private TextBox txtLogin = null; 15 private TextBox txtPassword = null; 16 private Button btnConnect = null; 17 private OutputText lblResult = null; 18 19 20 public void page_load( WebPageEvent webPageEvent ) { 21 this.traceLogger.info( "Virtual Caddy", "page_load" ); 22 this.btnConnect.addActionListener( new ActionListener() { 23 public void actionPerformed( ActionEvent event ) { 24 btnConnect_actionPerformed( event ); 25 } 26 }); 27 } 28 29 public void btnConnect_actionPerformed( ActionEvent event ) { 30 String login = txtLogin.getValue(); 31 String password = txtPassword.getValue(); 32 33 if ( UserHome.findByConnectInformations( login, password ) != null ) { 35 this.redirect( "SelectArticle.wp" ); 39 } else { 40 lblResult.setText( "Bad connection for user : " + login ); 41 this.traceLogger.warning( "Virtual Caddy", "Bad connection" ); 42 this.traceLogger.error( "Virtual Caddy", "Bad connection" ); 43 } 44 } 45 }
Donc, comme nous l'avons dis, la ligne 12 déclare la classe en la faisant dériver de la classe WebPage. Ensuite, des attributs sont définis : ne cherchons pas à les instancier (ne placez pas de new), cela ne servirait à rien, car le framework NWS le fera automatiquement. Notez néanmoins que les noms de ces attributs ainsi que leurs types doivent correspondre très exactement à ce qui est déclaré dans la page Web associée. Les données qui seront saisies (sur le navigateur), par le bais de ces composants, seront transférées dans la requête HTTP, récupérées par le framework NWS et stockées dans les instances de composants Web dont nous sommes en train de parler. Contrairement à certains framework de développement Web (servlet et JSP notamment), il n'est pas nécessaire d'extraire les données de la requête HTTP : cela est fait automatiquement.
Parmi ces quatre attributs, nous trouvons notamment deux zones de saisie de texte (ligne 14 et 15), un bouton de soumission du formulaire et un label permettant, lors de la réponse du serveur (vers le navigateur), de renvoyer un message suite à une mauvaise soumission du formulaire. Notez bien que ces trois types de composants NWS font parti du package corelib.services.web.components.
Ensuite, en ligne 20, nous avons la méthode page_load : elle a été redéfinie et fait partie du cycle de vie d'une page NWS. Elle sera appelée par le framework dès lors que la page sera entièrement construite au niveau du serveur Web, mais avant le renvoie de la réponse HTML. Cette méthode réalise deux choses : en ligne 21, une trace est ajoutée (vous pourrez la visualiser en demandant l'affichage des traces - http://localhost:8080/VirtualCaddy/Trace.wp) et en ligne 22 un gestionnaire de clique sur le bouton est ajouté.
Attention, nous parlons ici d'un gestionnaire d'événement de type serveur. Si le lecteur clique sur le bouton du formulaire (dans le navigateur utilisé), les données saisies dans le formulaire sont envoyées au serveur, et la méthode btnConnect_actionPerformed sera alors invoquée. Notez que la gestion des événements suit la technique préconisée (toujours par le modèle JavaBeans) par Java : les fameux listeners (ou écouteurs en français).
Enfin, à partir de la ligne 29, nous trouvons le code de notre gestionnaire d'événement côté serveur. Celui ci récupère les données saisies pour le login et le mot de passe (ligne 30 et 31) et vérifie si la connexion de cet utilisateur est autorisée ou non. Voici un couple login/password valide : Login=Malone et Password=P@ssw0rd (ce sont de plus les valeurs saisies par défaut dans le formulaire). Les plus curieux d'entre vous peuvent aller voir le code de la classe UserHome : celle-ci se propose de simuler une base de données contenant une table d'utilisateurs autorisés à se connecter à notre application de démonstration.
Comme nous l'avons déjà vu dans le chapitre précédent, pour déployer votre application dans un serveur Tomcat, il suffit d'y copier votre WAR dans le répertoire webapps. Néanmoins, cette étape peut être réalisée manuellement ou bien être automatisée par le biais d'un script ANT.
Si Tomcat n'était pas déjà démarré, prenez soin de le faire maintenant. Lancez aussi un navigateur Internet, et saisissez-y dans la barre d'adresse l'URL suivante : http://localhost:8080/VirtualCaddy/Logon.wp.
Si tout se passe bien, un écran d'authentification devrait apparaître. Testez cet écran avec une identité quelconque, puis testez ensuite le login et le password attendu et vous devriez ainsi passer à l'écran suivant. Ensuite, vous pouvez aussi essayer d'afficher les traces en utilisant l'adresse suivante : http://localhost:8080/VirtualCaddy/Trace.wp. Vous devriez retrouver dans les rapport de traces, les informations qui y ont étaient consignées durant les essais d'authentification.
Dominique LIARD - © 2007 SARL Infini Software - Tous droits réservés Les autres marques et les noms de produits cités dans ces documents sont la propriété de leurs détenteurs respectifs.