1. Généralités
Des Servlets qui s'exécutent sur un même serveur, dans une même JVM, peuvent communiquer entre elles; les trois procédés de communication les plus utilisées sont:
- Partage d'informations: Une Servlet peut avoir accès au Contexte d' une autre Servlet sur le même serveur et exécuter quelques tâches de cette autre Servlet. Par exemple, une Servlet peut demander à une autre Servlet d'écrire son état sur disque de façon périodique pour parer à un éventuel crash du serveur.
- Le Partage de contrôle: Une Servlet peut se servir des requêtes d'une autre Servlet pour exécuter certaines tâches.
- Autre type de collaboration: Un ensemble de Servlets peuvent communiquer entre elles en utilisant la liste de propriétés (Properties List ) ;
2. Partage d'informations
2.1. La manipulation directe
La manipulation directe des Servlets n'est plus utilisée pour des raisons de sécurité (voir dans un autre cours).
2.2. Utiliser la classe ServletContext pour partager des informations
A chaque application web développée avec des Servlets est associée un contexte; à partir de la version 2.1 de l’API Servlet, ce contexte est représenté par une instance de la classe ServletContext. Dans cette interface sont définies un ensemble de méthodes qui permettent aux servlets au sein d'un conteneur de communiquer; ces méthodes permettent par exemple d'avoir le type de fichier texte retourné comme réponse (MIM Type) par une requête, de distribuer les requêtes ou d'écrire dans un fichier log. Chaque Servlet accède à son contexte par la méthode getServletContext() comme suit:
ServletContext context = getServletContext();
Une "application web" est une collection de Servlets et d'autres fichiers (JSP, java Bean, HTML, ...) installés dans un sous-ensemble des URLs d'un serveur.
Dans le cas d'une "application web" distribuées, on a un seul contexte pour chaque JVM. Dans cette situation, on ne peut pas utiliser la notion de contexte de l'application pour échanger des informations; on se sert alors d' une source externe comme une base de données pour communiquer entre Servlets.
Les éléments d'un contexte se présentent comme des couples (nom, objet) et les accesseurs aux éléments du contexte sont :
public void ServletContext.setAttribute(String name,Object o)
public Object ServletContext.getAttribute(String name)
public Enumeration ServletContext.getAttributeNames() public void ServletContext.removeAttribute(String name)
La méthode setAttribute(String name, Object o) attribue un nom à l'objet indiqué; toute précédente liaison d'un objet avec le nom "name" est remplacée par la nouvelle liaison;
La méthode getAttribute(String name),retrouve l’objet sous le nom indiqué
La méthode removeAttribute(String name), supprime l’objet lié sous le nom indiqué
Pour accéder au contexte d'une application le chemin d'accès doit être absolu.
Marche à suivre :
1. accès au contexte courant: "ServletContext contexteCourant = getServletContext();"
2. accès à un autre contexte : "ServletContext contexteExterieur = getServletContext("/autreAppli/index.jsp");"
3. récupération d’un attribut externe : "String qte = contexteExterieur.getAttribute("quantite");"
3. Illustration
3.1 fichier OrdreDujourAdmin.java
public class OrdreDuJourAdmin extends HttpServlet { protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setContentType("text/plain"); PrintWriter out = res.getWriter(); ServletContext context = this.getServletContext(); context.setAttribute("Presentation", "Bugdet des festivités"); context.setAttribute("Date", new Date()); out.println("Le budget de l'organisation."); } }
(à suivre)
3.2 fichier OrdreDuJourClient.java
public class OrdreDuJourClient extends HttpServlet { protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setContentType("text/plain"); PrintWriter out = res.getWriter(); ServletContext context = this.getServletContext(); String budget_sport = (String)context.getAttribute("Presentation"); Date day = (Date)context.getAttribute("Date"); DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM); String today = df.format(day); out.println("Aujourd'hui (" + today + "), notre présentation est : " + budget_sport); } }
(à suivre)
3.3 Fichier ReadSharedOrdreDuJour.java
public class ReadSharedOrdreDuJour extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
Contextes de l’application
res.setContentType("text/html");
web précédente
PrintWriter out = res.getWriter();
ServletContext my_context = this.getServletContext();
ServletContext ordredujour_context = my_context.getContext("/ServletContext");
String pizza_spec = (String)pizzas_context.getAttribute("Presentation");
Date day = (Date)ordredujour_context.getAttribute("Date");
DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM);
String today = df.format(day);
out.println("Aujourd'hui (" + today + "), notre présentation est : " + budget);
}
}
(à suivre)
3.4 Exemple:
L'exemple ci-dessous utilise ces méthodes pour afficher une information concernant les Servlets chargées. (remarque: ce programme est changé pour ne pas avoir à utiliser les méthodes dépréciées).
import java.io.*; import java.util.*; import javax.servlet.*; import javax.servlet.http.*; public class Loaded extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setContentType("text/plain"); PrintWriter out = res.getWriter(); ServletContext context = getServletContext(); Enumeration names = context.getServletNames(); // on doit getServletNames() remplacer par ..... while (names.hasMoreElements()) { // à corriger car dépend de getServletNames() String name = (String)names.nextElement(); Servlet servlet = context.getServlet(name); // remplacer getServlet(name) out.println("Servlet name: " + name); out.println("Servlet class: " + servlet.getClass().getName()); out.println("Servlet info: " + servlet.getServletInfo()); out.println(); } } }
(à suivre)
3.5 Sauvegarde l'état des Servlets chargées
L'exemple ci-dessous montre une autre utilisation de ces méthodes. Dans cette Servlet, on appelle chaque méthode saveState() de chaque Servlet si cette méthode existe; cette Servlet peut s’exécuter de façon périodique pour parer aux pertes de données si le Serveur se crashe: (remarque: ce programme doit êre changé pour ne pas avoir à utiliser les méthodes dépréciées).
import java.io.*; import java.lang.reflect.*; import java.util.*; import javax.servlet.*; import javax.servlet.http.*; public class SaveState extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setContentType("text/plain"); PrintWriter out = res.getWriter(); ServletContext context = getServletContext(); Enumeration names = context.getServletNames(); //getServletNames() à enlever while (names.hasMoreElements()) { String name = (String)names.nextElement(); Servlet servlet = context.getServlet(name); out.println("Trying to save the state of " + name + "..."); out.flush(); try { Method save = servlet.getClass().getMethod("saveState", null); save.invoke(servlet, null); out.println("Saved!"); } catch (NoSuchMethodException e) { out.println("Not saved. This servlet has no saveState() method."); } catch (SecurityException e) { out.println("Not saved. SecurityException: " + e.getMessage()); } catch (InvocationTargetException e) { out.print("Not saved. The saveState() method threw an exception: "); Throwable t = e.getTargetException(); out.println(t.getClass().getName() + ": " + t.getMessage()); } catch (Exception e) { out.println("Not saved. " + e.getClass().getName() + ": " + e.getMessage()); } out.println(); } } public String getServletInfo() { return "Calls the saveState() method (if it exists) for all the " + "currently loaded servlets"; } }