Archive

Archives pour la catégorie ‘Web Services – SOA’

Seconde édition de la conférence NCrafts, soutenue par Viseo

NCraftsNCrafts est une conférence indépendante traitant du développement en technologies Microsoft … et aussi de sujets plus transversaux gravitant autour du Software Craftsmanship (la passion & la fierté de développer !).

Pour cette seconde édition qui aura lieu les 21 et 22 mai 2015 à Paris, Viseo soutient la conférence en étant Gold Sponsor et partenaire formation.

Si vous aimez le mouvement ALT.NET et les valeurs qu’il porte, vous allez adorer NCrafts qui en est une continuité encore plus ambitieuse, avec deux jours de conférences menées par des speakers de renom  : Hadi HARIRI, Mark SEEMAN, Laurent BOSSAVIT, Tomasz JASKULA, pour n’en citer que quelques uns.

… et aussi un jour de workshop pour rendre les choses encore plus concrètes ! Si vous recherchez un point de vue plus indépendant que les conférences éditeurs, vous allez également aimer !

Si les architectures avancées , les tendances naissantes dans les pratiques de développement vous font saliver, vous êtes les bienvenus à cette conférence … où vous pourrez aussi rencontrer les experts Microsoft de Viseo à notre stand dans l’espace sponsoring !

Retrouvez toutes les infos sur la conférence sur http://ncrafts.io/

En tant qu’organisme de formation agréé et partenaire de la conférence, nous pouvons vous accompagner pour vous faire participer via le budget formation de votre entreprise ! Prenez contact par email : formation@ncrafts.io

Spring eXchange – rencontre européenne pour les experts Spring

spring-by-pivotal

Après SpringOne 2GX qui a eu lieu outre Atlantique en septembre,  l’Europe organise sa sixième édition de la rencontre annuelle « Spring eXchange » à Londres les 6 et 7 novembre. Dans le cadre de la montée en expertise sur les nouvelles technologies chez Viseo: Papa Abdou Niang, Ibrahima Kane et moi aurons l’opportunité de participer à cet événement.

skillsMatter

Cette rencontre organisée par Skills Matter réunit les experts et les passionnés de la communauté Spring et Java pour deux jours d’apprentissage et de partage de compétences sur les best practices et solutions à des problèmes souvent rencontrés par la communauté. Pendant ces deux jours, une série de conférences et discussions sera animée par les experts autour des thèmes suivants :

  • Big Data
  • Spring XD
  • Spring en production (Spring IO)
  • Spring Data
  • Spring Boot
  • AngularJS et Spring
  • Spring Cloud
  • REST
  • Microservices et architecture moderne

Lire la suite…

Service à blocs

Lors de ma dernière mission, j’ai été confronté à un besoin qui me semble récurrent et pour lequel nous avons trouvé une solution qu’il me semble intéressant de partager. Ce besoin était de fournir des informations « presque identiques » à des clients « presque pareils ». Le problème étant dans le « presque », évidemment.

Prenons un exemple :

Pour une commande de meuble classique, un client se balade dans le magasin, choisit ses meubles et va voir un vendeur.
Le vendeur va alors enregistrer la commande du client ainsi que les détails nécessaires à la livraison. Le client peut alors décider d’un règlement immédiat ou différé, du dépôt simple ou du montage des meubles…
Le jour prévu, le livreur vient déposer les meubles chez le client et les monter si cela est prévu. Une fois cela effectué, le livreur signale la commande comme étant terminée.

Lire la suite…

Ecrire un client WebService avec CXF (3/3) – ajouter une pièce jointe

Cet article, proposé par Henri Darmet, fait suite à celui publié la semaine dernière et qui expliquait comment sécuriser l’accès à un web service CXF avec WS-Security.

At last, but not at least : Ajouter une pièce jointe

Cette étape est assez simple à réaliser en soi, elle demande essentiellement, de faire quelques ajustements au niveau de la définition de l’objet passé par la requête SOAP. Je m’explique.

  • Il s’agit d’un objet binaire (une image, un PDF) dont la nature en soi n’intéresse pas notre Web Service (ni SOAP, ni CXF). Pour nous, ce sera un tableau d’octets.
  • Il est possible (quoique onéreux) de passer cet objet en base 64 au sein même de l’enveloppe SOAP. Mais ici, nous allons utiliser une optimisation standard, MTOM qui permet d’inclure directement le document dans une requête http multipart.
  • Il s’agit d’une optimisation, c’est-à-dire que CXF peut décider – ou pas – de la réaliser. Pour le développeur, c’est à peu près transparent, à condition bien sûr de ne pas chatouiller CXF de trop près.
  • Le souci c’est que si un certain nombre de choses de ne sont pas faites, l’optimisation n’est pas déclenchée et le document est passé en base 64 avec éventuellement des problèmes de taille de message SOAP (Tomcat est assez récalcitrant…).

L’interface  de notre WebService change un peu :

package com.objetdirect.mailer;

 

import java.io.ByteArrayInputStream;

import java.io.ByteArrayOutputStream;

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

 

import javax.activation.DataHandler;

import javax.activation.DataSource;

import javax.xml.bind.annotation.XmlAccessType;

import javax.xml.bind.annotation.XmlAccessorType;

import javax.xml.bind.annotation.XmlMimeType;

import javax.xml.bind.annotation.XmlRootElement;

 

@XmlRootElement

@XmlAccessorType(XmlAccessType.FIELD)

publicclass Mail {

String from;

String to;

String topic;

String message;

@XmlMimeType(« application/octet-stream »)

DataHandler file;

public Mail(String from, String to, String topic, String message,

byte[] file)

{

super();

this.from = from;

this.to = to;

this.topic = topic;

this.message = message;

if (file!=null) {

setFile(file);

}

}

public void setFile(finalbyte[] content) {

DataSource ds = new DataSource() {

@Override

public OutputStream getOutputStream() throws IOException {

return new ByteArrayOutputStream();

}

@Override

public String getName() {

return « mydoc.pdf »;

}

@Override

public InputStream getInputStream() throws IOException {

return new ByteArrayInputStream(content);

}

@Override

public String getContentType() {

return « application/octet-stream »;

}

};

file = new DataHandler(ds);

}

 

public String getFrom() {

return from;

}

public String getTo() {

return to;

}

public String getTopic() {

return topic;

}

public String getMessage() {

return message;

}

}

Pour utiliser MTOM, CXF réclame trois actions :

  • définir la pièce jointe sous la forme d’un DataHandler,
  • annoter le champ incarnant la pièce jointe (de type DataHandler donc) par @XmlMimeType(« application/octet-stream »)
  • instruire l’objet client du WebService qu’il faut activer MTOM.

Les deux premières actions sont assurée par l’objet Mail ci-dessus. Jetons un coup d’œil sur l’instanciation du DataHandler. Volontairement, j’ai implémenté ici ce DataHandler de la façon la plus générique et donc la plus passe-partout. Ceci dit, java propose des classes de facilitation dans des cas courant comme les ressources Web ou les fichiers. Si votre besoin correspond au mieux, c’est-à-dire si votre document vous arrive sous la forme d’un tableau d’octets, la solution présentée ci-dessus devrait correspondre exactement à votre besoin.

Dernière action, donc : déclarer au client que l’on veut activer MTOM. Cela se fait aussi au niveau de la méthode getClient() dont la version finale est la suivante :

package com.objetdirect.mailer;

 

import java.io.IOException;

import java.util.HashMap;

import java.util.Map;

 

import javax.security.auth.callback.Callback;

import javax.security.auth.callback.CallbackHandler;

import javax.security.auth.callback.UnsupportedCallbackException;

import javax.xml.ws.BindingProvider;

import javax.xml.ws.soap.SOAPBinding;

 

import org.apache.cxf.interceptor.LoggingInInterceptor;

import org.apache.cxf.interceptor.LoggingOutInterceptor;

import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;

import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;

import org.apache.ws.security.WSConstants;

import org.apache.ws.security.WSPasswordCallback;

import org.apache.ws.security.handler.WSHandlerConstants;

 

