mercredi 3 septembre 2014

Talend : comment passer des variables entre job et sous job

Quel est le problème ?
Il est parfois nécessaire de pouvoir récupérer des informations depuis un sous-job par le job parent. Cette procédure n'est pas évidente à mettre en place, voici donc comment faire...

L'exemple utilisé ci-dessous n'est peut-être pas le meilleur, mais il illustre le propos. Je souhaite surveiller la présence d'une table particulière dans une base de données, et attendre sa présence avant de poursuivre l'exécution des jobs suivants. Si vous avez une meilleure solution pour réaliser cela, je suis bien sûr preneur.

Bref, allons-y :

Un peu de théorie...

Je vais essayer de vulgariser un peu des concepts de programmation java, qui sont nécessaires pour comprendre le mécanisme utilisé par talend.

Dans talend, deux (à ma connaissance) objets permettent de stocker de l'information de manière globale, et de la faire transiter d'un job à un autre : les contextes, et le globalMap.

Malheureusement (ou pas), lorsque l'on passe une variable d'un job vers un sous job, celle-ci est passée en valeur, pas en référence. La valeur de la variable est ainsi passée au sous-job, et si celui-ci en modifie la valeur, cette valeur modifiée ne sera accessible que dans le sous job. Le job père, lui a accès à sa propre valeur de la variable.

Cela est vrai pour les objets "immuables" (dont font partie les entiers et les chaines, par exemple). Le seul moyen de contourner cette limitation, est de passer au sous-job, une référence vers un objet "mutable".

Il faut donc utiliser un objet "mutable", mais aussi utilisable en multi-thread. Pour cela, on utilise un ConcurrentHashMap. Ouf, fini pour la théorie.


Un peu de pratique...

Tout ceci étant maintenant extrêmement clair (sinon, ce n'est pas grave), voici comment réaliser cette opération.

Job père

Ce job devra passer une variable au sous-job, puis lire la variable modifiée renvoyée par le sous-job.

Job père avec tJava1 -> sous-job -> tJava2
Job père


Déclaration de la variable

Le premier élément clef est le tJava "set variable". Ce tJava défini la variable que nous allons passer à notre sous-job, avec le code suivant :

// On defini un concurrent hashmap qui sera accessible par le fils de ce job
globalMap.put("Go_SB_SharedMap", new java.util.concurrent.ConcurrentHashMap());


En résumé, dans le globalMap de talend, on crée un objet de type ConcurrentHasMap, qui s'appelle Go_SB_SharedMap.

Lecture de la valeur de la variable

Le deuxième élément clef est le tJava "get variable". Ce tJava récupère la valeur qui a été définie dans le sous-job, de la manière suivante :

// On recupere le contenu de la variable definie dans notre childjob
System.out.println("Valeur de retour du sous job : " + ((java.util.Map) globalMap.get("Go_SB_SharedMap")).get("tableOK") );


(pour les curieux, en fait j'utilise cette valeur de retour dans le tLoop pour sortir de la boucle une fois que le sous job indique que la table est présente)

Passage de la variable au sous-job

Bien évidemment, entre les deux opérations, on aura passé la variable au sous-job, qui lui l'aura modifiée. Pour passer la variable au sous-job, on utilise (évidemment) les contextes. On défini donc une variable de contexte dans les paramètres du tRunJob :

Contexte 'built-in' du sous-job
Contexte du tRunJob (sous-job)


et la valeur de cette variable de contexte (ici, je l'ai nommée avec le même nom que la variable que l'on passe, mais cela n'est pas obligatoire, et même peut porter à confusion), est tout simplement le hashmap que l'on aura défini dans notre premier tJava.

Accès et modification de la variable dans le sous-job

sous-job avec un tJava qui modifie la variable passée par le job père
Sous-job


Ici mon sous-job fait une petite requête sur une table, et s'il n'y a pas d'erreur (donc si la table existe), met à jour la variable grace au tJava, qui fait tout simplement :

// On met a jour la variable dans le shared map pour que le père de ce job récupère l'info :
((java.util.Map) context.Go_SB_SharedMap).put("tableOK", "1");



Et voila!
Facile, non?

1 commentaire: