Projet ECOM – Documentation de la couche présentation J2EE (Servlets)

M2PGI & RICM 3
Année 2006-2007

Responsables : Fabienne Boyer & Didier Donsez

Editeur : D. Donsez

Références J2EE :

-    Lien vers le cours HTTP

-    Lien vers le cours Servlet

 -    J2EE main page

-         Tutorial Java/J2EE

-         API Sun/EJB2.0

1       Programmation de la partie présentation d’une application J2EE  à base de servlets

Les servlets correspondent à la partie présentation d’une application conçus sur le modèle J2EE. Les servlets sont des « scripts » exécutés par le serveur pour traiter la requête d’un navigateur et lui retourner un document dans un langage de présentation supporté par le navigateur. Par exemple, HTML4.x+CSS+JavaScript, CHTML, WML, XML+XSLT, PDF, GIF, JPEG, SVG, …

Petite remarque avant de commencer :

La programmation des servlets diffèrent de ceux des JSP, ASP, PHP, … car leur code est une classe Java dans laquelle le développeur écrit des lignes de code out.println(" … "); pour retourner le « texte » du document retourné. Dans l’approche SSS (Server Side Script) comme ASP, JSP et PHP, les scripts sont nichés au milieu de code HTML. Cette dernière approche à l’avantage de pouvoir utiliser les outils auteurs (authoring tools) comme Visual Studio, DreamWeaver, … Mais cette approche possède un très gros inconvénient puis qu’elle mêle deux métiers complémentaires mais diffèrents ! En effet, l’auteur du document « SSSiser » doit être à la fois Web Designer (i.e. Infographiste) et Développeur (connaissant bien les bases de données, les transactions, les EJB, la sécurité, …).

La suite de cette section ‎0 présente la notion d’application Web, les packages Java pour la programmation des servlets, le cycle de vie d’une servlet, l’accès aux ressources, le suivi de session et enfin le déploiement d’une application Web.

1.1   Notion d’application Web

Une application Web est un ensemble de scripts serveur (Servlet, Filter, JSP, TagLib, …) et des documents (hypertextuels, XML, XSLT, images, vectoriel animée, …) reliés par des relations d’inclusion, de référencement, …

En clair, une application se conçoit de manière modulaire et donc il est nécessaire de réfléchir à la structure globale de celle-çi avant de se mettre à programmer des bouts (les servlets !).

1.2   Les packages javax.servlet et javax.servlet.http

La programmation des servlets se fait au moyen des classes et des interfaces (listés dans le schéma ci dessous) qui se trouvent dans les 2 packages javax.servlet et javax.servlet.http.

Le package javax.servlet est conçu pour fournir des scripts serveur indépendant d’un protocole. Cependant le seul protocole supporté actuellement est HTTP et le package sert à programmer de scripts invoqués au moyen d’HTTP !

Packages javax.servlet et javax.servlet.http

1.3   Cycle de vie d’une servlet

Une servlet est un objet instancié (d’une classe dérivant de javax.servlet.http.HttpServlet) une seule fois. Cependant vous pouvez déployez plusieurs servlets à partir de la même classe Java! Attention aux méthodes et membres statiques de la classe, ils sont partagées entre les instances (quand elles appartiennent à la même application Web donc le même ClassLoader (voir %JONAS_ROOT%\doc\ClassLoader.html).

Une fois instantié, cet objet est « initialisé » lors la première requête (méthode init(…)).

Cet objet est ensuite concurremment accédé par les threads que le serveur démarre pour traiter les requêtes issues des navigateurs (méthode service(…)) ! Il peut être donc nécessaire de contrôler l’accès à des sections critiques du code qui accéder aux membres de l’objet (i.e. synchronized(this){ … })

1.3.1    Initialisation

L’initialisation se fait au moyen de la méthode void init(ServletConfig config)

Le développeur y place généralement l’initialisation des membres de l’objet (ou les statiques de la classe ) et utilise généralement les paramètres d’initialisation de la servlet et/ou ceux du contexte.

 les paramètres d’initialisation de la servlet sont dans les éléments init-param (dans le fichier de déploiement de l’application WEB-INF\web.xml voir ‎5.5) et sont récupérés au moyen des 2 méthodes de Servlet : Enumeration getInitParameterNames(); et String getInitParameter(String paramName);

les paramètres d’initialisation du contexte de l’application sont dans les éléments context-param (dans le fichier de déploiement de l’application WEB-INF\web.xml voir ‎5.5) et sont récupérés au moyen des 2 méthodes de ServletContext : Enumeration getInitParameterNames(); et String getInitParameter(String paramName);

Exemple:

  out.println("Servlet init parameters:");

  Enumeration e = getInitParameterNames();

  while (e.hasMoreElements()) {

      String key = (String)e.nextElement();

      String value = getInitParameter(key);

      out.println("   " + key + " = " + value);

  }

  out.println("Context init parameters:");

  ServletContext context = getServletContext();

  Enumeration enum = context.getInitParameterNames();

  while (enum.hasMoreElements()) {

      String key = (String)enum.nextElement();

            Object value = context.getInitParameter(key);

            out.println("   " + key + " = " + value);

  }

Exemple d’extrait du fichier web.xml:

  <servlet>

    <servlet-name>CustomerServlet</servlet-name>

    <servlet-class>ecom.servlets.CustomerServlet</servlet-class>

    <init-param>

      <param-name>language</param-name>

      <param-value>en</param-value>

    </init-param>

    <init-param>

      <param-name>currency</param-name>

      <param-value>EUR</param-value>

    </init-param>

  </servlet>

  <context-param>

      <param-name>language</param-name>

      <param-value>fr</param-value>

      <description>Parametre du contexte</description>

    </init-param>

  </context-param>

1.3.2    Traitement d’une requête

Le traitement d’une requête se fait au moyen de la méthode void service(ServletRequest req, ServletResponse res). Cependant la méthode service(…) implémentée par javax.servlet.http.HttpServlet appelle les méthode suivantes doGet(…), doPost(…), doPut(…), doDelete(…) …en fonction du type de la requête HTTP (GET, POST, PUT, DELETE, …)

Pour les deux plus courantes doGet(…) et doPost(…) (celles dont vous vous servirez), le traitement comporte généralement 3 phases :

1)      récupération des paramètres de la requête

2)      invocation de la logique applicative (par exemple, invoquer une ou plusieurs méthodes de Session Beans

3)      formatage d’un document de retour (de préférence dans un format supporté par le navigateur à l’origine de la requête)

1.3.2.1     Récupération des paramètres de la requête

Les paramètres d’une requête HTTP sont encodés au format x-www-form-urlencoded

 et passés  soit dans l’URI d’une requête de type GET soit dans le corps  d’une requête de type POST.

Pour la servlet, les paramètres se récupèrent décodées au moyen des 3 méthodes de ServletRequest :

·         Enumeration getParameterNames(); qui retourne une énumeration des noms (key) de paramètres récupérés

·         String[] getParameterValues(String key); qui retourne un tableau des valeurs d’un paramètre (en effet en HTML, dans le cas des <input type="checkbox" name="menu" value= "dessert"><input type="checkbox" name="menu" value= "fromage"> peuvent retourner des valeurs multiples)

·         String getParameterValue(String key); qui retourne la première valeur d’un paramètre

Exemple :

        out.println("Parameter names in this request:");

        e = request.getParameterNames();

        while (e.hasMoreElements()) {

            String key = (String)e.nextElement();

            String[] values = request.getParameterValues(key);

            out.print("   " + key + " = ");

            for(int i = 0; i < values.length; i++) {

                out.print(values[i] + " ");

            }

            out.println();

        }

Il est possible de récupérer d’autres informations concernant la requête (dont les cookies, les champs d’entête, les attributs du contexte de l’application, …) comme le présente l’exemple suivant :

  out.println("Servlet Name: " + getServletName());

  out.println("Protocol: " + request.getProtocol());

  out.println("Scheme: " + request.getScheme());

  out.println("Server Name: " + request.getServerName());

  out.println("Server Port: " + request.getServerPort());

  out.println("Remote Addr: " + request.getRemoteAddr());

  out.println("Remote Host: " + request.getRemoteHost());

  out.println("Character Encoding: " + request.getCharacterEncoding());

  out.println("Content Length: " + request.getContentLength());

  out.println("Content Type: "+ request.getContentType());

  out.println("Locale: "+ request.getLocale());

  out.println("Request Is Secure: " + request.isSecure());

  out.println("Auth Type: " + request.getAuthType());

  out.println("HTTP Method: " + request.getMethod());

  out.println("Remote User: " + request.getRemoteUser());

  out.println("Request URI: " + request.getRequestURI()); // Example: /ecom/store

  out.println("Context Path: " + request.getContextPath()); // Example: /ecom

  out.println("Servlet Path: " + request.getServletPath()); // Example: /store

  out.println("Path Info: " + request.getPathInfo());

  out.println("Path Trans: " + request.getPathTranslated());

       // Example: G:\devtools\jakarta-tomcat-4.0.3\bin\..\webapps\ecom\servlets\CustomerServlet

  out.println("Query String: " + request.getQueryString());

  out.println("Headers in this request:");

  e = request.getHeaderNames();

  while (e.hasMoreElements()) {

    String key = (String)e.nextElement();

    String value = request.getHeader(key); // example: Accept, User-Agent, ...

    out.println("   " + key + ": " + value);

  }

  out.println("Cookies in this request:");

  Cookie[] cookies = request.getCookies();

  if (cookies != null) {

    for (int i = 0; i < cookies.length; i++) {

      Cookie cookie = cookies[i];

      out.println("   " + cookie.getName() + " = "

                        + cookie.getValue());

    }

  }

  out.println("Context attributes:");

  enum = context.getAttributeNames();

  while (enum.hasMoreElements()) {

    String key = (String)enum.nextElement();

    Object value = context.getAttribute(key);

    out.println("   " + key + " = " + value);

  }

1.3.2.2     Invocation de la logique applicative

Une fois que les paramètres récupérés dans des objets, la servlet invoque la logique applicative de l’application qui de préférence est encapsulé dans des Session Beans. La référence sur la maison de ces beans est obtenue classiquement avec le contexte (voir ‎3.2.6).

1.3.2.3     Formatage d’un document de retour

Une fois que le traitement est effectué, il est nécessaire de formater un document à retourner au navigateur. Il est préférable de choisir un format qui est supporté par le navigateur à l’origine de la requête et dans une langue comprise de l’usager de ce navigateur. Rappel : la liste des formats supporté est donnée dans le champs d’entête de la requête Accept et la langue par le champs d’entête Accept-Language.

Le document retourné est typé au moyen de la méthode setContentType(String mimeType), avec des types MIME comme text/html, text/xml, text/plain, text/vnd.wap.wml, … et de récupérer le flux de sortie (java.io.OutputStream ou java.io.PrintWriter)

Exemple

public class Hello extends HttpServlet {

  public void doGet(HttpServletRequest req, HttpServletResponse res)

                               throws ServletException, IOException {

    res.setContentType("text/html");

    PrintWriter out = res.getWriter();

    out.println("<HTML>");

    out.println("<HEAD><TITLE>Hello World</TITLE></HEAD>");

    out.println("<BODY>");

    out.println("<BIG>Hello World</BIG>");

    out.println("</BODY></HTML>");

} }

La réponse suivante permet au navigateur et au serveur de maintenir la connexion ouverte entre eux (KeepAlive) pour d’autres requêtes afin d’améliorer les performances réseaux.