publicclass MailerClient {

publicstatic Mailer getClient(

String url,

String username,

final String password)

{

JaxWsProxyFactoryBean
factory =
new JaxWsProxyFactoryBean();

 

Map<String,Object> outProps = new HashMap<String,Object>();

outProps.put(WSHandlerConstants.ACTIONWSHandlerConstants.USERNAME_TOKEN);

outProps.put(WSHandlerConstants.USER, username);

outProps.put(WSHandlerConstants.PASSWORD_TYPEWSConstants.PW_TEXT);

class ClientPasswordCallback implements CallbackHandler {


public ClientPasswordCallback() {


}


publicvoid handle(Callback[] callbacks) throws IOException,

UnsupportedCallbackException {

WSPasswordCallback
pc = (WSPasswordCallback) callbacks[0];

pc.setPassword(password);


}

}

outProps.put(WSHandlerConstants.PW_CALLBACK_REFnew ClientPasswordCallback());

WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(outProps);

wssOut.setAllowMTOM(true);

factory.getInInterceptors().add(new LoggingInInterceptor());

factory.getOutInterceptors().add(new LoggingOutInterceptor());

factory.getOutInterceptors().add(wssOut);

factory.setServiceClass(Mailer.class);

factory.setAddress(url);

Mailer client = (Mailer) factory.create();

((SOAPBinding)((BindingProvider)client).getBinding()).setMTOMEnabled(true);

return client;

}

}

Il faut rajouter deux lignes :

  • une première au niveau de l’intercepteur WS-Security qui indique à ce dernier qu’il doit prendre en compte des pièces jointes
  • une seconde, qui utilisant le client créé , va rechercher l’objet SOAPBinding attaché et indique à cet objet que MTOM est acceptée

Il faut que ces deux appels soient effectifs pour que CXF daigne utiliser MTOM avec WS-Security ! Sinon, MTOM est silencieusement ignoré. Autant le second appel est (relativement) bien documenté, autant le premier est un secret jalousement gardé (ai-je commis une trahison ? la NSA va-t-elle s’intéresser à mon cas ?). Si vous l’oubliez, MTOM est silencieusement ignoré et aucun message de log, aucune documentation, aucune googlisation (jusque-là) ne vous renseigne sur la raison…

Thats’s all folks.

Categories: Java EE, Web Services - SOA Tags:

Ecrire un client WebService avec CXF (2/3) – comment sécuriser l’accès avec WS-Security

Cet article, proposé par Henri Darmet, fait suite à celui publié la semaine dernière et qui expliquait comment écrire la partie cliente d’un web service de manière simple avec CXF.

Seconde étape : sécuriser l’accès avec WS-Security

Je passe sur l’absolue nécessité de sécuriser l’accès à ce WebService afin que n’importe qui ne fasse pas n’importe quoi. D’ailleurs, en dehors des salles de TP en école d’ingénieur ou en université, tous les WebServices devraient être sécurisés. La bonne nouvelle, c’est que c’est plutôt simple à réaliser. La mauvaise nouvelle est qu’il n’est pas toujours facile de trouver un tutoriel complet sur le sujet. La nouvelle bonne nouvelle, c’est qu’existe enfin, cet article pour l’expliquer.

La méthode employée, pour faire simple est la plus commune : transmettre un login et un mot de passe. C’est lorsqu’on demande un accès au service que ces informations doivent être fournies. Inutile donc de modifier l’interface de notre service. Conséquence : les classes Mail et Mailer ne changent pas. Tout est contenu dans la méthode getClient().

La nouvelle mouture de cette méthode est la suivante :

package com.objetdirect.mailer;

 

import java.io.IOException;

import java.util.HashMap;

import java.util.Map;

 

import javax.security.auth.callback.Callback;

import javax.security.auth.callback.CallbackHandler;

import javax.security.auth.callback.UnsupportedCallbackException;

 

import org.apache.cxf.interceptor.LoggingInInterceptor;

import org.apache.cxf.interceptor.LoggingOutInterceptor;

import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;

import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;

import org.apache.ws.security.WSConstants;

import org.apache.ws.security.WSPasswordCallback;

import org.apache.ws.security.handler.WSHandlerConstants;

 

publicclass MailerClient {

 

publicstatic Mailer getClient(

String url,

String username,

final String password)

{

JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();

Map<String,Object> outProps = new HashMap<String,Object>();

outProps.put(WSHandlerConstants.ACTION,WSHandlerConstants.USERNAME_TOKEN);

outProps.put(WSHandlerConstants.USER,username);

outProps.put(WSHandlerConstants.PASSWORD_TYPE,WSConstants.PW_TEXT);

class ClientPasswordCallback implements CallbackHandler {


public ClientPasswordCallback() {


}


publicvoid handle(Callback[] callbacks) throws IOException,

UnsupportedCallbackException {

WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];

pc.setPassword(password);

}

}

outProps.put(WSHandlerConstants.PW_CALLBACK_REF,

new ClientPasswordCallback());

WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(outProps);

factory.getInInterceptors().add(new LoggingInInterceptor());

factory.getOutInterceptors().add(new LoggingOutInterceptor());

factory.getOutInterceptors().add(wssOut);

factory.setServiceClass(Mailer.class);

factory.setAddress(url);

Mailer client = (Mailer) factory.create();

return client;

}

}

