Developpez.com - Java
X

Choisissez d'abord la catégorieensuite la rubrique :


SOA facile avec SCA et FraSCAti

Date de publication : 24 janvier 2012.

Par Michel Dirix Site Blog

 

Comment simplifier le développement d'applications SOA tout en se donnant un cadre architectural ?
SCA (Service Component Architecture) et notamment FraSCAti que nous utiliserons apportent des réponses à ces préoccupations.
http://frascati.ow2.org Article tiré d'un tutoriel de Christophe Demarey et Damien Fournier (INRIA Lille-Nord Europe). Avant de commencer, je vous conseille d'aller voir cet article pour être un peu plus familier avec les termes SCA.

       Version PDF (Miroir)   Version hors-ligne (Miroir)
Viadeo Twitter Facebook Share on Google+        



I. Introduction
II. Présentation et installation de FraSCAti
III. SCA, cadre architectural
IV. SCA, vecteur d'interopérabilité et d'intégration technologique
V. Implémentation d'un composant SCA
VI. SOA simplifiée
VII. Accès à un service REST : Twitter
VIII. Accès à un Web Service (SOAP) météo
IX. Réalisation de l'orchestration
X. Descripteur d'assemblage
XI. Créer un service web
XII. Conclusion


I. Introduction

Ecrire des applications SOA, avec de nombreux services web, n'est pas toujours chose aisée. Notamment, la mise en ?uvre de services web (WS, REST, etc.) demande du temps et surtout du code technique en plus de vos classes métiers.
Que diriez-vous de n'écrire que le code métier et simplement spécifier dans un fichier XML les services que vous voulez exposer sur le web ? SCA rend ceci possible !
Mais ce n'est pas le seul avantage, SCA vous permet aussi de bénéficier d'un cadre architectural pour vos applications orientées services. Enfin, il permet de mixer des applicatifs utilisant des technologies différentes (bundle OSGi, Java, scripts, BPEL, etc.) et des protocoles de communication hétéroclites (SOAP, HTTP, JSON-RPC).


II. Présentation et installation de FraSCAti

Il existe plusieurs implémentations des spécifications SCA (OW2 FraSCAti, Apache Tuscany, IBM WebSphere, etc.). Nous utiliserons FraSCAti, une plate-forme open-source du consortium OW2. Elle ne supporte pas tous les langages et protocoles spécifiés pour SCA (focus sur les technologies Java) mais, en contrepartie, fournit plusieurs fonctionnalités avancées, telles que le support de composants SCA réflexifs (permettant le changement de configuration à chaud des assemblages), des protocoles d'accès originaux comme UPNP, JNA ou encore des outils qui nous aiderons à observer l'état et administrer les assemblages de composants pendant leur exécution. FraSCAti est téléchargeable sous la forme d'une archive zip sur le site du projet (http://frascati.ow2.org). Pour installer la plateforme, il suffit d'extraire les fichiers de l'archive.


III. SCA, cadre architectural

Notre exemple fil rouge, MyWeather, consiste en une orchestration de plusieurs services. Dans un premier temps, nous allons interroger un compte twitter pour récupérer la localisation d?une personne, ensuite nous interrogerons un service météo afin d?obtenir le temps pour ce lieu.

SCA propose un langage d'architecture décrit en XML qui permet de construire des applications par assemblage de composants, le composant représentant une fonctionnalité implémentée généralement par une classe. Un assemblage SCA est comparable à la notion de contexte d'application dans Spring, les beans étant assimilés à des composants SCA.

Il est possible de générer le descripteur d'architecture (fichier *.composite) en utilisant l?éditeur STP/SCA d?Eclipse, mais nous allons ici modéliser notre exemple directement en XML [Figure 1.]. Pour cet assemblage (ou composite) SCA nous devons réaliser deux composants :

Implémentation du composant de décodage
Figure 1 : Implémentation du composant de décodage

IV. SCA, vecteur d'interopérabilité et d'intégration technologique

SCA n'impose pas de langage particulier pour ses composants. Il est possible d'implémenter des composants avec le langage Java ou Scala, des scripts Ruby ou JavaScript, ou encore d'utiliser des composants Spring. Cette flexibilité se retrouve pour la création ou l'utilisation de services pouvant être réalisés par le biais des technologies SOAP, HTTP, RMI, JMS, etc. Les nombreux langages et protocoles d'accès supportés par les implémentations de SCA présentent cette technologie comme solution efficace pour faciliter l'intégration de composants logiciels existants.


V. Implémentation d'un composant SCA

