Les besoins des projets informatiques sont sujets aux changements dont ceux relatifs à l'intégration avec des systèmes tiers. Le fait d'être en mesure de répondre rapidement à ces besoins pourrait devenir critique pour la réussite des projets, d'où, l’importance de la mise en place d’un processus de développement le permettant. Heureusement, l’EAI (Enterprise Application Integration) nous livre tout le savoir, les bonnes pratiques et les moyens technologiques qui servent à créer des solutions d'intégration extensibles et entretenues en mode productif.
Cependant, la plupart des solutions d'intégration nous posent un dilemme : Bien qu'elles soient riches en fonctionnalités et peuvent être assez productives pour les projets de grande envergure et à environnements exigeants, elles nécessitent malgré tout de gros investissements lors de l'apprentissage du système, son déploiement et sa maintenance.
Voilà pourquoi, face à de simples exigences d'intégration, les solutions ad hoc semblent être très attrayantes. Cependant, ces solutions deviennent difficiles à maintenir et contre productives, lorsque les besoins en intégration augmentent. L'utilisation des bonnes pratiques EAI permet la résolution de ce problème. Cependant, leur mise en œuvre exige des efforts et des connaissances approfondies pour les faire proprement. Le chemin le plus simple au départ risque alors de devenir plus tard une impasse.
Comment peut-on être productif face à des tâches d'intégration à la fois simples et complexes, tout en évitant dès le départ de lourds investissements ? Dans cet article, je vous montrerai qu’Apache Camel propose déjà une solution et je vais essayer de démontrer qu’il peut relever les défis d’intégration complexes permettant ainsi de tirer profit des meilleures pratiques EAI tout en étant facile à adapter et à maîtriser. Dans ce contexte, Camel permet de se concentrer sur les valeurs métiers sans vous soucier des complexités techniques de certains frameworks.
Je vais illustrer cela à travers des exemples concrets de problèmes d'intégration typiques et voir comment Camel peut nous aider à les résoudre. Ces exemples seront présentés dans le cadre d'une solution d'intégration simple au départ, mais au fil du temps, de nouveaux besoins d'intégration vont surgir et introduire plus de complexité. À chaque fois, on va étudier comment Camel serait capable de répondre à ces besoins en se concentrant sur la gestion de la complexité tout on essayant de rester productif.
À mon avis, le choix d’Apache Camel vient du fait qu’il offre une alternative simple et efficace à plusieurs produits ESB comme Service Mix, Mule ESB, OpenESB et JBossESB. Son concurrent direct est probablement Spring Integration qui s’avère être une bonne piste à envisager, surtout si le projet est déjà basé sur des technologies SpringSource. Mais, il est aussi possible d’utiliser Camel et Spring de concert. Gunnar Hillert nous livre plus de détails sur ces alternatives ici.
Introduction Simple
Généralement, l’intégration est initialement simple. Prenons l'exemple d'un téléchargement de fichier depuis un serveur FTP vers un fichier local. À ce stade, la solution faite maison paraît la plus avantageuse; Examinons ça de plus près.
La solution maison pourrait ressembler à ceci :
public class FTPFetch {
public static void main(String[] args) {
FTPClient ftp = new FTPClient();
try {
ftp.connect("host"); // try to connect
if (!ftp.login("camel", "apache")) // login to server
{
ftp.disconnect();
return;
}
int reply = ftp.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
ftp.logout();
ftp.disconnect();
return;
}
ftp.changeWorkingDirectory("folder");
// get output stream for destination file
OutputStream output = new FileOutputStream("data/outbox/file.xml");
ftp.retrieveFile("file.xml", output); // transfer the file
output.close();
ftp.logout();
ftp.disconnect();
} catch (Exception ex) {
ex.printStackTrace();
} finally {
if (ftp.isConnected()) {
try {
ftp.disconnect();
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
}
}
}
La classe ClientFTP d’Apache Commons est utilisée dans cette solution. Comme il s’agit d’un simple client, c’est à nous d’établir une connexion FTP et de corriger les possibles erreurs. Mais, que faire si plus tard le fichier est modifié sur le serveur FTP ? J’imagine qu’il est nécessaire de planifier ce traitement afin de l'exécuter périodiquement.
Maintenant, si on jette un coup d'oeil sur Apache Camel, on constate que c’est un framework d'intégration conçu pour résoudre ce genre de problématiques tout en se basant sur les bonnes pratiques EAI. Camel peut être, à la fois, considéré comme une boîte à outils qui contient des composants d'intégration prêts à l'emploi et un environnement d'exécution personnalisé pour répondre aux besoins spécifiques en les combinant. Ci-dessous, un exemple qui permet de résoudre ce problème avec Camel :
public class CamelRunner{
public static void main(String args[]) throws Exception {
Main camelMain = new Main();
camelMain.enableHangupSupport(); //ctrl-c shutdown
camelMain.addRouteBuilder(new RouteBuilder() {
public void configure() {
from(
"ftp://host/folder?username=camel&password=apache&fileName=file.xml&delay=360000" )
.to("file:data/outbox");
}
});
camelMain.run(); //Camel will keep running indefinitely
}
}
Il est à noter que Camel considère les deux méthodes "from" et "to" comme étant des "routes" : l’itinéraire traversé par les données depuis la source jusqu’à la destination. En outre, les données ne sont pas échangées sous forme brute, mais plutôt encapsulées dans des messages qui contiennent les données en question. Ceci est assimilé à une enveloppe SOAP avec des sections pour le corps du message, des pièces jointes et des en-têtes.
Les sources et les destinations des messages sont nommés "endpoints" et c'est grâce à eux que Camel échange les données. On remarque que les arguments des méthodes "from" et "to" sont des chaînes formatées. Ces URI sont le moyen avec lequel on définit les "endpoints". Par conséquent, la façon avec laquelle nous informons Camel de ce qu'il faut faire, est de créer de manière déclarative les routes entre les endpoints et les enregistrer par la suite.
Le reste n'est qu’un superflu réutilisable à chaque fois qu’on veut ajouter d’autres itinéraires, ce qui simplifie clairement la communication avec un serveur FTP. Camel s’occupe des malaises de connexions FTP et permet d’interroger périodiquement le serveur une fois qu’il détecte des modifications puisqu’il est configuré à fonctionner indéfiniment.
Cette compacité et clarté du code proviennent de la DSL Camel : un Domain Specific Language (langage dédié) où EAI est le domaine. Cela signifie que contrairement à d'autres solutions, il n'y a pas de traduction à faire du domaine des problèmes EAI vers le domaine d'application Camel : les deux sont concrètement les mêmes. Cela contribue à garder la courbe d'apprentissage douce et facile à appréhender : lorsque vous avez compris votre problème d'EAI, ça sera simple pour le mettre en œuvre avec Camel.
Toutefois, le code que vous écrivez n’est pas la seule chose simplifiée : Tout ce qui est nécessaire pour que cela fonctionne sont les librairies camel-core. jar, camel-ftp. jar et leurs dépendances, en tout quelques MB de lignes de code. Cette classe main peut être exécutée depuis l’invite de commande sans avoir recours à un serveur d’applications qui engendrera plus de complexité. En effet, Camel est un framework si léger qu’il peut être intégré dans n'importe quel environnement. Argumenter le choix d'une solution faite maison principalement en s’appuyant sur le fait que les frameworks sont complexes n’est plus vrai : Camel est simple à comprendre, simple à utiliser et simple à exécuter.
Complexité croissante
Disons qu’on a maintenant à faire de plus en plus d'intégration. Non seulement, on devrait être capable de gérer plus d’intégration, mais également essayer de garder l’ensemble maintenable. Comment Camel pourrait faire face à cela ?
Plus de connexions implique plus de routes Camel. Ces nouvelles routes auront sans doute besoin de se connecter via d'autres endpoints tels que HTTP, JMS, SMTP, etc. Heureusement, Camel dispose d’une panoplie très vaste d’endpoints où chacun représente un code réutilisable que vous n'avez pas à écrire.
Il est clair que tôt ou tard, vous aurez besoin de quelque chose qui n'est pas sur la liste. La question sera alors : comment puis-je facilement intégrer mon propre code dans Camel ? Dans ce cas de figure, nous pouvons utiliser ce que Camel désigne par "Components". les Components définissent un contrat qui, lorsqu'il implémenté, sera manipulé comme tout autre endpoint invoqué à partir du DSL.
Désormais, on sait comment ajouter de plus en plus de routes, les connecter avec n'importe quel type de protocole offert ou non par Camel. Mais à un certain moment, les routes deviennent nombreuses et on se retrouve en train de se répéter. Le but est d’essayer de les réutiliser et envisager de diviser l’ensemble de la solution en lots séparés de différentes tailles.
La stratégie de Camel pour la réutilisation est basée sur des endpoints spéciaux, visibles uniquement à l’intérieur de Camel. Si vous avez besoin de réutiliser une partie d'une route existante, il est possible de la recomposer en deux parties reliées par un endpoint interne. Détail ci-dessous :
Initialement :
//original
from(“ftp://server/path”).
to(“xslt:transform.xsl”).
to(“http://server2/path”);
Aprés modification :
//receiving from internal endpoint d1
from(“direct:d1”).
to(“xslt:transform.xsl”).
to(“http://server2/path”);
//sending to d1
from(“ftp://server/path”).
to(“direct:d1”);
//also sending to d1
from(“file://path”).
to(“xslt:other-transformation.xsl”).
to(“direct:d1”);
Le critère de connexion à l’endpoint est du type "DIRECT". Les endpoints de ce type ne sont adressables qu’au sein d’un même contexte Camel. VM, est un autre type intéressant d’endpoint, adressable à partir d’autres contextes, à condition que les deux contextes fonctionnent sur la même instance de JVM.
Un contexte Camel est comme un conteneur pour les routes. Chaque fois qu’on exécute Camel, il instancie un contexte et cherche les routes en interne. Ainsi, quand on exécute Camel, on est en train d'exécuter cette instance de contexte.
Être capable d’adresser des routes dans d'autres instances de contexte Camel via VM s’avère très utile. Celà ouvre la possibilité de fragmenter votre solution en modules interconnectés d'une manière encore plus légère que via JMS, par exemple.
L’image ci-dessous présente les différentes routes désormais réparties entre les différentes instances de Camel, chacune fonctionne séparément sur la même instance JVM et échange les unes avec les autres à travers l’endpoint VM :
Notre solution est décomposée en modules. Ce qui permet de développer, déployer et exécuter n'importe quel autre module qui intéragit également avec "Consumer Context", indépendamment de "Producer Context1" ou "Producer Context2" ; Celà est essentiel pour que les solutions les plus vastes restent gérables.
À ce stade, il est peut-être judicieux d'utiliser un serveur d'applications capable d'exploiter pleinement la modularité. A moins que vous en utilisiez déjà un. Une approche très courante est alors de mettre Camel dans un WAR et de le déployer sous Tomcat. Il est également possible de le déployer sur un serveur d'applications Java EE comme JBoss, WebLogic ou WebSphere. D'autres options incluent aussi un conteneur OSGi ou même Google App Engine.
Maîtriser la complexité
Le volume n'est pas le seul axe sur lequel les applications peuvent grossir. Les routes peuvent également croître en complexité : les messages peuvent faire l'objet de divers quantités et types de transformations, de filtrage, d'enrichissement, de routage, etc... selon n’importe quel nombre de combinaisons. Afin de discuter de la manière dont Camel peut aider à cet égard, voyons en premier lieu, comment nous envisageons de faire face à des problèmes aussi complexes.
Les problèmes complexes existent dans tous les domaines, mais la stratégie générale pour les résoudre est généralement la même : diviser pour mieux régner. Essayer de décomposer le problème en sous problèmes plus simples à résoudre. Ces solutions seront combinées pour produire ensuite la solution totale par inversion de la décomposition.
Suite à l’observation, on constate que certains problèmes continuent d’être récurrents et c’est avec l'expérience qu’on identifie la solution la plus optimale : C’est ce qu’on désigne par modèles (Pattern). Les modèles d'EAI ont été catalogués par Gregor Hohpe et Bobby Woolf et publiés en ligne.
Les modèles EAI peuvent être très simples, représentés souvent par des opérations de base comme une transformation ou un filtrage. Ils peuvent également être combinés pour former des solutions plus complexes. Ceux-ci peuvent alors devenir eux-mêmes des modèles. Cette capacité découle du fait que tous les modèles d'EAI ont la même "interface" : les messages peuvent circuler depuis et vers un modèle. Ces modèles peuvent alors être chaînés entre eux en utilisant la sortie d'un modèle comme entrée de l'autre.
Grosso modo, cela implique que les problèmes d'EAI sont en fait juste une combinaison de modèles. Ce qui signifie que pour résoudre un problème EAI, aussi complexe soit-il, on est ramené à trouver la combinaison qui réponde à nos besoins. L’implémentation de modèles individuels peut bien sûr ramener à avoir beaucoup de complexité, mais ça reste un cas isolé et gérable.
Prenons un modèle concret comme exemple : le modèle de "Composed Message Processor" qui n’est autre qu’une combinaison de modèles plus basiques. Il est utilisé lorsque des parties du même message doivent être traitées par les différents composants. Ce modèle n'est pas directement mis en œuvre par Camel, mais ses sous-modèles le sont. Donc, c'est un exemple typique sur la façon dont les modèles peuvent être combinés par la DSL Camel.
Ci-dessous le diagramme du modèle. "Splitter" va diviser le message entrant en plusieurs parties, tandis que "Router" décidera à quel système les envoyer : soit "Widget Inventory" ou "Gadget Inventory". Ces systèmes peuvent être considérés comme étant des entités entreprises qui transforment et retournent les messages traités. "Aggregator" va recombiner les résultats dans un message sortant.
Ci-dessous l’implémentation avec Camel :
from("some:input")
.setHeader("msgId") //give each message a unique id based on timestamp
.simple("${date:now:S}")
.split(xpath("//item")) //split the message into parts (msgId is preserved)
.choice() //let each part be processed by the appropriate bean
.when( xpath("/item[@type='widget']") )
.to("bean:WidgetInventory")
.otherwise()
.to("bean:GadgetInventory")
.end()
.aggregate(new MyAggregationStrategy()) //collect the parts and reassemble
.header("msgId") //msgId tells us which parts belong together
.completionTimeout(1000L)
.to("some:output"); //send the result along
Dans cette implémentation, les "beans" sont en fait des POJO enregistrés sous le nom du bean via JNDI par exemple. De cette manière, il est possible de faire une logique personnalisée dans la route. MyAggregationStrategy est également un code personnalisé qui précise comment rassembler les parties du message traité.
Notez que les méthodes split, choice et aggregate correspondent directement aux modèles "Splitter", "Router" et "Aggregator". L’implémentation Camel de "Composed Message Processor" est essentiellement une représentation textuelle du diagramme ci-dessus. Il n'est pas nécessaire de penser la plupart du temps selon un contexte "Camel" mais juste selon EAI. Le résultat est que Camel reste relativement à l'écart, et l'accent peut être mis sur la compréhension du problème et l'identification des modèles appropriés. Ce qui contribue à améliorer la qualité globale de la solution.
Cependant, ce n'est pas toute la vérité. Camel a ses propres moyens pour faire les choses et sa propre logique derrière les coulisses. Il y aura des moments où l'inattendu se produit et vous serez laissés désemparés. Mais, ces revers devraient être analysés à la lumières du temps effectivement gagné en utilisant Camel : d'autres frameworks ont une courbe d'apprentissage abrupte et des comportements parfois bizarres, et utiliser des solutions faites maison signifie que vous réinventez la roue plutôt que réutiliser toutes les fonctionnalités offertes par Camel.
Aucun argument sur la gestion de la complexité et l’évolution de logiciels ne serait convainquant sans parler de tests unitaires. Camel peut être intégré pour être exécuté dans n'importe quelle autre classe comme il peut également fonctionner à l'intérieur d'un test unitaire.
Camel résout également l'une des choses les plus lourdes lors des tests d'intégration : devoir monter un serveur FTP ou HTTP pour pouvoir exécuter ses tests. Concrètement, on peut l’éviter en modifiant les routes existantes lors de l'exécution. Voici un exemple :
public class BasicTest extends CamelTestSupport {
// This is the route we want to test. Setup with anonymous class for
// educational purposes, normally this would be a separate class.
@Override
protected RouteBuilder createRouteBuilder() throws Exception {
return new RouteBuilder() {
@Override
public void configure() throws Exception {
from("ftp://host/data/inbox").
routeId("main").
to("file:data/outbox");
}
};
}
@Override
public boolean isUseAdviceWith() {
// Indicates we are using advice with, which allows us to advise the route
// before Camel is started
return true;
}
@Test
public void TestMe() throws Exception {
// alter the original route
context.getRouteDefinition("main").adviceWith(context,
new AdviceWithRouteBuilder() {
@Override
public void configure() throws Exception {
replaceFromWith("direct:input");
interceptSendToEndpoint("file:data/outbox")
.skipSendToOriginalEndpoint()
.to("mock:done");
}
});
context.start();
// write unit test following AAA (Arrange, Act, Assert)
String bodyContents = "Hello world";
MockEndpoint endpoint = getMockEndpoint("mock:done");
endpoint.expectedMessageCount(1);
endpoint.expectedBodiesReceived(bodyContents);
template.sendBody("direct:input", bodyContents);
assertMockEndpointsSatisfied();
}
}
AdviceWithRouteBuilder permet de modifier, via notre code, une route existante dans sa méthode de configuration sans modifier le code original. Dans ce cas, nous avons remplacé l'endpoint source avec un type DIRECT pour contourner la destination initiale par mockendpoint. De cette manière, on n’a pas besoin d'avoir un serveur FTP qui fonctionne réellement pour tester la route, même si elle est programmée pour télécharger les messages depuis FTP. La classe MockEndpoint fournit ainsi une API pratique pour la mise en place des tests unitaires de manière déclarative, semblable à jMock. Une autre grande particularité est le modèle utilisé pour envoyer facilement les messages à notre route en cours de test.
Se reposer sur Camel
Une importante caractéristique des solutions d'intégration, vu qu’elles sont des intermédiaires par lesquels tous les autres systèmes sont reliés, par nature sont potentiellement un unique point de défaillance. L'augmentation du nombre de systèmes connectés et des données échangées implique une tolérance moindre à toute forme de défaillance du système, aux pertes de données ou la dégradation des performances.
Même si cet article parle de Camel, une solution qui réponde à tous ces défis est hors de portée pour Camel seul. Cependant, il constitue un élément central d'une telle solution, car il contient toute la logique pour échanger les données avec les tiers. Il est donc important de savoir qu'il peut remplir ses fonctions, même dans ces rudes conditions.
Prenons un exemple pour illustrer comment ces exigences sont généralement respectées. Dans cet exemple, on a une file d'attente (queue) JMS dans laquelle les messages seront déposés par des systèmes externes. La tâche de Camel sera de récupérer ces messages, faire quelques traitements, puis les livrer à une file d'attente JMS sortante. Les files d'attente JMS peuvent être persistantes ainsi qu'hautement disponibles. Nous allons donc nous concentrer sur Camel et supposer que les systèmes externes peuvent "toujours" placer des messages sur la file d'attente entrante. Que se passera-t-il si Camel ne peut pas récupérer et traiter des messages assez vite avant le remplissage de la file ?
Notre objectif serait alors d’essayer de faire résister Camel aux défaillances du système et accroître ses performances, et nous le faisons en le déployant sur plusieurs serveurs, chacun exécutant une instance Camel connectée aux mêmes endpoints. Voir l'image ci-dessous :
Il s'agit en fait d'une implémentation d'un autre modèle EAI appelé "Competing Consumers". Ce modèle présente deux avantages : d'abord, les messages sont récupérés depuis la file d'attente par plusieurs instances et seront traités parallèlement, ce qui améliore les performances. Ensuite, si un serveur devient hors-service, les autres sont déjà en cours d'exécution et peuvent contribuer à la récupération des messages, afin que leur traitement se poursuive automatiquement et sans aucune intervention, ce qui améliore la résilience à l'échec.
Lorsqu'une instance Camel récupère un message, il n'est plus disponible pour les autres. Ce qui garantit l’unicité du traitement des messages. La charge de travail est ainsi distribuée sur les serveurs une fois que chaque serveur récupère les messages : les serveurs plus rapides peuvent traiter les messages à un rythme plus rapide et gère automatiquementplus de charge que les serveurs lents. C’est ainsi que nous pouvons réaliser la coordination nécessaire et la répartition du travail entre les instances Camel.
Cependant, il y a un élément qui manque : si un serveur tombe en panne lors du traitement d'un message, un autre doit reprendre son travail sinon le message sera perdu. De même, si tous les nœuds tombent en échec, les messages qui sont en cours de traitement ne doivent pas être perdus.
Pour que cela se fonctionne, on aura besoin des transactions. Avec les transactions, la file d'attente JMS va attendre un accusé de réception de l'instance qui a pris le message avant de le supprimer réellement. Si le serveur qui a récupéré le message échoue en cours du traitement, il n’y aura pas d'émission d'acquittement et éventuellement, la restauration du message se fera pour que ce dernier réapparaisse sur la file d'attente et être de nouveau disponible pour les instances qui fonctionnent. Si aucun serveur est en cours d'exécution, le message reste dans la file jusqu'à ce qu'un serveur soit à nouveau disponible.
Dans la terminologie Camel, cela signifie que les routes doivent être transactionnelles. Camel ne fournit pas lui-même les transactions mais fait appel plutôt à des solutions tierces. Cela permet de rester simple, tout en permettant la réutilisation des techniques éprouvées et de basculer facilement entre les divers modes d’implémentation.
À titre d'exemple, nous allons configurer un contexte Camel avec des transactions à l'intérieur d'un conteneur Spring. Notez que comme il s’agit d’exécution à l'intérieur de Spring, il est plus pratique d'utiliser la version de Spring XML de la DSL Camel au lieu de celle Java, même si elle est idéale pour les débutants.
Bien sûr, l'évolution de la DSL à mi-chemin signifie la refonte, il est donc important de migrer à bon escient et au moment opportun. Heureusement, Spring DSL fonctionne aussi à partir de tests unitaires, c’est ainsi que ces tests peuvent aider à faire la transition en toute sécurité car ils vont agir sur les routes indépendamment du type de DSL utilisé.
<beans //namespace declarations omitted >
//setup connection to jms server
<jee:jndi-lookup id="jmsConnectionFactory" jndi-name="ConnectionFactory">
<jee:environment>
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming.client
java.naming.provider.url=jnp://localhost:1099
</jee:environment>
</jee:jndi-lookup>
//configuration for the jms client, including transaction behavior
<bean id="jmsConfig" class="org.apache.camel.component.jms.JmsConfiguration">
<property name="connectionFactory" ref="jmsConnectionFactory"/>
<property name="transactionManager" ref="jmsTransactionManager"/>
<property name="transacted" value="true"/>
<property name="acknowledgementModeName" value="TRANSACTED"/>
<property name="cacheLevelName" value="CACHE_NONE"/>
<property name="transactionTimeout" value="5"/>
</bean>
//register camel jms component bean
<bean id="jboss" class="org.apache.camel.component.jms.JmsComponent">
<property name="configuration" ref="jmsConfig" />
</bean>
//register spring transactionmanager bean
<bean id="jmsTransactionManager"
class="org.springframework.jms.connection.JmsTransactionManager">
<property name="connectionFactory" ref="jmsConnectionFactory"/>
</bean>
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="jboss:queue:incoming"/>
<transacted/>
<log loggingLevel="INFO" message="processing started." />
<!-- complex processing -->
<to uri="jboss:queue:outgoing?exchangePattern=InOnly" />
</route>
</camelContext>
</beans>
Avec le tag , la route est marquée comme transactionnelle, Camel fera appel à cette route via les ressources de la transaction manipulées par le gestionnaire. En cas d'échec durant le traitement, le gestionnaire de transaction s'assurera que la transaction soit annulée et que le message réapparaisse dans la file d'attente entrante.
Cependant, toutes les routes ne peuvent pas être marquées transactionnelles car certains endpoints, FTP, par exemple, ne supportent pas les transactions. Heureusement, Camel dispose d’une gestion d’erreurs qui fonctionne même sans transactions. Un pattern particulièrement intéressant est le DeadLetterChannel, un gestionnaire d'erreurs qui implémente le modèle Dead Letter Channel. Ce modèle stipule que les messages qui ne peuvent pas ou ne devraient pas être livrés à leur destination, doivent être déplacés vers un autre endroit afin de ne pas encombrer le système. Le système de messagerie décidera alors que faire avec ces messages.
Par exemple, supposons que la livraison vers un endpoint comme un emplacement FTP échoue. Si DeadLetterChannel est configuré pour cette route, elle tentera d'abord et à plusieurs reprises de restituer le message. Si le problème persiste, le message est signalé comme "poison", ce qui signifie qu’il inutile et qu’il doit être retiré du système. Par défaut, Camel trace l’erreur et abandonne le message. Naturellement, ce mécanisme peut être personnalisé : ainsi, vous pouvez demander que Camel effectue 3 tentatives de livraisons puis de stocker le message dans une file d'attente JMS par la suite en cas d’échec. Et oui, le DeadLetterChannel peut être combiné avec les transactions intégrant ainsi le meilleur des deux.
Conclusion
D’habitude, avoir des intégrations non maintenables commence avec de simples besoins réalisés en mode ad-hoc. Ces approches ne s'adaptent pas aux exigences plus rigoureuses, et présentent un investissement considérable. Cependant, investir très tôt dans des EAI spécialisés porte un grand risque en raison de la complexité qu'ils apportent souvent et ont une forte chance de ne pas être rentables.
Dans cet article, j'ai étudié une troisième option : utiliser Camel afin de garder les choses simples au début, tout en étant capable de répondre aux exigences élevées plus tard. À cet égard, je crois que Camel s'est montré tout à fait à la hauteur : il a une courbe d'apprentissage facile et il est simple d'utilisation et de déploiement. En plus, dès le départ, les investissements sont mineurs. Même dans de simples cas, l'apprentissage Camel peut effectivement être plus rapide par rapport à l'intégration de solutions faits-maison. Par conséquent, Camel est vraiment bon et représente un point d’entrée à faible coût dans le monde des EAI.
De plus, je pense que Camel est un bon choix pour les demandes importantes dans le cadre de solutions d'intégration. En plus de la productivité, il est extensible, réutilisable et possède une élégante intégration DSL. Cette DSL permet de réduire sa complexité d'utilisation, de sorte que vous pouvez vous concentrer sur le vrai problème. Lorsque vous atteignez les limites de ce qui peut être fait avec le standard, Camel dispose d'une infrastructure de plugins pour les Components et l’invocation des POJO permettant de prendre les choses en main.
Le support des tests unitaires avec Camel est génial. Camel fait aussi ses preuves dans le cadre de solutions à haute disponibilité.
Dans l'ensemble, Camel est réellement une excellente option pour les intégrations de n’importe quelle taille ou complexité : Il est possible de commencer petit et simple avec un investissement initial minime et de rester confiant en sachant que pour les besoins d'intégration plus complexe, Camel fournira encore la solution. Entre-temps, il est possible de rester productif tout en bénéficiant d'un cadre d'intégration mature et complet.
À propos de l'auteur
Frans van der Lek est un ingénieur en informatique avec une expérience dans le web, le mobile, Internet et les solutions EAI. Il est actuellement employé par Capgemini aux Pays-Bas où il travaille en tant que concepteur, développeur et prescripteur sur un certain nombre de projets. S’il n'est pas en train d’écrire ou de penser à un logiciel, il bénéficie d'un bon livre, une tasse de café ou il passe du temps avec sa famille.