1. Présentation
Un WebHook est un mécanisme qui permet de notifier, via une requête HTTP(S), un système externe de la survenue d’un évènement.
Il s’agira donc d’évènements qui se produisent dans l’application CARL Source.
Ces évènements sont essentiellement des évènements simples sur les entités : création, modification, ou suppression d’une entité.
|
|
Techniquement les WebHooks de CARL Source n’exécutent pas une requête HTTP pour chaque évènement des entités. Pour des raisons de performance (éviter de multiplier le nombre de requêtes HTTP), les notifications sont faites par transaction métier. |
Dans CARL Source, deux types de WebHook peuvent être utilisés :
-
Entités : il s’agit d’un WebHook classique qui permet de notifier un système externe en envoyant une description de l’évènement via une requête HTTP POST avec un contenu au format JSON.
-
ArcGIS® : il s’agit d’un WebHook spécifique permettant d’envoyer les évènements vers un serveur de cartographie ArcGIS® dans un format adapté de façon à synchroniser les données de CARL Source avec ce serveur.
|
|
Attention dans CARL Source 7.0.0, seule les webhooks de type "ArcGIS®" sont complétement opérationnels. |
2. Fonctionnalité Webhooks
La fonctionnalité Webhooks est accessible dans le module Système au niveau de la partie "Échanges de données".
2.1. Informations générales
Le formulaire des webhooks présente les informations suivantes :
-
Code : code du WebHook, unique dans l’application. Obligatoire.
-
Libellé : libellé descriptif du WebHook.
-
Type : Entités ou ArcGIS®.
-
État : trois états possibles.
-
Actif : les notifications sont envoyées au fil de l’eau lorsque les entités ciblées par le WebHook sont modifiées.
-
Inactif : état initial qui permet de préparer et sauvegarder la définition d’un WebHook. Aucune notification n’est envoyée.
-
Annulé : le WebHook n’est plus fonctionnel dans CARL Source. A utiliser par exemple lorsque le système externe n’est plus accessible.
La définition d’un WebHook inactif peut malgré tout être utilisé par exemple dans un traitement automatique de synchronisation avec ArcGIS®. Ce qui permet des synchronisations manuelles ou programmées.
-
-
URL : URL du système externe vers laquelle est envoyée la requête HTTP de notification
-
Jeton d’authentification : visible uniquement pour un webhook de type "Entités". La zone n’est pas modifiable.
Le bouton "Générer" permet de créer un jeton qui sera utilisé pour l’authentification entre CARL Source et le système externe (voir le bloc Sécurité plus bas dans le document). Le bouton "Supprimer" permet d’arrêter l’utilisation de ce jeton pour les échanges avec le système externe. -
Utilisateur / Mot de passe : visible uniquement pour un webhook de type "ArcGIS®". Ces deux zones permettent d’indiquer un compte (utilisateur et son mot de passe) pour la demande de génération du jeton par le serveur ArcGIS®.
-
Nb d’erreurs max. : nombre d’erreurs max. autorisées pour un délai donné
-
Délai en minutes :
-
Responsable : nom du responsable qui sera averti si le nombre d’erreurs dépasse le seuil configuré
-
Commentaire : saisie libre permettant de décrire ou donner des informations techniques ou autre sur le système externe par exemple.
-
Définition : texte au format JSON (dépendant du type de WebHook). Il décrit les entités pour lesquelles on veut notifier le système externe, les attributs de ces entités que l’on veut exporter, etc.
|
|
Si le nombre d’erreurs dépasse le seuil configuré pour le délai donné, le WebHook sera automatiquement désactivé et un mail d’avertissement sera envoyé au responsable désigné. |
|
|
Le paramètre WEBHOOK_ERROR_HORIZON du module "Échange de données" permet de définir la durée de conservation des échecs. Actuellement la suppression des échecs trop ancien n’est pas faite via un traitement automatique. Il est donc possible que des échecs restent présents sur une période plus grande que celle prévue dans l’horizon. |
|
|
Il est possible d’ajouter des documents liés au WebHook ; ceux-ci permettant par exemple de détailler le WebHook en question. |
2.2. Webhooks de type "Entité"
Ce type de WebHook permet d’envoyer un message au format JSON à un système externe lors d’un évènement CRUD (Création, Modification, Suppression) sur des entités.
La définition du WebHook est une description au format JSON qui permet d’indiquer :
-
les entités pour lesquelles on veut émettre une notification,
-
les types d’évènement CRUD sur ces entités pour lesquels on veut émettre une notification,
-
les attributs de l’entité à inclure dans le message de notification.
Un WebHook pouvant concerner plusieurs types d’entités, la définition est une liste de descriptions contenant ces informations : quelles entités, pour quels évènements, émettent un message avec quels attributs.
La définition a le format :
{
"entities": [
{ <entité / évènements / attributs> },
{ <entité / évènements / attributs> },
{ <entité / évènements / attributs> }
]
}
Chaque descripteur d’entité a lui le format :
{
"entity": [
<critères>, ...
],
"events": [ <évènements>, ... ],
"attributes": {
"attribut1": "${expression1}",
...
}
}
Entity
La première partie "entity" permet de sélectionner les entités pour lesquelles on souhaite être notifié.
Il s’agit d’une liste de critères ("matchers") qui sont évalués dans l’ordre et qui doivent tous être validés pour que la notification soit envoyée.
Actuellement, il y a 3 types de critères :
| Type | Exemple | Description |
|---|---|---|
typeHierarchy |
|
Permet de sélectionner tous les types d’entités d’une hiérarchie de types dont la racine est donnée. |
exactType |
|
Permet de sélectionner précisément et uniquement les entités du type donné. |
attributeValue |
|
Permet de sélectionner les entités dont l’attribut indiqué a la valeur précisée. Le nom d’attribut doit être un nom d’attribut simple porté par l’entité. La valeur doit être une chaîne de caractères au format interne utilisé par CARL Source pour représenter des valeurs de différents types (ex. dans les fichiers de chargement XML). Pour l’instant le seul opérateur disponible est l’égalité. |
|
|
Le premier critère de la liste doit obligatoirement porter sur un type d’entité. |
Events
Cette partie permet d’indiquer le type d’évènements sur les entités sélectionnées pour lesquels on veut être notifié : création d’entité (created), modification d’entité (updated), suppression d’entité (deleted).
Si cette partie n’est pas précisée ("events" absent ou null), alors tous les types d’évènements seront notifiés.
|
|
Si la liste est vide, un message d’alerte sera présent dans les logs de l’application indiquant que cette partie ne capturera aucun évènement mais aucune erreur ne bloquera l’activation de l’ensemble du WebHook. |
Attributes
Cette partie permet de lister les attributs de l’entité qui seront inclus dans le message de notification sous la forme :
"<nom d'attribut dans le message JSON>": "${<expression utilisée pour produire la valeur mise dans le message>}"
Le nom d’attribut est une chaîne quelconque.
L’expression doit être de la forme "${entity.attr}".
Il est possible de chaîner l’expression sur plusieurs niveaux : "${entity.attrA.attrB}".
|
|
Le chaînage peut entrainer des impacts sur les performances de l’application. |
Pour avoir l’information sur le type d’évènement qui produit la notification, il est possible d’utiliser un attribut dédié avec l’expression : "${event}", qui aura les valeurs : "created", "updated", ou "deleted".
Il est aussi possible de ne pas mettre d’expression et d’indiquer directement la valeur qui sera incluse dans le message JSON.
Par exemple :
-
"attrA": true,
-
"attrB": 5,
-
"attrC": null
Sécurité
Sur les WebHooks de type "Entité", il est possible de demander la génération d’un jeton d’authentification unique.
Ce jeton sert de secret partagé avec le système externe destinataire de la requête issue du WebHook.
Si un jeton est défini sur un WebHook, une entête http X-CS-HMAC-SHA256 est ajoutée à la requête.
Cet entête contient le hash (élément crypté) du message JSON envoyé.
À la réception, le système externe est libre de produire un hash du JSON reçu en utilisant le jeton et les mêmes algorithmes (HMAC + SHA256) et de comparer le résultat avec celui stocké dans l’entête.
Si les résultats sont identiques, l’origine du JSON reçu est alors authentifiée, sinon il peut être rejeté.
|
|
Cette fonctionnalité est disponible à partir de la version 7.1 de CARL Source et reste optionnelle. |
Entête HTTP
Quelques précisions sur la définition des entêtes HTTP :
-
Un entête HTTP peut contenir plusieurs valeurs, c’est pourquoi il est possible de définir plusieurs fois un entête portant le même nom.
-
Certains entêtes HTTP standards sont définis automatiquement :
host,content-length,content-type, etc.
Cette liste peut évoluer dans le temps. -
Les entêtes suivants ne sont actuellement pas modifiables :
host,content-lengthetcontent-encoding.
Pour des raisons de sécurité ou de fiabilité, d’autres entêtes pourraient être rendus non modifiables dans le futur. -
Actuellement, seules des valeurs simples sont autorisées pour les entêtes ; il n’est pas possible d’inclure des expressions.
Il est techniquement possible d’utiliser une expression “${…}” mais aucune variable n’est pour l’instant disponible pour être évaluée.
|
|
La configuration des entêtes HTTP n’est disponible qu'à partir de la version 7.3.3 de CARL Source mais également à partir du patch P23 de la version 7.2.0. |
Exemple de définition
{
"headers": [
{ "name": "some_header", "value": "something" },
{ "name": "my_header", "value": "value_1" },
{ "name": "my_header", "value": "value_2" }
],
"entities": [
{
"entity": [
{ "match": "typeHierarchy", "value": "mr" }
],
"events": ["created", "updated", "deleted"],
"attributes": {
"event": "${event}",
"code": "${entity.code}",
"description": "${entity.description}",
"lastModTime": "${entity.modifyDate}",
"eqptBroken": "${entity.eqptBroken}",
"expectedAmount": "${entity.amount}",
"delay": "${entity.delay}"
}
}, {
"entity": [
{ "match": "exactType", "value": "room" },
{ "match": "attributeValue", "attribute": "use", "value": "TECHNICAL" }
],
"events": [ "deleted" ],
"attributes": {
"code": "${entity.code}",
"description": "${entity.description}",
"lastModTime": "${entity.modifyDate}",
"projectGuid": "${entity.bimGuid}",
"area": "${entity.area}"
}
}
]
}
Exemple de message envoyé
{
"data": [
{
"type": "mr",
"id": "183368af405-c1",
"attributes": {
"event": "updated",
"code": "000003",
"description": "test",
"modifyDate": "2022-09-13T15:01:28.851+02:00",
"eqptBroken": false,
"amount": 0.0,
"delay": null,
"symptom": "ALERTE",
}
},
{
"type": "mr",
"id": "18014fc38127-5a",
"attributes": {
"event": "created",
"code": "000007",
"description": "test 2",
"modifyDate": "2022-09-13T15:01:29.583+02:00",
"eqptBroken": true,
"amount": 5864.0,
"delay": null,
"symptom": "ALERTE",
}
}
]
}
2.3. Webhooks de type "ArcGIS®"
Ce type de WebHook permet d’aller plus loin qu’une simple notification et permet de synchroniser les données des entités CARL Source avec celles d’une Géodatabase d’un serveur ArcGIS® en passant par un FeatureService et son API REST applyEdits.
Comme pour un WebHook sur les entités, CARL Source enverra des notifications (synchronisation) au fil de l’eau lors de la modification des entités mais il y a un certain nombre de différences.
Pour ces WebHooks :
-
Ils ne fonctionnent que pour des types d’entités "localisables", c’est-à-dire des entités ayant une géométrie et pouvant être affichées sur une carte ou un plan.
-
La synchronisation n’est faite que pour les entités qui ont une géométrie. Par exemple un matériel sans géométrie ne sera pas synchronisé vers le serveur ArcGIS®.
-
De la même manière la suppression de la géométrie d’une entité entraine sa suppression du serveur ArcGIS®.
La définition au format JSON est très similaire à celle d’un WebHook de type entité et décrit un ensemble de "layers" du FeatureService et pour chacun, quelles entités seront synchronisées avec ces layers.
{
"layers": [
{ <entité / layer / attributs> },
{ <entité / layer / attributs> },
{ <entité / layer / attributs> }
]
}
Chaque descripteur d’entité a lui le format :
{
"entity": [
<critères>, ...
],
"layer": { "id": <id numérique>, "name": "<nom du layer>", "geometryType": "POINT|LINESTRING|POLYGON" },
"attributes": {
"attribut1": "${expression1}",
...
}
}
Les parties concernant la sélection des entités et la liste des attributs exportés est identique à celle des WebHooks classiques sur les entités.
La partie “layer” permet d’indiquer les identifiants du layer avec lequel synchroniser les entités sélectionnées.
|
|
Ces identifiants sont importants pour permettre à CARL Source d’assurer la synchronisation. Si le FeatureService sur lequel s’appuie un WebHook est republié, les numéros de |
Lors de la republication d’un FeatureService, il est préférable de désactiver le WebHook avant, de le mettre à jour après la republication, de le réactiver, et enfin d’utiliser le traitement automatique pour synchroniser les entités modifiées dans l’intervalle de temps où il était inactif.
A noter que les layers ne peuvent contenir qu’un seul type de géométrie, par conséquent le type de géométrie est aussi utilisé pour filtrer les entités synchronisées avec le layer.
Un matériel ayant une géométrie de type "polygone" ne sera pas synchronisé avec un layer ciblant les matériels si ce layer a un type de géométrie "ligne".
Si aucun layer ne correspond au filtre et au type de géométrie, l’entité ne sera pas synchronisée même si elle a une géométrie.
Si un type d’entité peut avoir plusieurs types de géométries, il est nécessaire d’avoir plusieurs déclarations pour plusieurs layers cibles.
Sécurité
Sur les WebHooks de type "ArcGIS®", il est possible d’indiquer le couple login / mot de passe.
Ces informations sont utilisées pour demander la génération d’un jeton au serveur ArcGIS®.
Ce jeton est ensuite adjoint aux requêtes à destination du serveur de cartographie qui peut vérifier sa validité et s’assurer de la légitimité du flux en provenance de CARL Source.
|
|
Cette fonctionnalité est optionnelle. |
Layers du FeatureService ArcGIS®
Pour pouvoir initialiser automatiquement un WebHook à partir de la définition d’un FeatureService il faut, comme pour l’initialisation automatique des cartes, nommer les layers avec le préfixe : CARL_<type d’entité>_.
Ces layers seront automatiquement importés, et les autres ignorés.
Les layers doivent également avoir les champs suivants :
| Nom du champ | Type |
|---|---|
ENTITYID |
Text(33) |
ENTITYCLASS |
Text(255) |
GlobalID |
GlobalID / avec un index unique. |
Enfin, les layers et le FeatureService doivent avoir la capacité (visible dans la description du FeatureService) : "Supports ApplyEdits With Global Ids: true".
Cette capacité est souvent dépendante de la présence du champ GlobalID avec un index unique mais d’autres restrictions peuvent s’appliquer pour que cette capacité soit active. Il faut pour cela consulter la documentation ArcGIS®.
Exemple de définition
{"layers": [
{
"entity": [ {"match": "typeHierarchy", "value": "mr"} ],
"layer": { "id": 0, "name": "CARL_MR_POINT", "geometryType": "POINT" },
"attributes": { "xtraTxt01": "${entity.description}" }
},
{
"entity": [ {"match": "typeHierarchy", "value": "wo"} ],
"layer": { "id": 1, "name": "CARL_WO_POINT", "geometryType": "POINT" },
"attributes": { "xtraTxt01": "${entity.description}" }
},
{
"entity": [ {"match": "typeHierarchy", "value": "wo"} ],
"layer": { "id": 2, "name": "CARL_WO_LINE", "geometryType": "LINESTRING" },
"attributes": { "xtraTxt01": "${entity.description}" }
},
{
"entity": [ {"match": "typeHierarchy", "value": "wo"} ],
"layer": { "id": 3, "name": "CARL_WO_POLYGON", "geometryType": "POLYGON" },
"attributes": { "xtraTxt01": "${entity.description}" }
},
{
"entity": [
{"match": "typeHierarchy", "value": "material"},
{"match": "attributeValue", "attribute": "eqptType", "value": "VHL"}
],
"layer": { "id": 4, "name": "CARL_MATERIAL_POINT", "geometryType": "POINT" },
"attributes": {
"xtraTxt01": "${entity.description}",
"xtraNum01": "${entity.replacementAge}",
"xtraDate01": "${entity.lastInventory}"
}
},
{
"entity": [ {"match": "typeHierarchy", "value": "material"} ],
"layer": { "id": 5, "name": "CARL_MATERIAL_LINE", "geometryType": "LINESTRING" },
"attributes": { "xtraTxt01": "${entity.description}" }
},
{
"entity": [ {"match": "typeHierarchy", "value": "material"} ],
"layer": { "id": 6, "name": "CARL_MATERIAL_POLYGON", "geometryType": "POLYGON" },
"attributes": { "xtraTxt01": "${entity.description}" }
},
{
"entity": [ {"match": "typeHierarchy", "value": "box"} ],
"layer": { "id": 7, "name": "CARL_BOX_POINT", "geometryType": "POINT" },
"attributes": { "xtraTxt01": "${entity.description}" }
},
{
"entity": [ {"match": "typeHierarchy", "value": "box"} ],
"layer": { "id": 8, "name": "CARL_BOX_LINE", "geometryType": "LINESTRING" },
"attributes": { "xtraTxt01": "${entity.description}" }
},
{
"entity": [ {"match": "typeHierarchy", "value": "box"} ],
"layer": { "id": 9, "name": "CARL_BOX_POLYGON", "geometryType": "POLYGON" },
"attributes": { "xtraTxt01": "${entity.description}" }
}
]}
Traitement automatique de synchronisation avec un serveur ArcGIS®
Lorsqu’un WebHook est actif, il synchronise au fils de l’eau les entités vers le service ArcGIS®.
Cependant, il peut arriver qu’en cas d’erreur (indisponibilité d’un serveur, coupures réseau, etc.) certaines entités ne soient pas synchronisées correctement. De même, lorsqu’une synchronisation est mise en place sur une base existante, il faut pouvoir synchroniser les entités existantes avant son activation.
Pour ces cas d’usage, CARL Source permet d’ajouter un traitement automatique permettant de déclencher (manuellement ou de façon programmée) une synchronisation de certaines entités.
Les entités qui seront (re)synchronisées sont celles qui ont été modifiées entre les 2 dates indiquées en paramètre du traitement, où si aucune n’est précisée, toutes les entités (par exemple pour une synchronisation initiale).
Pour fonctionner, le traitement de synchronisation s’appuie sur la définition d’un WebHook qui doit donc être précisé et être à l’état "Actif" ou "Inactif" (dans cet état la synchronisation au fil de l’eau est désactivée mais le WebHook est valide et utilisable par le traitement).
En plus des dates, il est aussi possible de retreindre les entités synchronisées par le traitement en listant les types d’entités à synchroniser.
Il s’agit d’une liste séparée par des virgules. Si elle est vide, tous les types d’entités précisés dans le WebHook seront synchronisées.
Par défaut, le traitement suppose que les états de synchronisation des entités sont valides. Les entités en question n’ont simplement pas été synchronisées (ex. WebHook inactif).
Lorsqu’il y a des incohérences, il faut alors "Forcer la resynchronisation".
Dans ce cas, les données synchronisées sont supprimées (état de synchronisation dans CARL Source, et données sur l’entité dans le FeatureService ArcGIS®), de façon à repartir de zéro pour ces entités, puis ces entités sont de nouveau synchronisées.
Durée du traitement
La durée du traitement est évidemment proportionnelle au nombre d’entités à synchroniser.
Pour cela, il est recommandé de limiter leur nombre en précisant un intervalle de dates, ou en limitant les types d’entités à synchroniser.
Le paramètre "Forcer la resynchronisation" a aussi un impact très fort sur le temps du traitement puisqu’il nécessite au préalable, pour chaque entité, de faire des suppressions.
Programmation périodique du traitement
| New 7.1 |
A partir de la version 7.1.0 de CARL Source, un nouveau paramètre intitulé "Entités modifiées depuis la dernière exécution en succès de ce traitement automatique" est disponible sur les traitements automatiques associés à la classe Si une date de début est déjà spécifiée sur le traitement, le fait de cocher ce paramètre entrainera le remplacement de cette dernière par la date calculée automatiquement. |
|
|
À noter que si un traitement automatique était déjà défini avec la classe |
3. Impact des webhooks sur les performances
Les WebHooks ont été développés avec l’objectif d’impacter le minimum possible les performances de l’application. Néanmoins, lorsqu’ils sont actifs, ils ajoutent nécessairement des traitements supplémentaires.
Quelques mesures ont été prises pour éviter les impacts négatifs :
-
Toutes les entités de l’application ne sont pas concernées par les WebHook.
Les entités importantes des processus métier le sont, mais pas les "entités techniques". Techniquement seules les entités héritant de "BaseBean" sont utilisables actuellement. -
La construction des messages envoyés dans les notifications sont faites en dehors des transactions métier.
-
Les messages sont envoyés de façon asynchrone de façon à ne pas pénaliser la réactivité des IHMs.
-
A titre de conseil, il est important de limiter les entités ciblées par les WebHooks de façon à ne pas envoyer de notification pour tous les évènements sur toutes les entités de l’application.
-
Il est également important pour les scénarii d’usage "interactifs" que le lien réseau entre les serveurs ait une latence faible. Sinon l’utilisateur ne verra pas tout de suite une modification qu’il vient de faire.
Dans tous les cas les WebHooks sont suivis par des indicateurs de performance qui sont disponibles dans le "rapport de performance".
4. Débogage des webhooks
Un profil de traces a été ajouté de façon à activer des traces détaillées sur les WebHooks.
Il se nomme WH_DEBUG.
Par ailleurs, pour faciliter les diagnostics, un fichier webhooks.json contenant les définitions des WebHooks a été ajouté dans le Rapport de performance avec les indicateurs suivants :
-
com.carl.webhook/{0}/tx.event.time : Durée de gestion des évènements transactionnels onXxx()/postXxx() pour un WebHook.
-
com.carl.webhook/{0}/after.tx.time : Durée du traitement post-transaction pour un WebHook.
-
com.carl.webhook/{0}/async.exec.time : Durée de l’envoi d’un message pour un WebHook.
Avis de marques déposées
Nous avons apporté tous nos efforts pour garantir l’exactitude des informations au moment de la publication de ce document.
CARL Source étant en constante évolution, CARL Berger-Levrault ne peut être tenu responsable des éventuels manques ou erreurs de ce document.
Si vous relevez une incohérence ou une erreur, merci de contacter le service support de CARL Berger-Levrault.
Toute reproduction, en tout ou en partie, sous quelque forme que ce soit, est formellement interdite sans l’autorisation préalable de CARL Berger-Levrault.
Toutes les marques et noms de produits mentionnés dans ce document sont les propriétés de leurs détenteurs respectifs telles que répertoriées ci-dessous :
-
Android™ et Google Chrome® sont des marques déposées de Google LLC
-
ArcGIS® est une marque déposée d’Environmental Systems Research Institute.
-
Elasticsearch® est une marque déposée d’Elasticsearch B.V. aux États-Unis et dans d’autres pays.
-
Firefox® est une marque déposée de Mozilla Foundation.
-
Java™ et Oracle® sont des marques déposées d’Oracle Corporation.
-
PostgreSQL® est une marque déposée de The PostgreSQL Community Association of Canada.
-
Safari® est une marque d’Apple Inc., déposée aux États-Unis et dans d’autres pays.
-
Azure®, SQL Server®, Microsoft Edge® et Windows® sont des marques déposées de Microsoft Corporation.
-
Tomcat® est une marque déposée de l’Apache Software Foundation aux États-Unis et dans d’autres pays.