Nous allons, dans un premier temps, nous intéresser à l'implémentation de notre composant de décodage qui sera utilisé pour traduire les réponses du service météo, encodées au format XML. Notons que ce composant ainsi que les objets JAXB sont nécessaires car le WSDL du service décrit le type de retour de ces méthodes comme une chaine de caractères et non le type réel (liste de Locations).

Le composant Decoder, développé en Java, fournit une méthode 'decode'. Nous commençons par définir une interface Java, nommée 'Decoder', qui représentera le contrat du service. Cette interface a la signature suivante : Locations decode(String message);

On nommera son implémentation DecoderImpl :
DecoderImpl

public Locations decode(String message) {
	InputStream is = new ByteArrayInputStream(message.getBytes());
	try {
		JAXBContext context = JAXBContext.newInstance(Locations.class);
		Unmarshaller unmarshaller = context.createUnmarshaller();
		return (Locations) unmarshaller.unmarshal(is);
	} 
	catch (JAXBException e) {
		System.err.println("Unable to decode server message.");
		return null;
  	} 
}
Cette méthode permet de décoder (via JAXB) le message XML renvoyé par le service météo et donnant la liste des villes pour lesquelles le service météo est disponible. Cette liste est utilisée par le composant d'orchestration pour connaitre l'ensemble des villes où les informations météo sont accessibles.

Notons qu'un composant SCA ne peut exposer un service que s'il fournit une interface décrivant ses méthodes (aussi appelée contrat). Ici, le contrat est une interface Java, mais SCA permet aussi de définir les contrats via des descripteurs WSDL.


VI. SOA simplifiée

Grâce à SCA, nous allons très facilement utiliser ou réaliser des services distants sans nous soucier des détails techniques propres aux protocoles d'accès. Nous illustrerons l'intégration et l'exposition de services avec SCA via la création d'un composant d'orchestration qui proposera la mise à jour des informations météorologiques pour des utilisateurs du service twitter

Pour obtenir les informations relatives à un compte utilisateur, twitter propose une API conforme au principe d'architecture REST (REpresentational State Transfer). Le service de météo est lui, accessible via le protocole SOAP. Nous allons accéder à ces services de nature différente via les connecteurs REST et Web Service fournis par la plateforme FraSCAti. L'utilisation d'un connecteur avec SCA est non intrusive, elle n'impacte pas l'implémentation même du composant. C'est FraSCAti qui se chargera de la création des stubs/squelettes en charge des connexions distantes


VII. Accès à un service REST : Twitter

Nous passons à l'intégration des services twitter et météo afin de les rendre utilisables par notre orchestration. Pour rappel, la technologie SCA propose l'intégration des services via de nombreux protocoles d'accès dont l'utilisation est spécifiée via le descripteur d'architecture. Par exemple, pour accéder aux méthodes exposées par twitter nous sélectionnerons le binding REST en ajoutant, dans la description de notre composite SCA, la balise XML suivante:

<frascati:binding.rest uri="http://twitter.com"/
L'attribut URI permet d'indiquer l'adresse de la ressource web à accéder via REST, dans notre cas "http://twitter.com". Pour permettre à notre composant, implémenté en Java, d'accéder aux informations du profil utilisateur, Nous devons écrire l'interface qui reflètera le service utilisé.

import javax.ws.rs.*;
public interface Twitter {
	@GET
	@Path("/users/show/{id}.xml")
	User getUser(@PathParam("id") String id);
}
Nous utiliserons la méthode "getUser" qui permet de récupérer les informations contenues dans le profil utilisateur. Cette méthode prend en paramètre l'identifiant de l'utilisateur. Dans le cas d'un service REST, nous devons utiliser les annotations de l'API JAX-RS afin de préciser le chemin d'accès, la commande HTTP, et les paramètres utilisés pour accéder à la ressource. L'appel à la méthode "getUser" renvoie un objet de type User reflétant l'architecture de la ressource REST reçue. La classe User comporte les annotations de l'API JAXB afin de réaliser la correspondance entre les tags XML et les champs de l'objet. Le code java pour la classe "User" est donné ci-dessous :

