Introduction aux EIPs (suite) : mise en pratique avec Spring Integration

Passons à la mise en pratique avec Spring Integration !

Comme nous l’avons vu dans l’article précédent, Camel prends quelques libertés vis-à-vis des concepts des EIPs, les channels sont implicites et l’implémentation des routes modélisées par EIPs peuvent se révéler assez différentes. Spring Integration au contraire, est à la base une pure implémentation des EIPs, chaque élément retrouvé dans notre modélisation va être retranscrite point par point et enrichie :

Ainsi chaque endpoint et channel (aller comme retour) sont retranscrits dans Spring Integration, nous aurons donc :

  • Un endpoint http d’entrée
  • Un endpoint s’occupant de l’appel http au service Google
  • 2 endpoints transformant les messages
  • 4 channels liant les endpoints

Chacun de ces composants seront définis comme bean spring, on retrouvera donc une configuration et une architecture classique des applications spring, très modulaire facilitant la réutilisation.

Toute la configuration se fait par fichier spring XML, les endpoints et channels développés peuvent néanmoins être intégrés et configurés dans le conteneur Spring à l’aide d’annotations.

Les Channels

Contrairement à Camel, les channels sont explicites, ils peuvent être de type publish/subscribe, queue, direct… Nous allons utiliser seulement les directs dans notre exemple :

<!-- Inbound/Outbound Channels -->
<int:channel id="spellJsonRequest" />
<int:channel id="spellXmlRequest" />
<int:channel id="spellXmlResponse" />
<int:channel id="spellJsonResponse" />

Endpoint http : inbound-gateway

Afin de réaliser notre endpoint http, Spring Integration propose le endpoint http inbound gateway. C’est un endpoint producteur de messages. Evidemment, Spring se base sur Spring MVC pour créer ce endpoint :

<int-http:inbound-gateway id="inboundEmployeeSearchRequestGateway"
	supported-methods="GET" request-channel="spellJsonRequest"
	reply-channel="spellJsonResponse" mapped-request-headers="null"
	mapped-response-headers="Return-Status, Return-Status-Msg, HTTP_RESPONSE_HEADERS"
	path="/spell/{word}" reply-timeout="50000">
 <int-http:header name="word" expression="#pathVariables.word" />
</int-http:inbound-gateway>

Cette configuration créé un endpoint à l’adresse /spell qui est rajouté à la DispatcherServlet de Spring MVC. Le mapped-request-headers permet de spécifier quel headers http sont mappés sur les headers du message du flux. Les request et reply channel permettent de brancher le endpoint aux channels. Le header est enrichi du pathVariable pour la suite.

Template velocity

Afin de garder la même logique que pour l’implémentation Camel, la requête XML est générée à l’aide d’un template Velocity. Il n’existe pas de Transformer velocity natif sous Spring Integration, mais il est simple d’en implémenter un :

@Component("velocityTransformer")
public class VelocityTransformer {
	@Value("request.vm")
	private String templateLocation;

	@Autowired
	private VelocityEngine velocityEngine;

	@Transformer
	public String transform(@Header("word") String word)
			throws VelocityException, IOException {
		Map map = new HashedMap();
		map.put("word", word);
		return VelocityEngineUtils.mergeTemplateIntoString(velocityEngine,
				templateLocation, map);
	}
}

A noter l’utilisation des Annotations, la méthode @Transformer permet d’injecter directement dans ses paramètres d’appel des valeurs du header « word ».
Le transformer est ensuite branché sur la route :

<int:transformer input-channel="spellJsonRequest"
		output-channel="spellXmlRequest" ref="velocityTransformer" />

Endpoint http : outbound-gateway

Un endpoint permettant les appels http est disponible, il est basé sur le RestTemplate de Spring :

<int-http:outbound-gateway request-channel="spellXmlRequest"
		expected-response-type="com.sedona.simple.SpellResult" reply-channel="spellXmlResponse"
		url="http://www.google.com/tbproxy/spell?lang=en" http-method="POST" />

L’url cible est simplement précisée avec la méthode http utilisée. L’expected-response-type permet de convertir directement la réponse XML en objet Java grâce à un mapping JaxB. Aucune configuration supplémentaire est nécessaire, seule la classe SpellResult est développée :

@XmlRootElement(name = "spellresult")
public class SpellResult {
	private String c;

	public String getC() {
		return c;
	}

	public void setC(String c) {
		this.c = c;
	}
}

 Transformation Objet vers Json

Un transformer natif est disponible à partir du moment où la librairie Jackson est disponible dans le classpath. Il suffit ensuite de le déclarer :

<int:object-to-json-transformer
	input-channel="spellXmlResponse" output-channel="spellJsonResponse" content-type="application/json" />

Les headers de réponse du service google étant par défaut mappés, attention à bien changer le content-type de xml à json.

Configuration et déploiement

La solution se basant sur du spring MVC, une configuration spring classique (ContextLoaderListener dans le web.xml) et un déploiement dans un conteneur de servlet (tomcat) sont nécessaires.

Conclusion

Comme déjà précisé, Spring Integration est plus fidèle aux EIPs, la route configurée correspond exactement à la conception de notre flux, l’implémentation est donc plus implicite et demande moins de connaissance du framework et de ses composants, on profite en plus des forces de ce framework (Spring MVC, système de conversion etc…).
Néanmoins Camel est plus pragmatique, ses composants sont plus riches et le développement et la configuration a été plus rapide qu’avec Spring.

You may also like...

Laisser un commentaire