Camel SQL composant: Composant Camel-SQL

Ce billet illustre l'emploi du composant Camel-SQL.
camel-logo.png

Dans notre démo le composant camel-sql s'appuie sur une datasource déclarée dans spring.

La démo est réalisée en cinq étapes:

I. CONFIGURER LE POM DU PROJET

II. CONFIGURER SPRING

III. DESSINER LA ROUTE CAMEL

IV. CONFIGURER L'ENVIRONNEMENT

V. TESTER

Passons à la pratique.

Voici les étapes de la démo qui utilise java 7, spring 3, camel 2.10:

ETAPE 1. CONFIGURER LE POM

Pour utiliser le composant camel-sql on a besoin uniquement de cette déclaration:

<dependency>
 <groupId>org.apache.camel</groupId>
 <artifactId>camel-sql</artifactId>
 <version>2.10.2</version>
</dependency>

Voici le pom.xml en entier:

<properties>
	<!-- Versions Dependances -->
	<commons-beanutils-version>1.8.3</commons-beanutils-version>
	<commons-codec-version>1.6</commons-codec-version>
	<commons-collections-version>3.2.1</commons-collections-version>
	<commons-lang-version>2.6</commons-lang-version>
	<commons-digester-version>2.1</commons-digester-version>
	<javassist-version>3.12.1.GA</javassist-version>
	<cglib-version>2.2.2</cglib-version>

	<!-- Log -->
	<log4j-version>1.2.17</log4j-version>
	<slf4j-version>1.6.6</slf4j-version>

	<!-- Spring -->
	<spring-version>3.1.2.RELEASE</spring-version>
	<!-- camel-version -->
	<camel-version>2.10.2</camel-version>
	<!-- Versions Dependances de test -->
	<junit-version>4.10</junit-version>

	<!-- PostgresSql -->
	<postgresql-version>9.1-901-1.jdbc4</postgresql-version>

</properties>

