Avancé
Avancé – La gestion des Tree
Generic System permet de persister des arbres. Pour commencer nous avons besoin de créer un arbre, puis de l’instancier. Une instance sans super est interprétée par Generic System comme la racine de l’arbre. Pour ajouter une feuille ou une branche à un nœud, il faut créer une instance de l’arbre en précisant ce nœud comme super.
Premier exemple
Tout développeur web connaît la structure de base d’une page web. Voyons comment créer un arbre HTML simple avec Generic System :
Engine engine = new Engine();
// Create a tree called tags
Generic tags = engine.setInstance("Tags");
// Create the root html
Generic html = tags.setInstance("html");
// Create the children header, body and footer
Generic head = tags.setInstance(html, "header");
Generic body = tags.setInstance(html, "body");
Generic foot = tags.setInstance(html, "footer");
// Create the children p and table for the node body
tags.setInstance(body, "p");
tags.setInstance(body, "table");
// Persist changes
engine.getCurrentCache().flush();
Deuxième exemple : relations d’un arbre avec un autre type
Complétons maintenant notre premier exemple avec la création d’un type Color auquel on ajoute trois instances de couleur :
// Create a new type color
Generic color = engine.setInstance("Color");
// Add three new colors
Generic blue = color.setInstance("blue");
Generic red = color.setInstance("red");
Generic green = color.setInstance("green");
Créons ensuite une relation tagsColor entre notre arbre Tag et notre type Color et ajoutons quelques liens :
// Create a relation between tag and color
Generic tagsColor = tags.setRelation("TagsColor", color);
// Add links
tags.setHolder(tagsColor, "BlueDefault", blue);
html.setHolder(tagsColor, "htmlRed", red);
body.setHolder(tagsColor, "bodyGreen", green);
assert tags.getHolders(tagsColor).first().getTargetComponent().equals(blue);
assert html.getHolders(tagsColor).first().getTargetComponent().equals(red);
assert head.getHolders(tagsColor).first().getTargetComponent().equals(red);
assert body.getHolders(tagsColor).first().getTargetComponent().equals(green);
assert p.getHolders(tagsColor).first().getTargetComponent().equals(green);
// Persist changes
engine.getCurrentCache().flush();
Voici une représentation schématique de l’arbre que nous venons de créer, qui met en évidence la relation et les links entre notre arbre et notre type :

Parcourir un arbre
Pour parcourir un arbre avec Generic System, le pattern Visitor a été prévu. Il suffit de faire appel à la méthode traverse sur le nœud à partir duquel on souhaite parcourir l’arbre. Comble du raffinement, il est possible de spécifier un traitement à effectuer avant et après le parcours de chaque nœud (pré- et post-fixé).
Reprenons notre premier exemple d’arbre représentant une page web, et parcourons-le pour afficher les nœuds avant et après qu’ils soient parcourus :
// Pass through the tree from html
html.traverse(new Visitor() {
@Override
public void before(Generic node) {
System.out.println("before : " + node.getValue());
}
@Override
public void after(Generic node) {
System.out.println("after : " + node.getValue());
}
});
// Persist changes
engine.getCurrentCache().flush();
Exécutez ce code chez vous. Vous devriez avoir un résultat semblable à celui-ci :
before : html
before : header
after : header
before : body
before : p
after : p
before : table
after : table
after : body
before : footer
after : footer
after : html
Generic System n’est pas limité à des arbres à un seul parent. En fait, Generic System est un modèle de données généralisable, il n’est pas limité sur les arbres et permet la gestion d’arbres à n parents.
Arbres à n parents
Nous allons voir la notion d’arbres à n parents à travers un exemple. Je suppose que vous avez tous songé un jour à réaliser votre arbre généalogique ? Voilà l’occasion rêvée ! Commençons par créer notre arbre, puis les parents :
Engine engine = new Engine();
// Create a binary tree called GenTree
Generic genealogicalTree = engine.setInstance("GenTree");
// Create the root father and mother
Generic father = genealogicalTree.setInstance("father");
Generic mother = genealogicalTree.setInstance("mother");
Pour créer les enfants, nous avons besoin d’indiquer quels sont leurs parents. Pour cela, il suffit d’indiquer les parents lors de la création de l’instance (sous forme de List) :
// Create the children : a son and a daughter
Generic son = genealogicalTree.setInstance(Arrays.asList(father, mother), "son");
Generic daughter = genealogicalTree.setInstance(Arrays.asList(father, mother), "daughter");
Nous pouvons ensuite vérifier que chaque parent a pour enfant les instances son et daughter :
// Get children of father
assert father.getInheritings().containsAll(Arrays.asList(son, daughter));
// Get children of mother
assert mother.getInheritings().containsAll(Arrays.asList(son, daughter));
// Persist changes
engine.getCurrentCache().flush();
Vous voyez, rien de bien compliqué ! Voici la représentation schématique de notre arbre généalogique :

En résumé
setInstance sans super ajoute une racine à un arbre.
setInstance avec un ou plusieurs super ajoute un nœud à un arbre.
La méthode traverse du pattern Visitor permet de parcourir un nœud de l’arbre.
Les méthodes before(Generic node) et after(Generic node) permettent de définir les traitements respectivement avant et après le parcours de chaque nœud (parcours pré- et post-fixé).
Ce billet n’était pas vraiment complexe si vous avez l’habitude d’utiliser les arbres. Le seul point que vous ne connaissiez peut-être pas était la notion d’héritage dans les arbres.
Dans le prochain billet, nous aborderons une notion bien différente de ce que nous avons vu jusqu’ici mais Ô combien importante dans toute base de données : la gestion de la concurrence.
