Camel, Spring et tests JUnit pour les nuls (partie 2/3)

Ce billet est la suite de Camel, Spring et tests JUnit pour les nuls (partie 1/3).
camel-logo.png

Voici donc la troisième démo avancée.

TROISIEME DEMO: Exécuter script shell: Niveau avancé

L'objet de cette démo avancée est de pouvoir envoyer des commandes batch windows.

Le canal d'entrée attend un message (body) ayant le format suivant: RepertoireExec;commande;optionCmd

avec comme séparateur le point virgule.

En résumé la route est composée de cet enchainement:

"direct://a"-> Processor1 ->uriExecShell ->Processor2 -> uriFile.

Nous allons détailler les trois actes.

Acte1: Dessiner une route plus complexe

package fr.netapsys.camel.routes;
import org.apache.camel.Exchange;
import org.apache.camel.builder.RouteBuilder;

import fr.netapsys.camel.processors.MyExecProcessor;
import fr.netapsys.camel.processors.MyProcessor;

public class MyThirdRoute extends RouteBuilder {
 @Override
 public void configure() throws Exception {
/**
 * la route est configurée ainsi:
 * Le msg, arrivant à "direct://a" est traité par MyProcessor. 
 * MyProcessor prépare les arguments de la commande batch
 * Puis passe le msg au second endpoint "exec:cmd". 
 * Arrivé à ce dernier, le msg est traité par MyExecProcessor qui
 * analyse le résultat de l'execution. Deux cas possibles: 
 * - En cas d'echec du shell, une exception est levée.
 * - Sinon, un header est setté puis le msg est passé à uriFile
 */

 from("direct://a").process(new MyProcessor())
	.to("cmd:exec").process(new MyExecProcessor())
	.setHeader(Exchange.FILE_NAME, constant("camelResult.txt"))
	.to("file:/temp/?fileExist=Override")
	.end();
  }
}

Noter que les commentaires de cette classe détaille l'enchaînement.

Il reste à écrire les deux classes MyProcessor et MyExecProcessor qui doivent implémenter l'interface Processor.

Ce dernier possède une seule méthode process(Exchange ex).

La première classe MyProcessor:

package fr.netapsys.camel.processors;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.camel.component.exec.ExecBinding;
import fr.netapsys.camel.utiles.Utiles;
import org.springframework.stereotype.Component;

@Component
public class MyProcessor  implements Processor {	
/***Simple processor afin de traiter  la ligne de commande** */
   @Override
   public void process(final Exchange exchange) throws Exception {
     // Recup the body sent to uriEntree
     final String body = exchange.getIn().getBody(String.class);
     String[] bodySplit=body.split(";");	    
     if(bodySplit.length<3) {
	throw new IllegalArgumentException(
            "Erreur:body format not correct for the body :" +body);
     }
    final String currentDir=bodySplit[0];
    final String cmdBatch=bodySplit[1];
    final String option=bodySplit[2];
    exchange.getOut().setHeader(
           ExecBinding.EXEC_COMMAND_WORKING_DIR, currentDir);	 
    // Activation des canaux StdErr si StdOut n est pas open
    exchange.getOut().setHeader(
              ExecBinding.EXEC_USE_STDERR_ON_EMPTY_STDOUT, true);
    exchange.getOut().setHeader(ExecBinding.EXEC_COMMAND_ARGS,
                Utiles.getExecCommand(cmdBatch, option));
  }
}

L'extraction des éléments de la commande windows est effectuée en splittant le message à l'aide du séparateur ; .

Ces éléments sont explicitement nommés dans le code.

La méthode process du Processor prend en argument une instance exchange.

La ligne exchange.getIn().getBody() illustre que l'objet exchange contient, entre autres, le message In (en entrée).

La ligne exchange.getOut() permet d'accéder au message Out (de sortie).

Plus loin, nous verrons comment accéder à d'autres informations (ex. exception) durant l'acheminement du message.

Donc, la ligne :

exchange.getOut().setHeader(ExecBinding.EXEC_COMMAND_ARGS, 
                   Utiles.getExecCommand(cmdBatch, option));

établit la liste des arguments de la commande batch en utilisant la méthode statique getExecCommand de la classe Utiles.

Le code de la classe Utiles contient une seule méthode statique dont voici son code:

public static List<String> getExecCommand(
     final String commande, final String param) {
    return new ArrayList<String>() {
      private static final long serialVersionUID =1L;
     {
       	add("/C");
       	add(commande);
       	add(param);
      }	        
    };
}

Une seule option (param) de la commande cmd.exe a été gérée (sans soin) dans cette méthode.

Passons à la seconde classe nommée MyExecProcessor:

package fr.netapsys.camel.processors;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.camel.component.exec.ExecResult;
import org.springframework.stereotype.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component
public class MyExecProcessor implements Processor {
 private Logger  logger=
         LoggerFactory.getLogger(MyExecProcessor.class);
  @Override
  public void process(Exchange exchange) throws Exception {
    // On recupere l'exec de la ligne de commande
    final ExecResult execRes = exchange.getIn().
                         getBody(ExecResult.class);
    if (execRes.getExitValue() != 0) {
      logger.error("\n\t>>>>Exec cmd '" +execRes.getCommand()+
          "' echec avec  exit value:'"+execRes.getExitValue()+"'\n");
    }
 }
}

Dans la méthode process, on accède:

- Au résultat de l'exécution de la commande via l'instance ExecResult,

- Au contenu de l'exception levée dans l'objet exchange.

L'objetExecResult permet de récupérer le code retour de l'exécution d'une commande.
En cas d'échec de l'exécution de la commande un code de retour différent de zéro est retournée.

Acte2: Configurer Spring

Pas grand chose si la route est déclarée dans le même package.

Acte3: Tester avec JUnit

Le test JUnit repose toujours sur Spring:

package fr.netapsys.camel.tests;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.component.exec.ExecException;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class TestMyExecRoute  extends TestParent{	
 private Logger logger=LoggerFactory.getLogger(TestMyExecRoute.class);
 @Test
 public void testExecRoute() throws Exception {		
    ProducerTemplate template=camelCtx.createProducerTemplate();
    try{
 	template.sendBody("direct://a", "/temp/;dir;/W");
    }catch(ExecException e){
	logger.error("\n>>>Erreur produite:\n"+e,e);
    }
 }
}

Il suffit de lancer mvn test.

Pour voir la log s'afficher passer en argument commande non reconnue par l'OS.

La troisième partie nous fait découvrir les composants Camel-JDBC et Camel-SQL, une autre manière de de faire du jdbc ou de la peristance sans écrire du code (de plomberie!).

Laisser un commentaire

Votre adresse de messagerie 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.