C’est notoirement plus compliqué, évidemment. A y regarder de près, on s’aperçoit néanmoins que le code reste lisible et surtout, surtout, générique. En gros, que fait-on ?On définit un nouvel intercepteur (un intercepteur de sécurité cette fois) que l’on va paramétrer à l’aide d’informations stockées dans une Map. Ces informations sont :

–         le type d’identification/authentification souhaité (ici login/mot de passe)
–         le login
–         le mot de passe

Jusque-là rien de complexe. Mais voilà, pour une raison certainement très valable, les auteurs de CXF ont défini une bien étrange manière de passer le mot de passe : on fournit un objet au sein de la Map et cet objet implémente une interface particulière (CallbackHandler) contenant une méthode « handle » recevant des réflexes (callback) donc le premier (et le seul ?) est de type WSPasswordCallback. C’est à cet objet réflexe-là qu’il faut transmettre, au sein de la méthode « handle », donc, le mot de passe adéquat. Ça ne se devine pas, n’est-ce pas ? Je suis bien d’accord. On imagine que derrière, le mot de passe est passé de manière asynchrone. Pourquoi ? Mystère.

Petite remarque pour les petits malins qui essaieraient d’externaliser ClientPasswordCallback : c’est un « inner class » (même si elle n’est pas « anonymous »). Elle fait référence au nouveau paramètre « password » de la méthode getClient (qui prend aussi un autre nouveau paramètre : le login). Prévoir, donc, de toucher à deux ou trois choses.

Pour le repos des neurones du lecteur, voici donc l’appel du Web Service légèrement amendé :

publicstaticvoid main(String[] argv) {

Mailer mailer = MailerClient.getClient(

« http://www.acme.com/ws/mailer »,

« myid »,

« mypassword »);

mailer.send(new Mail(

« noanswer@acme.com »,

« bigboss@goyoo.com »,

« New Webservice »,

« The new Web Service is ready ! »));

}

Seule différence : il faut fournir à getClient, un login et un mot de passe.

Pour que cela fonctionne, il faut, évidemment que la partie serveur accepte ces informations d’identification/authentification et puisse les valider (en se basant sur un annulaire LDAP par exemple). Notez qu’il s’agit d’une sécurité au niveau du Web Service et non au niveau http. Ceci ce code (en java) dans le WebService lui-même. Alimenter le « realm » de Tomcat ne servira donc à rien en l’état. Je dis ça, car j’ai vu certains faire la confusion.

Dans le prochain article, nous verrons comment ajouter une pièce jointe.

Categories: Java EE, Web Services - SOA Tags:

QCon London 2010 – Udi Dahan – Avoid a Failed SOA

“Business & Autonomous Components to the Rescue”

image Malgré un sujet pas très original, avec peu d’idées réellement neuves, probablement la meilleure présentation à laquelle j’ai assisté aux QCon 2010 de Londres. J’y ai été particulièrement sensible, du fait que j’ai moi-même réalisé et animé des séminaires sur des sujets similaires. Et j’ai pris une leçon, sur la forme comme sur le fond.

Sur le fond, finalement, un seul message simple est véhiculé par Udi Dahan : une condition nécessaire à la réussite d’une SOA c’est l’émergence de composants très faiblement couplés. Pas vraiment une surprise. Mais c’est grâce à une forme étudiée que son discours (simple mais pas simpliste) amène à se poser des questions profondes.

Sur la forme donc, un discours extrêmement clair sans utilisation d’aucun buzz, et un enchaînement logique des idées qui mène inexorablement l’auditoire à ses conclusions inéluctables. Quand la vidéo de cette présentation sera en ligne sur InfoQ (malheureusement, ils les distillent pendant six mois), ne la ratez pas.image

Je vais tenter de résumer.

Le sujet c’est le projet d’intégration. Pourquoi ça rate souvent, et comment faire que ça rate moins :-) On a le droit de se tromper plusieurs fois, mais à chaque fois différemment !