public class KeepAliveHello extends HttpServlet {

  public void doGet(HttpServletRequest req, HttpServletResponse res)

                               throws ServletException, IOException {

    res.setContentType("text/html");

    // Set up a PrintStream built around a special output stream

    ByteArrayOutputStream bytes = new ByteArrayOutputStream(1024);

    PrintWriter out = new PrintWriter(bytes, true);  // true forces flushing

    out.println("<HTML>");

    out.println("<HEAD><TITLE>Hello World</TITLE></HEAD>");

    out.println("<BODY>");

    out.println("<BIG>Hello World</BIG>");

    out.println("</BODY></HTML>");

    res.setContentLength(bytes.size()); // Set the content length

    bytes.writeTo(res.getOutputStream()); // Send the buffer

  } }

Exercice : Amusez vous à benchmarker ces 2 exemples avec Apache JMeter !

En cas d’erreur lors du traitement de la requête (mauvais paramètre, exception, …), il est souhaitable de retourner une réponse d’erreur avec le code d’état correspondant. Il est également souhaitable de journaliser cette erreur pour que l’administrateur de l’application ou du serveur soit informer du problème.

Exemple

public void doGet(HttpServletRequest req, HttpServletResponse res)

                               throws ServletException, IOException {

    ...

    try {//

      ...

    } catch (FileNotFoundException e) {

      // utilise le journal de GenericServlet

      this.log("Could not find file: " + e.getMessage());

      // envoi du code 404

      res.sendError(HttpServletResponse.SC_NOT_FOUND);

    } catch (IOException e) {

      // utilise le journal de ServletContext

      this.getServletContext().log(e, "Problem sending file");

      // envoi du code 500

      res.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,e.toString());

    }

}

Il est également possible d’ajouter des champs d’entête de la réponse au moyen de la méthode setHeader(…).

Exemple d’usage pour la redirection de document :

public class ClientPull extends HttpServlet {

  public void doGet(HttpServletRequest req, HttpServletResponse res)

                               throws ServletException, IOException {

    res.setContentType("text/plain");

    PrintWriter out = res.getWriter();

    res.setHeader("Refresh", "10");

    out.println(new Date().toString());

  }

}

public class ClientPullMove extends HttpServlet {

  static final String NEW_HOST = "http://www.ecom.com";

  public void doGet(HttpServletRequest req, HttpServletResponse res)

                               throws ServletException, IOException {

    res.setContentType("text/html");

    PrintWriter out = res.getWriter();

    String newLocation = NEW_HOST + req.getRequestURI();

    res.setHeader("Refresh", "10; URL=" + newLocation);

    out.println("The requested URI has been moved to a different host.<BR>");

    out.println("Its new location is " + newLocation + "<BR>");

    out.println("Your browser will take you there in 10 seconds.");

  }

}

Il est également possible d’ajouter un cookie à l’entête de la réponse afin que le navigateur le stocke et le retourne lors d’une prochaine requête (méthode void HttpServletResponse.addCookie(Cookie cookie))

Remarque : quand les URL insérées dans le document comporte des caractères spéciaux (+, &, <space>, é, à, …), il est nécessaire d’encoder celles ci avec la  méthode static String java.net.URLEncoder.encode(String str).

1.3.3    Accès aux ressources

La servlet peut récupérer via le contexte JNDI les variables d’environnements globales à l’application. Ces variables sont initialisées au moyen d’éléments env-entry du fichier web.xml

Exemple

  <env-entry>

    <env-entry-name>defaultCurrency</env-entry-name>

    <env-entry-value>EUR</env-entry-value>

    <env-entry-type>java.lang.String</env-entry-type>

  </env-entry>

  <env-entry>

    <env-entry-name>defaultLanguage</env-entry-name>

    <env-entry-value>33</env-entry-value>

    <env-entry-type>java.lang.Integer</env-entry-type>

  </env-entry>

Exemple