import javax.xml.bind.annotation.*;
@XmlRootElement
public class User {
   	public String id;
	public String name;
	public String screen_name;
	public String location;
	...
}
La valeur de l'attribut "location" de l'objet "User" contient les informations de localisation renseignées dans le compte twitter. Nous pouvons passer { l'intégration du service météo.


VIII. Accès à un Web Service (SOAP) météo

Le service météo que nous utilisons est accessible via le protocole SOAP, il est publié à l'adresse "http://www.webservicex.net/globalweather.asmx". Ce service web présente deux opérations : "GetCitiesByCountry" qui permet de lister les villes où les informations sur la météo sont disponibles et "GetWeather" pour connaitre la météo d'une ville. Pour utiliser ce service nous allons faire appel au connecteur SOAP de la plateforme FraSCAti. Dans notre descripteur d'assemblage, nous décrivons l'accès à ce service via une référence comportant un binding web service. Le service météo est alors rendu accessible pour les composants SCA de notre assemblage, et donc accessible pour le composant d'orchestration. Dans le descripteur d'assemblage SCA, cette liaison se traduit par la balise suivante :

<binding.ws wsdli:wsdlLocation="http://www.webservicex.net/globalweather.asmx?wsdl"
wsdlElement="http://www.webservicex.net#wsdl.port(GlobalWeather/GlobalWeather
Soap)" />
La présence des attributs wsdlLocation et wsdlElement permettent à la plateforme de retrouver le descripteur de l'interface WSDL et le port d'accès au service web. Pour rendre le service météo utilisable par le composant d'orchestration, nous devons générer l'interface Java reflétant ce service à partir de son descripteur WSDL. Pour réaliser cette opération FraSCAti propose la commande wsdl2java :

% frascati wsdl2java -u http://www.webservicex.net/globalweather.asmx?wsdl -o 
src/generated
Elle permet d'obtenir l'interface "GlobalWeatherSoap" dans le dossier des sources Java. L'interface obtenue est décorée avec les annotations de l'API JAX-WS, indiquant le nom des opérations, paramètres et messages proposés par le service web. C'est via cette interface que l'on pourra interroger le service météo


IX. Réalisation de l'orchestration

Nous avons réalisé le composant de décodage des messages, puis écrit/généré les interfaces qui permettent d'interagir avec les services externes : twitter et météo. Nous pouvons, à présent, nous occuper de l'implantation du composant d'orchestration qui se chargera d'agréger les informations récupérées des services externes et de décoder les informations de localisation. Nous commençons par créer la classe "Orchestration" suivante :

public class Orchestration {
	@Reference protected Twitter twitter;
	@Reference protected Decoder decoder;
	@Reference protected GlobalWeatherSoap weather;
	@Property protected String userId;
	...
}
Dans notre implémentation, nous utilisons deux annotations spécifiques à SCA. L'annotation "@Reference" précise les attributs de la classe permettant d'utiliser d'autres services, internes ( ici le decoder) ou distants (twitter et météo dans notre cas). L'injection d'une référence vers un autre service ou un autre composant est réalisée par la plateforme SCA. La seconde annotation "@Property" définit une propriété configurable du composant, la valeur de cette propriété sera définie dans le descripteur d'assemblage SCA.

Il ne nous reste qu'a implémenter la méthode d'orchestration que nous nommerons "getWeatherForUser()". Nous allons d'abord appeler le service twitter et vérifier que notre utilisateur a renseigné la localisation dans son profil.