La présentation oscille autour de l’architecture entre la vision métier et la vision technologique.

SOA et couplage faible

Un des objectifs de la SOA est d’atteindre un couplage faible entre composants métiers autonomes. Tout le monde est d’accord là-dessus. Mais ce couplage faible doit être une exigence à la fois métier et technique qu’il faut prendre en compte à la conception comme à l’exécution.

imageUdi part d’un SI théorique plutôt bien aligné sur le métier (avec une véritable architecture fonctionnelle explicite) dont on pourrait se dire qu’il est facilement “SOAisable”.

Il montre qu’une intégration des applications par des services (une SOA) peut, en fait, mener facilement à des applications très fortement couplées qui amènent, en production, leur lot de contentions (mémoire, threads, locks base de données…) .

So what ? Qu’est-ce qu’on a loupé ?

On a oublié que pour obtenir le découplage à l’exécution il faut des communications asynchrones (d’un point de vue fonctionnel et pas seulement technique). Et il y a de fortes conséquences sur… la conception.

Il faut donc basculer du requête/réponse à la publication/abonnement (d’une architecture orientée services vers une architecture orientée événements). C’est la succession d’émission d’événements qui matérialise le processus et non l’orchestration d’appel de services. Et c’est l’émetteur qui définit le contrat de service et non le receveur. On parle d’Event Driven Architecture (EDA).

Mon avis

Même si ce qui vient d’être dit est parfaitement logique en terme d’affectation de responsabilités, la plupart des démarches de conception travaillent dans l’autre sens : le contrat de service est défini à partir du besoin du client du service (c’est ce qu’on fait quand on fait de la conception d’application : c’est le scénario d’utilisation qui définit les services publiés par le serveur métier). Il faut donc changer radicalement son mode dimagee conception lorsqu’on fait de la SOA/EDA : les contrats de service doivent être définis uniquement par les changements d’état des objets métier et non par les “clients” de ces changements d’état.

Autre réflexion que m’inspire cette vision (originale) de ce qu’est un processus SI : un enchainement infini d’événements. On ne peut plus définir un Processus avec un début (l’Evénement déclencheur) et une fin (un Produit de sortie) créant de la valeur pour son Client. C’est une révolution conceptuelle (on remet en cause la définition d’un processus selon l’ISO !) et surtout, ça pose un gros problème. Comment appliquer la doctrine millénaire du consultant en processus : “centrer les processus de l’entreprise sur le client”, si le client de l’entreprise n’est plus le client du processus ? Je n’ai pas de réponse pour le moment :-)

Composants métier autonomes

Udi Dahan évoque ensuite une autre question délicate. Comment partitionner les services en composants autonomes ? A nouveau, une réponse évidente est : aligner les composants sur le métier. Un composant métier par bloc fonctionnel. Un rêve d’urbaniste !

Il montre qu’en fait, ce partitionnement “idéal” ne répond pas toujours au besoin et  imageparticulièrement aux exigences non fonctionnelles. Il donne l’exemple des SLA différents en fonction du type de client et propose donc des composants métier autonomes techniquement (potentiellement très différents dans l’implémentation), définissant les mêmes contrats de service mais implémentés différemment.

Mais à nouveau, comment éviter un couplage si, finalement le routage des événement doit se faire en fonction de leur contenu (l’événement contenant un “petit client” doit être routé vers le composant dédié petit client, l’événement “gros client” vers le composant dédié gros client).

Le fonctionnement EDA précédent permet, à nouveau, à chaque composant d’être autonome dans la prise de décision : tous les composants d’un même métier sont abonnés aux mêmes événements et chacun décide de manière autonome de traiter ou non un événement particulier en fonction de son contenu.

A bientôt pour d’autres conférences QCon.

Categories: Web Services - SOA Tags: , , , ,

soapUI : tests de charge de Web Services

Je continue mon tutorial sur soapUI. Voyons cette fois-ci comment utiliser soapUI pour réaliser des tests de charge.

Il faut ajouter un nouveau test de charge sur le TestCase voulu.
Note: il faut savoir que le test de charge va lancer tous les tests en parallèle, donc il ne faut pas qu’il y a de dépendance entre les services du TestCase, car ceci pourrait fausser vos résultats.

clip_image002