Context ctx = new InitialContext();

Object value = ctx.lookup("java:/comp/env/defaultCurrency");

out.println("Default currency value : " + value);

Context envCtx = (Context) ctx.lookup("java:/comp/env/");

NamingEnumeration enum = ctx.list("java:/comp/env/");

while (enum.hasMoreElements()) {

                out.print("Binding : "+ (enum.nextElement().toString());

}

NamingEnumeration enumbinding = envCtx.listBindings("java:/comp/env/");

while (enumbinding.hasMoreElements()) {

                out.print("Binding : "+( enumbinding.nextElement().toString());

}

La servlet peut récupérer via le contexte JNDI les références vers les Home (local ou remote) des Enterprise JavaBeans de l’application. Ces références sont décrites au moyen d’éléments ejb-local-ref ou ejb-remote-ref du fichier web.xml

Exemple :

    <!-- Remote EJB Reference -->

  <ejb-ref>

    <ejb-ref-name>ejb/Cart</ejb-ref-name>

    <ejb-ref-type>Session</ejb-ref-type>

    <home>ecom.beans.CartHome</home>

    <remote>ecom.beans.Cart</remote>

    <ejb-link>ecom.jar#Cart</ejb-link>

  </ejb-ref>

    <!-- Local EJB Reference -->

  <ejb-local-ref>

    <ejb-ref-name>ejb/CartLocal</ejb-ref-name>

    <ejb-ref-type>Session</ejb-ref-type>

    <local-home>ecom.beans.CartLocalHome</local-home>

    <local>ecom.beans.CartLocal</local>

    <ejb-link>ecom.jar#Cart</ejb-link>

  </ejb-local-ref>

Exemple

        Context ctx = new InitialContext

       // We want to start transactions from client: get UserTransaction

        UserTransaction utx

            = (UserTransaction) initialContext.lookup("java:comp/UserTransaction");

        // Connecting to CartLocalHome thru JNDI

        CartLocalHome cartLocalHome = ctx.lookup("java:comp/env/ejb/CartLocal");

        CartLocal cartLocal = cartLocalHome.create("Cart123456789");

La servlet peut récupérer via le contexte JNDI les références d’autres ressources de l’application (EIS, Mail, …). Ces références sont décrites au moyen d’éléments resource-ref du fichier web.xml.

Exemple

    <resource-ref>

      <res-ref-name>mail/MailSession</res-ref-name>

      <res-type>javax.mail.Session</res-type>

      <res-auth>Container</res-auth>

    </resource-ref>

Exemple

Context ctx = new InitialContext();

javax.mail.Session session = (javax.mail.Session) ictx.lookup("java:comp/env/mail/MailSession");

javax.mail.Message message = new javax.mail.MimeMessage(session);

1.4   Suivi de Session

HTTP est un protocole sans session (sessionless), ne maintenant pas un état particulier associé à un usager particulier !

Or beaucoup d’applications sur le Web requièrent un suivi de session avec l’usager notamment les applications de commerce électronique (comme ECOM) qui par exemple ont besoin de se rappeler des produits achetés au cours de la navigation.

Pour cela, il vous faut utiliser une classe javax.servlet.http.HttpSession qui permet le suivi de session. On récupère la session courante de l’usager ou on ouvre une nouvelle session au moyen de la méthode getSession(boolean create)

javax.servlet.http.HttpSession session = req.getSession(false);

  // la session est récupérée ou null si elle n ’existait pas déjà

javax.servlet.http.HttpSession session = req.getSession(true);

  // la session est récupérée ou ouverte si elle n ’existait pas déjà

Les informations disponibles sur la session sont :

·         L ’identifiant

String sessionid= session.getId(); // par exemple: To1010mC8601021835741167At

·         La date de création

long datecreation= session.getCreationTime(); // nb de ms depuis 1/1/1970:00:00

·         La date du dernier accès

long datelastaccess= session.getLastAccessedTime();

·         Le nombre de seconde maximum d’inactivité de la session avant abandon

long nbsec= session.getMaxInactiveInterval();

Généralement la servlet lie à la session un certain nombre d’attributs (objet) qui sont récupérés lors d’une prochaine requête du navigateur (de cette servlet ou d’une autre). Chaque attribut est identifié au moyen d’une clé.

Les méthodes suivantes sont utilisées pour

L’ajout ou le remplacement d’un objet

·    void HttpSession.setAttribute(String key, Object attribute)

La suppression d ’un attribut

·    void HttpSession.removeAttribute(String name)

La récupération de noms d’attributs

·    Enumeration HttpSession.getAttributeNames()

La récupération d’un attribut

·    Object HttpSession.getAttribute(String key)

Exemple :

        HttpSession session = request.getSession();

        out.println("Session values: ");

        Enumeration names = session.getAttributeNames();

        while (names.hasMoreElements()) {

            String name = (String) names.nextElement();

            out.println("   " + name + " = " + session.getAttribute(name));

        }

Exemple de liaison d ’objets

import ecom.beans.cart.* ;

...

public void doGet(HttpServletRequest req, HttpServletResponse res) … {

  Cart cart;

  HttpSession session = req.getSession(true);

  if((cart=(Cart)session.getAttribute("MYCART"))!=null) {

    cart=cartHome.create();

    session.setAttribute("MYCART",cart);

  }

  ...

  cart.add(product,2);

}

...

A tout moment, la session peut être invalidée au moyen de la méthode invalidate()

javax.servlet.http.HttpSession session = req.getSession(true);

// invalide la session si la requête précédente est vieille de plus de 5 minutes

if(session.getLastAccessedTime() - session.getCreationTime() > 5*60*1000 ) {

  session.invalidate();  // la session est invalidée (i.e. fermée)

}

L’invalidation de la session est provoqué le plus souvent par le serveur car il ne peut maintenir une quantité infinie d’objets liés à une session. La durée maximum entre 2 requêtes avant invalidation de la session est fixée avec l’élément session-config du fichier web.xml.

Pour cela, il est nécessaire de déclarer des observateurs de liaison qui sont notifiés des ajouts ou retraits d’attributs d’une session. Un observateur est généralement utilisé pour libérer des ressources critiques (fermer des fichiers, des connexions, valider des transactions, ...). L’observateur est l’objet lié qui doit implémenter l’interface HttpSessionBindingListener

interface HttpSessionBindingListener {

  public void valueBound(HttpSessionBindingEvent event) ;

     // invoqué quand l ’objet est lié (putValue())

  public void valueUnbound(HttpSessionBindingEvent event) ;

     // est invoqué quand la session est invalidée ou expire
     // ou quand l ’objet est délié (putValue()/removeValue()).

}

class HttpSessionBindingEvent extends EventObject

  public Session getSession() { ... } // la session concernée

  public String getName(){ ... } // le nom de la liaison

}

Exemple d’observateur de liaison

class CartBindingListener implements HttpSessionBindingListener {

  Cart cart=null;

  public CartBindingListener(CartHome cartHome) { this.cart = cartHome.create(); }

  public void valueBound(HttpSessionBindingEvent event) {}

  public void valueUnbound(HttpSessionBindingEvent event) { cart.discard();}

}

...

public void doGet(HttpServletRequest req, HttpServletResponse res) {

  CartBindingListener cbl;

  HttpSession session = req.getSession(true);

  CartBindingListener cbl =( CartBindingListener)session.getValue("MYCART");

  if(cbl ==null) {

     cbl=new CartBindingListener ( ... );

     session.setValue("MYCART",cbl); // valueBound est invoqué sur l ’objet lié

   } …

  session.removeValue("MYCART"); // valueUnbound est invoqué sur l ’objet lié

Techniquement, le serveur maintient une session soit au moyen de cookie (le Cookie de nom SESSIONID pour TomCat (cependant les cookies peuvent être déactivés sur le navigateur) soit au moyen des la réécriture des URLs en y glissant l’identifiant de session (cependant la suivi de session est perdu si on traverse une page statique !)

La méthode de suivi de session est connue au moyen des 2 méthodes suivantes

·         boolean HttpServletRequest.isRequestedSessionIdFromCookie() teste si le suivi de session utilise un cookie

·         boolean HttpServletRequest.isRequestedSessionIdFromURL() teste si le suivi de session utilise la réécriture d ’URL

Dans le cas de la réécriture des URL, les URL générées dans le document de réponse doivent être encodées pour intégrer le suivi de session avec les 2 méthodes :

·         String HttpServletResponse.encodeRedirectURL(String url)

·         String HttpServletResponse.encodeURL(String url)

Exemple

  res.sendRedirect(res.encodeRedirectURL("/servlet/login");

1.5   Déploiement

Pour être déployée, une application Web doit être emballée dans un fichier WAR/Web Application Archive (par exemple, ecom.war). L’application est installée en plaçant ce fichier dans le répertoire webapps du serveur web J2EE sous %JONAS_BASE%/webapps (ou %JONAS_ROOT%/webapps).

Ce fichier WAR est une archive Java (fichier Jar) ayant la structure suivante :

-         *.html, *.jsp, … : des documents statiques ou dynamiques

-         WEB-INF/web.xml : des fichiers de déploiement décrivant le paramétrage des servlets, types MIME additionnels, etc.

-         WEB-INF/classes : les classes des servlets

Le fichier de déploiement web.xml comporte les informations nécessaires au nommage des servlets, leur initialisations, la désignation des ressources, …

<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE web-app

    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"

    "http://java.sun.com/j2ee/dtds/web-app_2.2.dtd">

<web-app>

  <servlet>

    <servlet-name> CustomerServlet </servlet-name>

    <servlet-class>ecom.servlets.CustomerServlet</servlet-class>

    <init-param>

      ...

    </init-param>

    ...

  </servlet>

    <servlet-mapping>

        <servlet-name>CustomerServlet</servlet-name>

        <url-pattern>/store</url-pattern>

    </servlet-mapping>

    <servlet-mapping>

        <servlet-name>CustomerServlet</servlet-name>

        <url-pattern>/product</url-pattern>

    </servlet-mapping>

    <servlet-mapping>

        <servlet-name>CustomerServlet</servlet-name>

        <url-pattern>/cart</url-pattern>

    </servlet-mapping>

...

  <session-config>

    <session-timeout>54</session-timeout>

  </session-config>

  <resource-ref>

    <res-ref-name>jdbc/EcomDataSource</res-ref-name>

    <res-type>javax.sql.DataSource</res-type>

    <res-auth>Container</res-auth>

  </resource-ref>

    <mime-mapping>

      <extension>wbmp</extension>

      <mime-type>image/vnd.wap.wbmp</mime-type>

    </mime-mapping>

    <mime-mapping>

      <extension>wml</extension>

      <mime-type>text/vnd.wap.wml</mime-type>

    </mime-mapping>

    <mime-mapping>

      <extension>wmls</extension>

      <mime-type>text/vnd.wap.wmlscript</mime-type>

    </mime-mapping>

    <welcome-file-list>

      <welcome-file>index.jsp</welcome-file>

      <welcome-file>index.wml</welcome-file>

      <welcome-file>index.html</welcome-file>

    </welcome-file-list>

</web-app>

1.6   Filter

Les Filter peuvent être chaînés pour effectuer des pré-traitements sur le contenu d’une requête avant d’invoquer la servlet ou la JSP, ou bien faire des post-traitements sur la réponse qui est retournée par la servlet (ou un autre filtre de la chaîne). Les utilisations possibles sont l’authentification, la conversion/transformation (XSLT, FOP), le chiffrage/compression, l’audit/journalisation, …

Exemple de Filter :

public class TraceFilter implements javax.servlet.Filter {

  private FilterConfig filterConfig = null;

  public void init(FilterConfig filterConfig) throws ServletException {

    this.filterConfig = filterConfig;

  }

  public void destroy() {

    this.filterConfig = null;

  }

  public void doFilter(ServletRequest req,ServletResponse res, FilterChain chain)

            throws IOException, ServletException {

      HttpServletRequest hreq = (HttpServletRequest)req;

      trace(hreq.getServletPath()); // trace only the path

      chain.doFilter(req, res);

  }

  private void trace(String msg){ System.err.println(msg); }

}

Exemple de déploiement de filtre dans le fichier web.xml

     <filter>

       <filter-name>TraceFilter</filter-name>

       <display-name>TraceFilter</display-name>

       <description>trace calls</description>

       <filter-class>ecom.servlets.TraceFilter</filter-class>

       <init-param>

         <param-name>traceContent</param-name>

         <param-value>date,session,uri</param-value>

       </init-param>

       <init-param>

         <param-name>fieldSeparator</param-name>

         <param-value>:</param-value>

       </init-param>

     </filter>

     <filter-mapping>

       <filter-name>TraceFilter</filter-name>

       <!-- trace all requests for (.html, .jsp, Servlets, … -->

       <url-pattern>/*</url-pattern>

     </filter-mapping>

Vous pouvez voir d’autres filtres dans les exemples de Jakarta Tomcat.

1.7   JSP

Les JSP (Java Server Page) sont des SSS (Server Side Script) comme les ASP (Active Server Pages) ou bien les PHP (Personal Home Pages). Ce sont des « scripts » qui sont nichés au milieu du document HTML. Ces scripts forment des parties du document qui sont générées lors de l’invocation.

En réalité, les documents *.jsp sont tous traités par une servlet org.apache.jasper.servlet.JspServlet qui lors de la première invocation d’une JSP transforme son document en une classe Java (héritant de la classe org.apache.jasper.runtime.HttpJspBase) puis invoque sa méthode _jspService(HttpServletRequest request, HttpServletResponse response). Plus de détail, explorez le répertoire work de TomCat !

Exemple de JSP ( http://localhost:8080/ecom/hello.jsp)

<HTML>

<HEAD><TITLE>Hello</TITLE></HEAD>

<BODY>

<H1> Hello

<%

String pname; // déclaration de variable

pname = request.getParameter("name"); // request : objet implicite

if (pname== null) { out.println("World !");

} else {

%>

Mister <%=pname%> !

<% } %>

</H1>

</BODY>

</HTML>

Vous pouvez voir un certain nombre de JSP dans les exemples de Jakarta Tomcat.

2       Déploiement d'une application EJB avec accès Web

Pour être déployée, une application composée d'une partie Web et d'une partie EJB doit être emballée dans un fichier EAR/Enterprise Application Archive, par exemple ecom.ear. L’application est installée en plaçant ce fichier dans le répertoire apps du serveur web J2EE sous %JONAS_BASE%/apps (ou %JONAS_ROOT%/apps).

Ce fichier EAR est une archive Java (fichier Jar) contenant à la fois :

-         La partie ejbjar, correspondant à la mise en œuvre de la partie EJB

-         La partie war, correspondant à la mise en œuvre de la partie servlets

-         Un fichier application.xml, qui décrit la composition des deux parties précédentes.

Pour charger effectivement votre application dans un serveur JOnAS, vous pouvez utiliser la commande jonas admin –a ecom.ear, ou bien utiliser l'outil d'administration fourni par JOnAS. En placeant votre fichier ear dans le sous-répertoire autoload, alors votre application sera automatiquement chargée par JOnAS lors du lancement du serveur.

Les commandes ant ear, et ant install, permettent respectivement de générer votre fichier ear, et d' installer votre application dans les répertoires de JOnAS.