<dependencies>

	<dependency>
		<groupId>commons-dbcp</groupId>
		<artifactId>commons-dbcp</artifactId>
		<version>1.2.2</version>
	</dependency>
	<dependency>
		<groupId>commons-pool</groupId>
		<artifactId>commons-pool</artifactId>
		<version>1.2</version>
	</dependency>

	<!-- dep transitive de JavConfig see @Configuration -->
	<dependency>
		<groupId>javassist</groupId>
		<artifactId>javassist</artifactId>
		<version>${javassist-version}</version>
		<scope>compile</scope>
	</dependency>
	<dependency>
		<groupId>cglib</groupId>
		<artifactId>cglib</artifactId>
		<version>${cglib-version}</version>
		<scope>compile</scope>
	</dependency>

	<!-- spring-core -->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-core</artifactId>
		<version>${spring-version}</version>
		<scope>compile</scope>
	</dependency>
	
	<!-- spring-expression -->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-expression</artifactId>
		<version>${spring-version}</version>
		<scope>compile</scope>
	</dependency>
	<!-- spring-asm -->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-asm</artifactId>
		<version>${spring-version}</version>
		<scope>compile</scope>
	</dependency>
	<!-- spring-beans -->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-beans</artifactId>
		<version>${spring-version}</version>
		<scope>compile</scope>
	</dependency>
	<!-- spring-context -->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-context</artifactId>
		<version>${spring-version}</version>
		<scope>compile</scope>
	</dependency>
	<!-- spring-context-support -->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-context-support</artifactId>
		<version>${spring-version}</version>
		<scope>compile</scope>
	</dependency>
	<!-- postgres -->
	<dependency>
		<groupId>postgresql</groupId>
		<artifactId>postgresql</artifactId>
		<version>${postgresql-version}</version>
		<scope>compile</scope>
	</dependency>
	<!-- CAMel -->
	<dependency>
		<groupId>org.apache.camel</groupId>
		<artifactId>camel-core</artifactId>
		<version>${camel-version}</version>
	</dependency>
	<!--    camel-sql -->		
	<dependency>
		<groupId>org.apache.camel</groupId>
		<artifactId>camel-sql</artifactId>
		<version>${camel-version}</version>
	</dependency>
	<dependency>
		<groupId>org.apache.camel</groupId>
		<artifactId>camel-spring</artifactId>
		<version>${camel-version}</version>
	</dependency>
	<!-- camel-spring-config -->
	<dependency>
		<groupId>org.apache.camel</groupId>
		<artifactId>camel-spring-javaconfig</artifactId>
		<version>${camel-version}</version>
	</dependency>
	<!-- logging -->
	<dependency>
		<groupId>org.slf4j</groupId>
		<artifactId>slf4j-api</artifactId>
		<version>1.6.6</version>
	</dependency>
	<dependency>
		<groupId>org.slf4j</groupId>
		<artifactId>slf4j-log4j12</artifactId>
		<version>1.6.6</version>
	</dependency>
	<dependency>
		<groupId>log4j</groupId>
		<artifactId>log4j</artifactId>
		<version>1.2.17</version>
	</dependency>
	<!-- logging -->
	<dependency>
		<groupId>commons-logging</groupId>
		<artifactId>commons-logging</artifactId>
		<version>1.1</version>
		<scope>runtime</scope>
	</dependency>
	<!-- CAMEL -test-spring  -->
	<dependency>
		<groupId>org.apache.camel</groupId>
		<artifactId>camel-test-spring</artifactId>
		<version>${camel-version}</version>
		<scope>test</scope>
	</dependency>
	<!-- spring-test -->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-test</artifactId>
		<version>3.1.2.RELEASE</version>
		<scope>test</scope>
	</dependency>
	<!-- DEPENDANCES DE TESTS junit -->
	<dependency>
		<groupId>junit</groupId>
		<artifactId>junit</artifactId>
		<version>${junit-version}</version>
		<scope>test</scope>
	</dependency>
 <!-- commons beanutils -->
 <dependency>
	<groupId>commons-beanutils</groupId>
	<artifactId>commons-beanutils</artifactId>
	<version>${commons-beanutils-version}</version>
 </dependency>
	<!-- commons codec -->
	<dependency>
		<groupId>commons-codec</groupId>
		<artifactId>commons-codec</artifactId>
		<version>${commons-codec-version}</version>
		<scope>compile</scope>
	</dependency>
	<!-- -->
	<dependency>
		<groupId>commons-collections</groupId>
		<artifactId>commons-collections</artifactId>
		<version>${commons-collections-version}</version>
		<scope>compile</scope>
	</dependency>
	<dependency>
		<groupId>commons-lang</groupId>
		<artifactId>commons-lang</artifactId>
		<version>${commons-lang-version}</version>
		<scope>compile</scope>
	</dependency>
	<!-- common DIGESTER -->
	<dependency>
	 <groupId>commons-digester</groupId>
	 <artifactId>commons-digester</artifactId>
	 <version>${commons-digester-version}</version>
	</dependency>
</dependencies>
<build>
 <defaultGoal>install</defaultGoal>
 <plugins>
  <plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-compiler-plugin</artifactId>
  <version>2.5.1</version>
  <configuration>
 	<source>1.7</source>
	<target>1.7</target>
  </configuration>
</plugin>
<!-- 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>
</plugins>
</build>
</project>

ETAPE 2. CONFIGURER SPRING

La configuration de spring est centrée dans le fichier xml suivant:


<context:property-placeholder location="db.properties"/>
<context:component-scan base-package="fr.netapsys.camel"/>
<camel:camelContext id="camel1"
	xmlns="http://camel.apache.org/schema/spring">
	<camel:package>fr.netapsys.camel.routes</camel:package> 
</camel:camelContext>

<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" 
     destroy-method="close">
    <property name="driverClassName" value="${bd.driverClassName}"/>
    <property name="url" value="${bd.url}"/>
    <property name="username" value="${bd.username}"/>
    <property name="password" value="${bd.password}"/>
    <property name="defaultAutoCommit" value="true" />
</bean>

Explications:

Un fichier (placeholder pour spring) contient les paramètres (propriétés) de définition de la datasource nommée myDataSource.

Les routes camel sont auto-injectées en les scannant dans le répertoire de <camel:package>.

Les autres composants à injecter par spring sont scannés depuis le <context:component-scan base-package.

Le fichier db.properties est donné à l'étape 4.

ETAPE 3. DESSINER LA ROURE CAMEL-SQL