Une fenêtre s’ouvre, il est possible de choisir la stratégie de test et de la configurer.
A savoir : la durée du test, le nombre de threads à utiliser, le délai (aléatoire ou non) entre chaque nouvelle requête, etc.

clip_image004

Sur cette image on peut se rendre compte qu’un service qui renvoie une stacktrace d’exception est couteuse en temps et en données.


Le tableau de résultat affiche : le temps de réponse min max moyen, le nombre de requêtes totales lancées lors du test, le total de données transférées, le nombre d’erreur.

De plus, la console de log en dessous permet d’avoir des détails sur les tests déroulés, comme l’heure de début et de fin du test, les éventuelles erreurs, etc …

Charger une association dans WCF RIA Services

Je l’avais annoncé ici : .NET RIA services est devenu WCF RIA Services.

Rappels

L’objectif de ce projet est de simplifier le développement d’applications RIA.

Le principe général est assez simple :
Je développe des services de domaine (CRUD + Queries) en utilisant des conventions de nommage côté serveur.

Par exemple, la méthode Sprint LoadSprint(int sprintId) renvoie un sprint d’une application Scrum à partir de son identifiant.

WCF RIA Services projette ce code côté client dans des classes de type DomainContext.

Dans notre exemple, j’obtiens une classe ScrumDomainContext avec une méthode EntityQuery<Sprint> LoadSprintQuery(int sprintId)

Projection de code

Projection de code

Les associations

La version beta est disponible depuis le mois de Novembre. On trouve sur le Web quelques introductions, notamment celles de Brad Abrams. En revanche, on trouve très peu de choses sur comment charger une association dans notre application cliente Silverlight.

Dans mon exemple, je veux afficher une vue Master/Details qui présente un sprint et la liste de ses tâches.

Le modèle

Sprint association

Sprint association

La déclaration de l’association

Je dois ensuite décrire à WCF Ria services les associations entre mes entités. Pour cela, je décore les propriétés Tasks de la classe Sprint, et Sprint de la classe Task avec l’annotation AssociationAttribute. Il faut indiquer un nom pour cette association, par exemple Sprint_Tasks et préciser les clés étrangères de chacune de ses relations. Dans le sens Sprint -> Task, la clé c’est le champ Id de la classe Sprint et la clé étrangère c’est le champ SprintId de la classe Task.


public class Sprint{
[Key]
public virtual int Id { get; set; }

[Association(« Sprint_Task », « Id », « SprintId »)]
public virtual ICollection Tasks { get; set; }
}

Quelques remarques :

  1. Les habitués de NHibernate vont déplorer le fait d’avoir à décrire l’association à l’aide des clés étrangères. Cela nécessite par ailleurs d’avoir une propriété SprintId dans la classe Task en plus de la propriété Sprint :(
  2. La décoration est automatique avec l’utilisation de LinqToSql ou d’Entities Framework

Le chargement explicite

Il reste enfin à indiquer explicitement que l’on souhaite sérialiser les tâches avec le sprint. Pour cela, nous devons définir une classe de méta données relative à la classe métier. Dans notre exemple, ce sera une classe SprintMetaData définissant un champ Tasks que l’on décore avec l’annotation IncludeAttribute.


public class SprintMetaData {
[Include]
public EntitySet Tasks;
}

Je vous laisse regarder le blog de Brad Adams ou un ancien billet pour les détails de la classe de méta données.

Personnellement je trouve dommage d’avoir à définir une stratégie de chargement dans un fichier de méta données. L’idée générale n’est pas mauvaise, mais présente un inconvénient majeur : la stratégie est valable pour tous les cas d’utilisation. Or il est probable que l’application ne nécessite à la fois le sprint et ses tâches que dans certains écrans …

Outils de mapping objet/relationnel

Si vous utilisez un ORM, n’oubliez pas de récupérer la collection de tâches dans votre requête.

Avec LinqToEntities, ça donne :


public Sprint LoadSprint(int sprintId){
return this.Context.Sprints
.Include("Tasks")
.Where(sprint=>sprint.Id == sprintId);
}

Avec LinqToNhibernate, ça donne:


public Sprint LoadSprint(int sprintId)
{
var result = this.Session.Linq().Expand("Tasks")
.Where(x => x.Id == sprintId)
.ToList().First();
return result;
}

Conclusion

Nous avons vu en détail comment charger une association entre deux entités dans une application WCF Ria Services. Une partie de ces détails est masquée par l’outillage fourni par Microsoft et nous ferait presque oublier la complexité qui ne manquera pas de ressortir si vous souhaitez utiliser cette pile en association avec des outils tel que NHibernate

soapUI : pré-remplir les champs d’une requête

Suite de mon tutorial sur soapUI, voyons cette fois-ci comment pré-remplir certains champs d’une requête. Par exemple, un login et un password nécessaire pour se connecter.

Si vous avez une série de requêtes dans votre Test case, il est préférable de créer un script qui se chargera de vous pré-remplir ces champs plutôt que de le faire à la main 😉

Il faut créer un nouveau « step » nommé ‘Groovy Script’.

clip_image002

Voici un exemple de code qui pré-rempli les champs ‘login’ et ‘password’. Ces valeurs doivent être déclarées et initialisées dans l’onglet « Custom Properties » du projet (il s’affiche en cliquant sur le nom du projet).

image

Entrez ensuite le code du script :

image

Un petit Copier-(Réfléchir*)-Coller du code suivant simplifiera le travail !             (* © F.D.)

def groovyUtils = new com.eviware.soapui.support.GroovyUtils( context )
//variables definitions
def login = '${#Project#login}'
def password = '${#Project#password}'

//Retrieves all TestSteps of the current testCase
log.info("* " + testRunner.testCase.name )
def testStepList = testRunner.testCase.getTestStepList()

testStepList.each{currentTestStep->
    if (currentTestStep.name != "Inits fields") { //ici liste des steps que le script ne doit pas modifier
        log.info(" \\-- " + currentTestStep.name )
        def holder = groovyUtils.getXmlHolder( currentTestStep.name+"#Request" )
        log.info(" " + 'holder' )
        holder.namespaces["ns"] = "http://schemas.xmlsoap.org/soap/envelope/"

        //Inits values of the current testStep
        log.info(" " + 'login' )
        holder.setNodeValue("//ns:Body/*/login", login)
        log.info(" " + 'password' )
        holder.setNodeValue("//ns:Body/*/password", password)

        //Updates the change
        holder.updateProperty()
    }
}
'Script OK'

Voici la requête une fois le script exécuté :

image

Note : pour éviter de faire un copier-coller du code à chaque Test case, il est possible de cloner ce « step » et le déplacer dans un autre Test case :-)

soapUI : tester l’enchainement de Web Services

Dans un précédent article, je vous ai montré comment tester unitairement un Web Service. Cette fois-ci, nous allons aller un peu plus loin en testant l’enchainement de plusieurs Web Services.

Comme nous l’avons vu chacun de nos tests unitaires se trouve dans un arbre. Il est alors possible de lancer l’ensemble des tests de la suite, ou toutes les étapes d’un scénario, simplement en double cliquant sur le nœud correspondant de l’arbre. (Nœuds : TestSuite ou TestCase)

Une fenêtre s’ouvre et permet de voir les résultats

clip_image002[10]

A peine plus compliqué, il est aussi possible de récupérer une valeur dans une réponse et de l’injecter dans le test suivant.

Exemple d’utilisation : Dans nos jeux de tests, on veut réaliser l’enchainement suivant :

  • Créer une commande (createOrder)
  • Annuler la commande qui vient d’être créée (cancelRequestNumber)

sachant que ce dernier service prend en paramètre un « request number » qui est renvoyé dans la réponse du « createOrder ».

Pour récupérer cette valeur et remplir notre requête « cancelRequestNumber », on utilise la fonctionnalité offerte par soapUI : le « Property Transfer ».

La valeur à récupérer (la « Source ») :

image

Le champ à remplacer (la « Target ») :

image

On ajoute un « step » ‘Property Transfer’ à notre Test Case « PropTransfer » :

clip_image006

On donne un nom au remplacement automatique qui sera effectué, à chaque exécution des tests :

clip_image008

On configure les chemins vers les champs qui nous intéressent :

image
Les chemins représentent les nœuds XML, de la requête et de la réponse SOAP, à parcourir pour atteindre les champs voulus

On place maintenant le « step » ‘Property Transfer’ entre les 2 tests (createOrder et cancelRequestNumber), de façon à obtenir un enchainement logique dans notre TestCase ‘PropTransfer’ :

clip_image012

On peut maintenant dérouler l’ensemble du Test Case :-)