author
Le projet Apache Camel est un framework d’intégration basé sur l’implémentation de patterns d’intégration d’entreprise connus. Il permet d’implémenter des règles de routage et de médiation à partir d’un DSL Java ou bien via des configurations Spring au format Xml.
Apache Camel utilise la notion d’URIs, ce qui permet de travailler facilement avec différents types de transport ou modèles d’échange de messages, tels que HTTP ou JMS. De la même manière, Apache Camel est capable de travailler avec différents formats de données (Csv, Xml, Json, …).
L’utilisation des composants fournis out of the box permet de travailler avec de nombreux protocoles et formats de données. Mais qu’en est-il lorsqu’un connecteur vient à manquer?
Pour répondre à cette question, le projet Apache Camel propose une API complète permettant d’implémenter soi-même des composants adaptés à son besoin.
Objectif
L’objectif de cet article est de présenter comment initier le développement d’un composant Apache Camel.
Pour cela, nous mettrons en place un composant qui permettra de dialoguer avec l’Apple Push Notification Service, dans le but d’envoyer des notifications aux différents terminaux Apple (iPad, iPhone, iPod Touch).
Le composant proposera à la fois des endpoints de type producer et de type consumer qui permettrons respectivement d’envoyer des notifications et de lire un flux feedback d’informations en provenance de l’APNS.
En pré-requis, un ensemble de endpoints devra utiliser une même instance de la classe ApnsService proposée par la librairie java-apns, qui permet de dialoguer avec les serveurs d’Apple. La firme à la pomme préconise en effet de créer un nombre limité de connexions, et de réutiliser celles-ci pour communiquer avec ses serveurs. Nous utiliserons également le scheme apns pour déclarer les URIs qui représenteront les endpoints gérés par nos composants.
Présentation de l’APNS
L’Apple Push Notification Service est disponible pour les applications destinées aux iPhones, iPads et iPods touch. Il permet d’envoyer des notifications de 3 types : texte, image ou badge.
Pour envoyer une notification, un provider (une application serveur en général) doit en premier lieu envoyer la notification à l’Apple Push Notification Service qui se chargera à son tour de diffuser la notification aux terminaux concernés.
La notification est composée d’un token (identifiant unique d’un terminal) et d’un payload (contenu de la notification).
L’APNS propose en complément de l’envoi de notifications, un flux feedback d’informations permettant de connaître la liste des terminaux pour lesquels les notifications n’ont pu être délivrées de façon répétée (généralement, lorsque l’application a été désinstallée).
Pour qu’une application iOS soit en mesure de recevoir des notifications, elle doit en premier lieu fournir à l’application serveur (celle qui va envoyer les notifications aux serveurs Apple) toutes les informations nécessaires notamment son token d’identification. Cette opération peut-être réalisée, par exemple, via un simple appel HTTP.
API Java de connexion à l’APNS
De nombreux projets permettent de dialoguer avec l’APNS via différents langages de programmation. Actuellement deux implémentations existent pour le langage Java :
Historiquement, l’implémentation javapns est apparue avant java-apns. Cependant nous choisirons d’utiliser la librairie java-apns qui a pour avantage de proposer des fonctionnalités complètes (gestion de pool de connections, capacité de reconnexion, …), ainsi qu’une API élégante et différentes facilités d’écriture de tests unitaires.
Les endpoints Camel
Le développement d’un endpoint Apache Camel implique d’implémenter une ou plusieurs des méthodes suivantes selon les besoins :
Méthode | Description |
---|---|
createProducer() | Crée un producer permettant d'envoyer des messages à un endpoint |
createConsumer() | Crée un consumer implémentant le pattern Event Driven Consumer pour consommer des messages depuis un endpoint |
createPollingConsumer() | Crée un consumer implémentant le Polling Consumer pour consommer des messages depuis un endpoint |
L’Event Driven Consumer
Ce modèle événementiel de consommation des messages correspond au modèle de consommation par défaut des messages par les composants Camel.
Le Polling Consumer
Le polling consumer propose 3 types de méthodes:
Méthode | Description |
---|---|
receive() | Attend qu'un échange soit disponible et le retourne (potentiellement indéfiniment) |
receive(long) | Attend un échange jusqu'à un timeout défini. Renvoie null si aucun échange n'a été reçu dans le temps imparti |
receiveNoWait() | Tente de recevoir un message sans attendre de timeout et retourne null si aucun échange n'est disponible |
Le composant camel-jms implémente cette notion de polling-consumer pour s’intégrer à Apache Camel.
Générer un squelette de composant
Partir de zéro pourrait s’avérer compliqué. Heureusement le projet Apache Camel met à disposition l’archétype Maven: camel-artefact-component.
mvn archetype:create
-DarchetypeGroupId=org.apache.camel.archetypes
-DarchetypeArtifactId=camel-archetype-component
-DarchetypeVersion=2.3.0
-DgroupId=org.apache.camel
-DartifactId=camel-apns
L’exécution de la ligne de commande précédente va créer un squelette de composant sur lequel s’appuyer pour développer notre composant:
L’archétype va générer la structure nécessaire au développement du composant Camel. Cependant il sera nécessaire de personnaliser le composant nouvellement créé pour qu’il corresponde au nommage souhaité :
- ‘META-INF/services/<PACKAGE_NAME>/direct’ devra être renommé selon le scheme de l’URI de votre composant (Dans notre cas: ‘apns’).
- Les différentes classes générées seront préfixées par ‘Apns’ plutôt que ‘Direct’.
Il est possible de supprimer les classes qui ne seraient pas utilisées dans le cas où le composant serait uniquement destiné à consommer des messages ou à bien en produire.
Après renommage, le résultat obtenu doit être le suivant :
Importer son composant dans Eclipse
Pour cela, il est possible d’utiliser la commande suivante:
mvn eclipse:eclipse
Le fichier pom.xml
Il est conseillé d’hériter du projet parent camel-parent:
<parent>
<groupid>org.apache.camel</groupid>
<artifactid>camel-parent</artifactid>
<version>2.4.0</version>
</parent>
Le composant camel-parent déclare en effet un certain nombre de dépendances nécessaires, ainsi que le type bundle qui permet d’OSGifier son composant. Ceci permettra aux utilisateurs/développeurs de le déployer dans un conteneur OSGi, tel qu’Apache ServiceMix.
Nous allons donc déclarer le packaging du composant, ainsi que différentes propriétés nécessaires à l’OSGificiation comme suit:
<packaging>bundle</packaging>
...
<properties>
...
<!-- OSGi bundles properties -->
<camel .osgi.import.pkg><strong></strong></camel>
<camel .osgi.private.pkg>!</camel>
<camel .osgi.export>${camel.osgi.export.pkg}*;version=${camel.osgi.export.version}</camel>
<camel .osgi.export.version>${project.version}</camel>
<camel .osgi.import>${camel.osgi.import.pkg}</camel>
<camel .osgi.symbolic.name>${groupId}.${artifactId}</camel>
</properties>
Il est également nécessaire de déclarer les dépendances Camel dont nous aurons besoin, ainsi que les dépendances nécessaires à l’implémentation du composant:
<dependencies>
...
<!-- Camel -->
<dependency>
<groupid>org.apache.camel</groupid>
<artifactid>camel-core</artifactid>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupid>org.apache.camel</groupid>
<artifactid>camel-spring</artifactid>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupid>org.apache.camel</groupid>
<artifactid>camel-test</artifactid>
<version>${camel.version}</version>
<scope>test</scope>
</dependency>
...
<!-- APNS -->
<dependency>
<groupid>com.notnoop.apns</groupid>
<artifactid>apns</artifactid>
<version>${apns.version}</version>
<exclusions>
<exclusion>
<groupid>ch.qos.logback</groupid>
<artifactid>logback-classic</artifactid>
</exclusion>
</exclusions>
</dependency>
...
</dependencies>
Le projet Apache Camel propose le plugin camel-maven-plugin que nous allons déclarer dans notre fichier pom. Celui-ci permet de lancer en ligne de commande une instance standalone d’Apache Camel et de démarrer les routes qui sont déclarées dans le classpath via le fichier Spring suivant: ‘META-INF/spring/camel-context.xml’.
<!-- allows the route to be ran via \'mvn camel:run\' -->
<plugin>
<groupid>org.apache.camel</groupid>
<artifactid>camel-maven-plugin</artifactid>
<version>${camel.version}</version>
</plugin>
Plusieurs entrées repository et pluginReposity doivent également être déclarées dans le pom afin que Maven puisse importer différentes dépendances et plugins nécessaires à notre projet:
<repositories>
<repository>
<id>open.iona.m2</id>
<name>IONA Open Source Community Release Repository</name>
<url>http://repo.open.iona.com/maven2</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
<releases>
<enabled>true</enabled>
</releases>
</repository>
<repository>
<id>open.iona.m2-snapshot</id>
<name>IONA Open Source Community Snapshot Repository</name>
<url>http://repo.open.iona.com/maven2-snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</repository>
<!-- java-apns repository -->
<repository>
<id>notnoop-repos</id>
<url>http://notnoop.github.com/m2-repo</url>
</repository>
...
<repository>
<id>apache.incubating.releases</id>
<name>Apache Incubating Release Distribution Repository</name>
<url>http://people.apache.org/repo/m2-incubating-repository</url>
</repository>
</repositories>
<pluginrepositories>
<pluginrepository>
<id>open.iona.m2</id>
<name>IONA Open Source Community Release Repository</name>
<url>http://repo.open.iona.com/maven2</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
<releases>
<enabled>true</enabled>
</releases>
</pluginrepository>
<pluginrepository>
<id>open.iona.m2-snapshot</id>
<name>IONA Open Source Community Snapshot Repository</name>
<url>http://repo.open.iona.com/maven2-snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</pluginrepository>
<pluginrepository>
<id>maven-repository.dev.java.net</id>
<name>Java.net Maven 2 Repository</name>
<url>http://download.java.net/maven/2</url>
</pluginrepository>
</pluginrepositories>
Conclusion
Nous avons vu dans cette première partie comment initier le développement d’un composant Camel à l’aide de l’archétype Maven camel-archetype-component.
Dans un prochain billet, nous verrons comment implémenter les différentes classes d’un composant Camel. Puis nous conclurons dans une troisième et dernière partie, par la présentation des méthodes permettant de tester notre composant afin de fournir un livrable de qualité.
Liens utiles
Le site google code du composant camel-apns présenté dans cet article:
Parties suivantes de l’article :