La route camel permettant de rechercher ( et d'insérer) des données depuis (dans) la table CLIENTS de la base s'écrit :

public class BatchSqlRoute extends RouteBuilder {
 public void configure() {
  //handled(false) tell camel propagate the exception to caller.
  onException(SQLException.class).handled(false).
  log(LoggingLevel.ERROR,">>>Error in:  ${body},\n ${exception}");
        	
  //using SqlEndpoint select from CLIENTS
 from("direct:simpleSelect")
 .to("sql:SELECT * FROM CLIENTS 
           WHERE id=# ?dataSourceRef=myDataSource")
 .end();

 //using SqlEndpoint to insert into CLIENTS
from("direct:insertSql") 
.to("sql:INSERT INTO CLIENTS
     (id, nom,prenom) values (#,#,#)?dataSourceRef=myDataSource")
.end();
 }
}

Noter que chacune des deux chaînes de .to doivent être sur la même ligne.

Vous pouvez constater que deux endpoints sont définis :

  • le premier permet d'effectuer un simple select en fonction de l'id du client.
  • le second effectue une insertion des trois champs de la table CLIENTS.

ETAPE 4. CONFIGURER L'ENVIRONNEMENT

A) Fichier db.properties

Ce fichier (placeholder de spring) contient les paramètres d'accès à la base postgres qu'il faudrait adapter.

#params db postgres
bd.driverClassName=org.postgresql.Driver
bd.url=jdbc:postgresql://localhost:5432/test
bd.username=XXXXXX
bd.password=XXXX

B) Script de création de la table CLIENTS

Voici le script pour créer la table clients

CREATE TABLE clients(
  id bigint PRIMARY KEY NOT NULL,
  nom varchar(255),
  prenom varchar(255)
);
CREATE UNIQUE INDEX clients_prim_key ON clients(id);

ETAPE 4. TESTER AVEC JUNIT

package fr.netapsys.camel.tests;

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import java.util.List;
import java.util.Map;

import org.apache.camel.Endpoint;
import org.apache.camel.Exchange;
import org.apache.camel.ProducerTemplate;
import org.junit.Test;
import org.springframework.dao.DuplicateKeyException;

public class TestBatchSqlRoute extends TestParent {
	final static int ID_2_CREATE=110;
	
@Test 
public void testInsertSql() throws Exception {
	ProducerTemplate template = camelCtx.createProducerTemplate();
	Endpoint endpoint = camelCtx.getEndpoint("direct:insertSql");
	Exchange exchange = endpoint.createExchange();
	final long id = ID_2_CREATE+1001;
	final String nom = "toto"+id;
	final String prenom = "prenom"+id;
	exchange.getIn().setBody(new Object[]{id,nom,prenom});
	Exchange exchangeOut = template.send(endpoint, exchange);
	assertNotNull(exchangeOut);
	assertNotNull(exchangeOut.getOut());
	assertTrue(exchangeOut.getException() ==null ||
         exchangeOut.getException() instanceof DuplicateKeyException);
	if(exchangeOut.getException() !=null)
	 assertTrue(
          exchangeOut.getException() instanceof DuplicateKeyException);
   }
}

Lancer la commande mvn test pour voir une ligne s'insérer dans la table CLIENTS.

Le test suivant vous permet de recherche un client par son id.

Vérifier que l'id passé existe en base.

@Test 
public void testSelectSql() throws Exception {

	final static int ID_4_SELECT=110;
	ProducerTemplate template = camelCtx.createProducerTemplate();
	
	Endpoint endpoint = camelCtx.getEndpoint("direct:simpleSelect");
	Exchange exchange = endpoint.createExchange();
	
	exchange.getIn().setBody(ID_4_SELECT);
	Exchange out = template.send(endpoint, exchange);
	assertTrue(out != null);
	assertTrue(out.getException() == null);
	assertTrue(out.getOut() != null);
	int nb=out.getOut().getHeader
                   ("CamelSqlRowCount",Integer.class);
	assertTrue(nb == 1);
	List<Map<String,Object>> l= (List<Map<String,Object>>) 
            out.getOut().getBody();
	assertTrue(l.size()>0);
	Map<String,Object> map=l.get(0);
	assertTrue(map.get("nom").contains("toto");
}

Pour conclure le composant camel-sql réduit la couche DAO (ici à base de jdbc) à presque quelques lignes de configuration.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Captcha *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.