public String getWeatherForUser() {
	User user = twitter.getUser(userId);
	if (user.location.equals("")) {
		System.err.println("The user " + userId + " did not publish his location");
		return "N/A";
	} ...
Nous supposons que l'attribut de localisation comporte le nom de ville et du pays séparés par une virgule, que nous récupérons dans les variables "cityName" et "countryName"

 ...
String[] locations = user.location.split("[\\s]*,[\\s]*", 2);
String cityName = locations[0];
String countryName = locations[1];
System.out.println("User '" + userId + "' is living in " + cityName
        + " (" + countryName + ")"); ...
On récupère la liste des villes proposées par le service météo en utilisant la référence correspondante : "weather", puis on appelle le composant de décodage. On obtient alors une instance d'objet "Locations".

String cities = weather.getCitiesByCountry(countryName);
Locations l = decoder.decode(cities);
...
Enfin, on compare la liste des villes avec la localisation de l'utilisateur. S'il y a correspondance, on appelle de nouveau le service météo pour obtenir les conditions météo détaillées:

String result = "";
if (l != null) {
	boolean done = false;
	for (Location loc : l.locations) {
		if (loc.city.value.toLowerCase().contains(cityName.toLowerCase())) {
			result += "Current weather in " + loc.city.value + ":\n";
        	result += weather.getWeather(loc.city.value, countryName) + "\n";
        	done = true;
		} 
	}
	if (!done) {
		System.err.println("Unable to find '" + cityName + "' in available cities of the weather service");
	} 
}
return result;

X. Descripteur d'assemblage

Nous avons implémenté les différents composants et interfaces nécessaires pour réaliser notre orchestration. Nous pouvons maintenant décrire l'architecture de notre application SCA. Le descripteur d'architecture appelé "composite" permet de construire notre application en définissant les composants, leurs liaisons, les propriétés de configuration ou encore les connecteurs utilisés.

L'écriture d'un composite commence avec l'élément XML "composite" qui mentionne obligatoirement un attribut "name". Notez également la définition des espaces de nommages via l'attribut "xmlns", qui seront ensuite utilisés dans la description:

<composite name="twitter-weather"
  xmlns="http://www.osoa.org/xmlns/sca/1.0"
xmlns:wsdli="http://www.w3.org/2004/08/wsdl-instance"
  xmlns:frascati="http://frascati.ow2.org/xmlns/sca/1.1">
....
On définit ensuite les composants SCA. Dans un premier temps, nous ajoutons le composant responsable du décodage des messages XML. Les lignes suivantes permettent de nommer le composant et de lui associer la classe d'implémentation Java écrite précédemment.

<component name="decoder">
    <implementation.java class="org.ow2.frascati.examples.twitterweather.lib.DecoderImpl" />
</component>
Nous ajoutons le second composant, responsable de l'orchestration. Outre la classe d'implémentation, nous décrivons les références vers les services nommés twitter et weather, ainsi que vers le composant de décodage. Nous définissons également la propriété "userId" qui utilisera la valeur définie dans la propriété nommée "userId" du composite (réutilisation de propriétés).

<component name="orchestration">
	<implementation.java class="org.ow2.frascati.examples.twitterweather.lib.Orchestration"/>
	<reference name="twitter"/>
	<reference name="weather"/>
	<reference name="decoder" target="decoder"/>
	<property name="userId" source="$userId"/>
</component>
Finalement, on décrit les références vers les services en spécifiant les connecteurs utilisés et on définit une valeur pour la propriété userId au niveau du composite.

	<reference name="twitter" promote="orchestration/twitter">
  		<frascati:binding.rest uri="http://twitter.com"/>
	</reference>
	<reference name="weather" promote="orchestration/weather">
   		<binding.ws wsdli:wsdlLocation="http://www.webservicex.net/globalweather.asmx?wsdl" wsdlElement="http://www.webservicex.net#wsdl.port(GlobalWeather/GlobalWeatherSoap)" />
	</reference>
	<property name="userId">userid</property>
</composite>

XI. Créer un service web

Pour exposer notre service TwitterWeather et le rendre accessible via SOAP, nous allons ajouter une interface le décrivant. Nous nommerons cette interface "TwitterWeather". Notez l'utilisation de l'annotation @Service pour indiquer que l'interface Java sera utilisée comme contrat pour le service SCA. Voici l'interface qu'implémentera alors la classe Orchestration.

@Service
public interface TwitterWeather {
	String getWeatherForUser();
}
On ajoute ensuite la définition du service au niveau du composite.

<service name="tw" promote="orchestration/TwitterWeather">
	<binding.ws uri="http://localhost:8080/TwitterWeather"/>
</service>
Le service "tw" sera ainsi accessible soit via un appel { parti d'un client SOAP, soit localement.

Il ne nous reste plus qu'à compiler et exécuter notre intégration de service implémentée avec la technologie SCA. Pour créer le jar de l'application, nous appelons FraSCAti avec la commande de compilation:

% frascati compile src myWeathe
L'exécution est ensuite réalisée grâce à la commande "run". On précisera les noms du service (option –s) et de la méthode (option –m) à appeler ainsi que le chemin vers le jar de l'application.

% frascati run myWeather -libpath myWeather.jar -s tw -m getWeatherForUse

XII. Conclusion

Nous avons illustré que SCA permet de construire très rapidement des architectures orientées services pouvant utiliser différentes technologies de communication. Nous avons réalisé une petite application, en quelques lignes de code, réalisant une orchestration entre un service SOAP et une ressource REST. Toutefois SCA et FraSCAti ne se limitent pas à cet usage. Dans un prochain article nous irons plus loin avec FraSCAti. Nous utiliserons ses capacités réflexives et son interface d'administration puissante pour montrer, avec un script ou en quelques clics, qu'il est possible de modifier le comportement d'une application SCA, de modifier sa configuration ou d'exposer les services d'une application encore plus rapidement.



               Version PDF (Miroir)   Version hors-ligne (Miroir)

Valid XHTML 1.0 TransitionalValid CSS!

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2012 Michel Dirix. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Responsables bénévoles de la rubrique Java : Mickael Baron - Robin56 -