Handlers JAX-WS

L'objectif de ce TP est de mettre en place des intercepteurs (handlers) JAX-WS. Sauf indication contraire1), les développements se feront dans le projet wine-service.

Rendu

Ce TP est à rendre pour le dimanche 20/10/2013. Le rendu se fera par l'intermédiaire d'un projet forge (on fera attention a bien donner au moin le rôle “reporter” à Emmanuel Coquery et à Lionel Medini) contenant:

  • le projet maven mis à jour par vos soins (sans le répertoire target)
  • un fichier README.txt contenant au moins les noms, prénoms et numéros d'étudiants du binôme/trinôme. Toute autre information à transmettre aux enseignants (e.g. justifications de choix techniques) se fera dans ce fichier.

L'identifiant du projet forge (e la forme pxxxxxx-nomprojet) est à saisir dans Tomuss, dans l'UE Tiw5 WebServices, dans la case FORGE_TP4. On fera attention à tagger la révision correspondant au rendu avec le tag TP4.

Exemple

Créer une classe sw.wine.services.handlers.SimpleLogHandler contenant le code suivant:

SimpleLogHandler.java
package sw.wine.services.handlers;
 
import javax.xml.ws.handler.LogicalHandler;
import javax.xml.ws.handler.LogicalMessageContext;
import javax.xml.ws.handler.MessageContext;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
public class SimpleLogHandler implements LogicalHandler<LogicalMessageContext> {
 
	private final static Logger LOG = LoggerFactory.getLogger(SimpleLogHandler.class);
 
	@Override
	public void close(MessageContext ctx) {
	}
 
	@Override
	public boolean handleFault(LogicalMessageContext ctx) {
		LOG.warn("faute");
		return true;
	}
 
	@Override
	public boolean handleMessage(LogicalMessageContext ctx) {
		boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
		LOG.info("message "+(outbound?"sortant":"entrant"));
		return true;
	}
 
}

Créer un fichier src/main/resources/sw/wine/services/handler-chains.xml contenant:

handler-chains.xml
<?xml version="1.0" encoding="UTF-8"?>
<handler-chains xmlns="http://java.sun.com/xml/ns/javaee">
  <handler-chain>
    <handler>
      <handler-name>sw.wine.services.handlers.SimpleLogHandler</handler-name>
      <handler-class>sw.wine.services.handlers.SimpleLogHandler</handler-class>
    </handler>
    <!-- handler>
      <handler-name>un.autre.Handler</handler-name>
      <handler-class>un.autre.Handler</handler-class>
    </handler -->
  </handler-chain>
</handler-chains>

Ajouter l'annotation @HandlerChain(file="handler-chains.xml") dans la classe sw.wine.services.WineStorage, déployer le service et tester l'affichage dans les log en appelant le service avec SOAPUI.

Clients

Créer une classe sw.wine.model.user.Client dans le projet modele:

Client.java
package sw.wine.model.user;
 
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
 
@Entity
public class Client {
 
	/**
	 * L'identifiant du client.
	 */
	@Id
	@GeneratedValue
	private int id;
 
	/**
	 * Le nom du client.
	 */
	private String nom;
 
	/**
	 * La quantité d'argent que le client possède sur son compte de location.
	 */
	private double compte;
 
	public String getNom() {
		return nom;
	}
 
	public void setNom(String nom) {
		this.nom = nom;
	}
 
	public int getId() {
		return id;
	}
 
	public double getCompte() {
		return compte;
	}
 
	public void setCompte(double compte) {
		this.compte = compte;
	}
 
}

Si le besoin s'en fait sentir, ne pas hésiter à créer une classe sw.wine.model.user.dao.ClientDAO pour gérer les clients.

Handler de log

Mettre en place une chaîne de handlers pour le service de livraison (une des versions utilisant CXF) que vous avez implémenté pour le TP3 et y ajouter le handler de Log utilisé pour le service WineStorage.

Pour cela on créera un nouveau module handlers en lancant

mvn archetype:generate -DinteractiveMode=false -DartifactId=handlers -DgroupId=sw.wine

On modifiera ensuite le pom du projet handlers en:

  • supprimant les tag <version> et <groupId> dans <project>2)
  • et en ajoutant dans <parent>:
    <relativePath>..</relativePath>

Enfin on ajoutera les dépendances handlersmodel, serviceshandlers, wine-servicehandlers.

Déplacer ensuite la classe du handler de log dans le projet handlers

Modifier le handler de log pour afficher le nom de l'élément principal du message transmis.

Ajout d'information

Créer un nouveau handler qui récupère dans le header SOAP la valeur de l'élément client-id et l'injecte dans le contexte (propriété “client-id”). Modifier le handler de log pour afficher cette propriété si elle est présente. Ajouter ce handler dans la chaine d'interception et modifier le test soapUI de votre service de livraison pour y intégrer le nouveau header et tester.

Récupération de l'objet client

Créer un handler logique d'authentification qui ajoute une propriété client contenant un objet Client correspondant à la propriété client-id. Si le client n'existe pas, le handler interdit l'accès au service. Ajouter l'intercepteur dans la chaine des services et tester. On créera un ensemble de clients pour le test via un test JUnit dans le projet wine-service en utilisant JPA.

Débit du compte client

Ajouter un champ de type javax.xml.ws.WebServiceContext dans la classe d'implémentation du service de livraison. Annoter ce champ avec @Resource afin que le contexte soit injecté via IoC. La méthode getMessageContext() permet alors de récupérer le contexte du message et les propriétés qui ont été ajoutées par les handlers. Modifier le code métier du service pour, en plus, débiter le compte du client. <note tip>Seules les propriétés dont le scope est MessageContext.Scope.APPLICATION peuvent être accédées dans le bean qui code le service. Il faut donc penser à changer le scope de la propriété client dans le handler d'authentification via

ctx.setScope("client", Scope.APPLICATION);

</note>

1)
classe Client
2)
mais pas dans <parent>