Introduction à Smooks

1. Vue d'ensemble

Dans ce didacticiel, nous présenterons le framework Smooks.

Nous allons décrire de quoi il s'agit, énumérer ses principales fonctionnalités et éventuellement apprendre à utiliser certaines de ses fonctionnalités les plus avancées.

Tout d'abord, expliquons brièvement ce que le cadre est censé atteindre.

2. Smooks

Smooks est un cadre pour les applications de traitement de données - traitant des données structurées telles que XML ou CSV.

Il fournit à la fois des API et un modèle de configuration qui nous permettent de définir des transformations entre des formats prédéfinis (par exemple XML vers CSV, XML vers JSON et plus).

Nous pouvons également utiliser un certain nombre d'outils pour configurer notre cartographie, y compris les scripts FreeMarker ou Groovy.

Outre les transformations, Smooks propose également d'autres fonctionnalités telles que la validation des messages ou le fractionnement des données.

2.1. Principales caractéristiques

Jetons un coup d'œil aux principaux cas d'utilisation de Smooks:

  • Conversion de messages - transformation des données de divers formats sources vers divers formats de sortie
  • Enrichissement du message - remplir le message avec des données supplémentaires, qui proviennent d'une source de données externe comme une base de données
  • Fractionnement des données - traitement de gros fichiers (Go) et division de ceux-ci en plus petits
  • Liaison Java - construction et remplissage d'objets Java à partir de messages
  • Validation des messages - effectuer des validations comme regex, ou même créer vos propres règles de validation

3. Configuration initiale

Commençons par la dépendance Maven que nous devons ajouter à notre pom.xml :

 org.milyn milyn-smooks-all 1.7.0 

La dernière version est disponible sur Maven Central.

4. Liaison Java

Commençons maintenant par nous concentrer sur la liaison des messages aux classes Java. Nous allons passer par une simple conversion XML vers Java ici.

4.1. Concepts de base

Nous allons commencer par un exemple simple. Considérez le XML suivant:

 771 IN_PROGRESS 

Pour accomplir cette tâche avec Smooks, nous devons faire deux choses: préparer les POJO et la configuration Smooks.

Voyons à quoi ressemble notre modèle:

public class Order { private Date creationDate; private Long number; private Status status; // ... } 
public enum Status { NEW, IN_PROGRESS, FINISHED }

Maintenant, passons aux mappages Smooks.

Fondamentalement, les mappages sont un fichier XML qui contient une logique de transformation. Dans cet article, nous utiliserons trois types de règles différents:

  • bean - définit le mappage d'une section structurée concrète à la classe Java
  • value - définit le mappage pour la propriété particulière du bean. Peut contenir une logique plus avancée comme des décodeurs, qui sont utilisés pour mapper des valeurs à certains types de données (comme la date ou le format décimal)
  • w iring - nous permet de câbler un haricot à d'autres haricots (par exemple, le haricot fournisseur sera câblé au haricot Order )

Jetons un coup d'œil aux mappages que nous utiliserons dans notre cas ici:

      yyyy-MM-dd   

Maintenant, avec la configuration prête, essayons de tester si notre POJO est construit correctement.

Tout d'abord, nous devons construire un objet Smooks et transmettre le XML d'entrée en tant que flux:

public Order converOrderXMLToOrderObject(String path) throws IOException, SAXException { Smooks smooks = new Smooks( this.class.getResourceAsStream("/smooks-mapping.xml")); try { JavaResult javaResult = new JavaResult(); smooks.filterSource(new StreamSource(this.class .getResourceAsStream(path)), javaResult); return (Order) javaResult.getBean("order"); } finally { smooks.close(); } }

Et enfin, affirmer si la configuration est faite correctement:

@Test public void givenOrderXML_whenConvert_thenPOJOsConstructedCorrectly() throws Exception { XMLToJavaConverter xmlToJavaOrderConverter = new XMLToJavaConverter(); Order order = xmlToJavaOrderConverter .converOrderXMLToOrderObject("/order.xml"); assertThat(order.getNumber(), is(771L)); assertThat(order.getStatus(), is(Status.IN_PROGRESS)); assertThat( order.getCreationDate(), is(new SimpleDateFormat("yyyy-MM-dd").parse("2018-01-14")); }

4.2. Liaison avancée - Référencement d'autres beans et listes

Étendons notre exemple précédent avec les balises fournisseur et articles de commande :

 771 IN_PROGRESS  Company X 1234567    1 PX1234 9.99   1 RX990 120.32   

Et maintenant, mettons à jour notre modèle:

public class Order { // .. private Supplier supplier; private List items; // ... }
public class Item { private String code; private Double price; private Integer quantity; // ... } 
public class Supplier { private String name; private String phoneNumber; // ... }

Nous devons également étendre le mappage de configuration avec les définitions de bean fournisseur et article .

Notez que nous avons également défini le bean d' éléments séparés , qui contiendra tous les éléments d' éléments dans ArrayList .

Enfin, nous utiliserons l'attribut de câblage Smooks , pour le regrouper.

Regardez à quoi ressembleront les mappages dans ce cas:

      yyyy-MM-dd                 

Enfin, nous ajouterons quelques assertions à notre test précédent:

assertThat( order.getSupplier(), is(new Supplier("Company X", "1234567"))); assertThat(order.getItems(), containsInAnyOrder( new Item("PX1234", 9.99,1), new Item("RX990", 120.32,1)));

5. Validation des messages

Smooks est livré avec un mécanisme de validation basé sur des règles. Voyons comment ils sont utilisés.

La définition des règles est stockée dans le fichier de configuration, imbriqué dans la balise ruleBases , qui peut contenir de nombreux éléments ruleBase .

Chaque élément ruleBase doit avoir les propriétés suivantes:

  • nom - nom unique, utilisé juste pour référence
  • src - chemin vers le fichier source de la règle
  • provider - nom de classe complet, qui implémente l' interface RuleProvider

Smooks est livré avec deux fournisseurs prêts à l'emploi : RegexProvider et MVELProvider .

Le premier est utilisé pour valider des champs individuels dans un style de type regex.

Le second est utilisé pour effectuer une validation plus compliquée dans la portée globale du document. Voyons-les en action.

5.1. RegexProvider

Let's use RegexProvider to validate two things: the format of the customer name, and phone number. RegexProvider as a source requires a Java properties file, which should contain regex validation in key-value fashion.

In order to meet our requirements, we'll use the following setup:

supplierName=[A-Za-z0-9]* supplierPhone=^[0-9\\-\\+]{9,15}$

5.2. MVELProvider

We'll use MVELProvider to validate if the total price for each order-item is less then 200. As a source, we'll prepare a CSV file with two columns: rule name and MVEL expression.

In order to check if the price is correct, we need the following entry:

"max_total","orderItem.quantity * orderItem.price < 200.00"

5.3. Validation Configuration

Once we've prepared the source files for ruleBases, we'll move on to implementing concrete validations.

A validation is another tag in Smooks configuration, which contains the following attributes:

  • executeOn – path to the validated element
  • name – reference to the ruleBase
  • onFail – specifies what action will be taken when validation fails

Let's apply validation rules to our Smooks configuration file and check how it looks like (note that if we want to use the MVELProvider, we're forced to use Java binding, so that's why we've imported previous Smooks configuration):

Now, with the configuration ready, let's try to test if validation will fail on supplier's phone number.

Again, we have to construct Smooks object and pass input XML as a stream:

public ValidationResult validate(String path) throws IOException, SAXException { Smooks smooks = new Smooks(OrderValidator.class .getResourceAsStream("/smooks/smooks-validation.xml")); try { StringResult xmlResult = new StringResult(); JavaResult javaResult = new JavaResult(); ValidationResult validationResult = new ValidationResult(); smooks.filterSource(new StreamSource(OrderValidator.class .getResourceAsStream(path)), xmlResult, javaResult, validationResult); return validationResult; } finally { smooks.close(); } } 

And finally assert, if validation error occurred:

@Test public void givenIncorrectOrderXML_whenValidate_thenExpectValidationErrors() throws Exception { OrderValidator orderValidator = new OrderValidator(); ValidationResult validationResult = orderValidator .validate("/smooks/order.xml"); assertThat(validationResult.getErrors(), hasSize(1)); assertThat( validationResult.getErrors().get(0).getFailRuleResult().getRuleName(), is("supplierPhone")); }

6. Message Conversion

The next thing we want to do is convert the message from one format to another.

In Smooks, this technique is also called templating and it supports:

  • FreeMarker (preferred option)
  • XSL
  • String template

In our example, we'll use the FreeMarker engine to convert XML message to something very similar to EDIFACT, and even prepare a template for the email message based on XML order.

Let's see how to prepare a template for EDIFACT:

UNA:+.? ' UNH+${order.number}+${order.status}+${order.creationDate?date}' CTA+${supplier.name}+${supplier.phoneNumber}'  LIN+${item.quantity}+${item.code}+${item.price}' 

And for the email message:

Hi, Order number #${order.number} created on ${order.creationDate?date} is currently in ${order.status} status. Consider contacting the supplier "${supplier.name}" with phone number: "${supplier.phoneNumber}". Order items:  ${item.quantity} X ${item.code} (total price ${item.price * item.quantity}) 

The Smooks configuration is very basic this time (just remember to import the previous configuration in order to import Java binding settings):

    /path/to/template.ftl  

Cette fois, nous devons simplement passer un StringResult au moteur Smooks:

Smooks smooks = new Smooks(config); StringResult stringResult = new StringResult(); smooks.filterSource(new StreamSource(OrderConverter.class .getResourceAsStream(path)), stringResult); return stringResult.toString();

Et nous pouvons, bien sûr, le tester:

@Test public void givenOrderXML_whenApplyEDITemplate_thenConvertedToEDIFACT() throws Exception { OrderConverter orderConverter = new OrderConverter(); String edifact = orderConverter.convertOrderXMLtoEDIFACT( "/smooks/order.xml"); assertThat(edifact,is(EDIFACT_MESSAGE)); }

7. Conclusion

Dans ce didacticiel, nous nous sommes concentrés sur la façon de convertir des messages dans différents formats ou de les transformer en objets Java à l'aide de Smooks. Nous avons également vu comment effectuer des validations basées sur des règles de regex ou de logique métier.

Comme toujours, tout le code utilisé ici peut être trouvé sur GitHub.