#Interopérabilité

0 Abonnés · 67 Publications

Dans le domaine de la santé, l'interopérabilité est la capacité de différents systèmes informatiques et applications logicielles à communiquer, à échanger des données et à utiliser les informations qui ont été échangées.

Article Iryna Mykhailova · Nov 3, 2025 13m read

Bonjour à tous,

Continuons à travailler sur la génération de données de test et l'exportation des résultats via une API REST. 😁

Ici, je souhaite réutiliser la classe `datagen.restservice` créée dans l'article précédent : « Écriture d'un service API REST pour exporter les données patient générées au format .csv ».

Cette fois-ci, nous prévoyons de générer un bundle FHIR incluant plusieurs ressources pour tester le référentiel FHIR.

Voici une référence si vous souhaitez en savoir plus sur FHIR : « The Concept of FHIR: A Healthcare Data Standard Designed for the Future ».

C'est parti ! 😆

0
0 10
Article Iryna Mykhailova · Oct 23, 2025 6m read

Salut,

C'est moi encore 😁. Je travaille actuellement à la génération de fausses données patients à des fins de test avec Chat-GPT et Python. J'aimerais également partager mon apprentissage. 😑

Tout d'abord, créer un service d'API REST personnalisé est facile en utilisant %CSP.REST.

Commençons ! 😂

1. Créez une classe datagen.restservice qui étend %CSP.REST.

Class datagen.restservice Extends%CSP.REST
{
Parameter CONTENTTYPE = "application/json";
}

2. Ajoutez une fonction genpatientcsv() pour générer les données du patient et les regrouper dans une chaîne csv

0
0 18
Article Guillaume Rongier · Sept 16, 2025 18m read

img

Dans cette section, nous allons découvrir comment utiliser Python comme langage principal dans IRIS, ce qui vous permettra d'écrire la logique de votre application en Python tout en profitant de la puissance d'IRIS.

Utilisation (irispython)

Tout d'abord, nous allons commencer par la méthode officielle, qui consiste à la mise en œuvre de l'interpréteur irispython.

Vous pouvez utiliser l'interpréteur irispython pour exécuter du code Python directement dans IRIS. Cela vous permet d'écrire du code Python et de l'exécuter dans le contexte de votre application IRIS.

Qu'est-ce qu'irispython?

irispython est un interpréteur Python qui se trouve dans le répertoire d'installation d'IRIS (<installation_directory>/bin/irispython) et qui sert à exécuter du code Python dans le contexte d'IRIS.

Cela vous permettra :

  • De configurer sys.path pour inclure les bibliothèques et les modules Python IRIS.
    • Cela est réalisé par le fichier site.py, qui se trouve dans <installation_directory>/lib/python/iris_site.py.
    • Pour plus d'informations, consultez l'article sur les modules Introduction aux modules Python.
  • Vous pourrez ainsi importer les modules iris, qui sont des modules spéciaux permettant d'accéder aux fonctionnalités IRIS, telles que la conversion de n'importe quelle classe ObjectScript vers Python, et réciproquement.
  • Vous pourrez corriger les problèmes d'autorisations et le chargement dynamique des bibliothèques du noyau iris.

Exemple d'utilisation d'irispython

Vous pouvez exécuter l'interpréteur irispython à partir de la ligne de commande:

<installation_directory>/bin/irispython

Prenons un exemple simple:

# src/python/article/irispython_example.py
import requests
import iris

def run():
    response = requests.get("https://2eb86668f7ab407989787c97ec6b24ba.api.mockbin.io/")

    my_dict = response.json()

    for key, value in my_dict.items():
        print(f"{key}: {value}")  # print message: Hello World

    return my_dict

if __name__ == "__main__":
    print(f"Iris version: {iris.cls('%SYSTEM.Version').GetVersion()}")
    run()

Vous pouvez lancer ce script à l'aide de l'interpréteur irispython:

<installation_directory>/bin/irispython src/python/article/irispython_example.py

Vous verrez le résultat:

Iris version: IRIS for UNIX (Ubuntu Server LTS for x86-64 Containers) 2025.1 (Build 223U) Tue Mar 11 2025 18:23:31 EDT
message: Hello World

Il est présenté ici comment utiliser l'interpréteur irispython pour exécuter du code Python dans le contexte d'IRIS.

Avantages

  • Python d'abord : vous pouvez écrire la logique de votre application en Python, ce qui vous permet de profiter des fonctionnalités et des bibliothèques de Python.
  • Intégration IRIS : vous pouvez facilement intégrer votre code Python aux fonctionnalités et aux caractéristiques d'IRIS.

Inconvénients

  • Débogage limité : le débogage du code Python dans irispython n'est pas aussi simple que dans un environnement Python dédié.
    • Cela ne signifie pas que c'est impossible, mais ce n'est pas aussi facile que dans un environnement Python dédié.
    • Consultez la Section supoplémentaire for more details.
  • Environnement virtuel : il est difficile de configurer un environnement virtuel pour votre code Python dans irispython.
    • Cela ne signifie pas que c'est impossible, mais c'est difficile à réaliser à cause de l'environnement virtuel qui recherche par défaut un interpréteur appelé python ou python3, ce qui n'est pas le cas dans IRIS.
    • Consultez la Section supoplémentaire for more details.

Conclusion

En conclusion, en utilisant irispython, vous pouvez écrire la logique de votre application en Python tout en profitant de la puissance d'IRIS. Cependant, cet outil présente certaines limites en matière de débogage et de configuration de l'environnement virtuel.

Utilisation de WSGI

Dans cette section, nous allons découvrir comment utiliser WSGI (Interface de passerelle serveur Web) pour exécuter des applications Web Python dans IRIS.

WSGI est une interface standard entre les serveurs Web et les applications ou frameworks Web Python. Elle vous permet d'exécuter des applications Web Python dans un environnement de serveur Web.

IRIS prend en charge WSGI, ce qui signifie que vous pouvez exécuter des applications Web Python dans IRIS à l'aide du serveur WSGI intégré.

Utilisation

Pour utiliser WSGI dans IRIS, vous devez créer une application WSGI et l'enregistrer auprès du serveur web IRIS.

Pour plus de détails, consultez la documentation officielle.

Exemple d'utilisation de WSGI

Vous trouverez un template complet ici iris-flask-example.

Avantages

  • Frameworks Web Python : Pour créer vos applications Web, vous pouvez utiliser des frameworks Web Python populaires tels que Flask ou Django.
  • Intégration IRIS : Vous pouvez intégrer vos applications Web Python aux fonctionnalités IRIS en toute simplicité.

Inconvénients

  • Complexité : la configuration d'une application WSGI peut s'avérer plus complexe en comparaison avec une simple utilisation de uvicorn ou gunicorn avec un framework web Python.

Conclusion

En conclusion, l'utilisation de WSGI dans IRIS vous permet de créer des applications web puissantes à l'aide de Python tout en profitant des fonctionnalités et des capacités d'IRIS.

DB-API

Dans cette section, nous allons découvrir comment utiliser l'API Python DB pour interagir avec les bases de données IRIS.

L'API Python DB est une interface standard pour se connecter à des bases de données en Python. Elle vous permet d'exécuter des requêtes SQL et de récupérer les résultats dans la base de données.

Utilisation

Vous pouvez l'installer en utilisant pip:

pip install intersystems-irispython

Ensuite, vous pouvez utiliser l'API DB pour la connexion à une base de données IRIS et exécuter des requêtes SQL.

Exemple d'utilisation de DB-API

Vous l'utilisez comme n'importe quelle autre API Python DB. Voici un exemple:

# src/python/article/dbapi_example.py
import iris

def run():
    # Connexion à la base de données IRIS
# Ouverture d'une connexion au serveur
    args = {
        'hostname':'127.0.0.1', 
        'port': 1972,
        'namespace':'USER', 
        'username':'SuperUser', 
        'password':'SYS'
    }
    conn = iris.connect(**args)

    # Création d'un curseur
    cursor = conn.cursor()

    # Exécution d'une requête
    cursor.execute("SELECT 1")

    # Récupération de tous les résultats
    results = cursor.fetchall()

    for row in results:
        print(row)

    # Fermeture du curseur et de la connexion
    cursor.close()
    conn.close()
if __name__ == "__main__":
    run()

Ce script peut être exécuté à l'aide de n'importe quel interpréteur Python:

python3 /irisdev/app/src/python/article/dbapi_example.py

Vous verrez le résultat:

(1,)

Avantages

  • Interface standard : l'API DB fournit une interface standard pour se connecter aux bases de données, ce qui facilite le passage d'une base de données à l'autre.
  • Requêtes SQL : vous pouvez exécuter des requêtes SQL et récupérer les résultats de la base de données à l'aide de Python.
  • Accès à distance : vous pouvez vous connecter à des bases de données IRIS distantes à l'aide de l'API DB.

Inconvénients

  • Fonctionnalités limitées : l'API DB fournit uniquement un accès SQL à la base de données. Vous ne pourrez donc pas utiliser les fonctionnalités avancées d'IRIS telles que l'exécution de code ObjectScript ou Python.

Alternatives

Il existe également une édition communautaire de la DB-API, disponible ici : intersystems-irispython-community.

Elle offre une meilleure prise en charge de SQLAlchemy, Django, langchain et d'autres bibliothèques Python qui utilisent la DB-API.

Pour plus de détail, consultez la Section supplémentaire.

Conclusion

En conclusion, l'utilisation de l'API Python DB avec IRIS vous permet de créer des applications puissantes capables d'interagir de manière transparente avec votre base de données.

Notebook

Après avoir vu comment utiliser Python dans IRIS, nous allons découvrir comment utiliser Jupyter Notebooks avec IRIS.

Jupyter Notebooks est un excellent moyen d'écrire et d'exécuter du code Python de manière interactive. Il peut être utilisé avec IRIS pour profiter de ses fonctionnalités.

Utilisation

Pour utiliser Jupyter Notebooks avec IRIS, vous devez installer les packages notebook et ipykernel:

pip install notebook ipykernel

Ensuite, vous pouvez créer un nouveau Jupyter Notebook et sélectionner le noyau Python 3.

Exemple d'utilisation de Notebook

Vous pouvez créer un nouveau Jupyter Notebook et écrire le code suivant:

# src/python/article/my_notebook.ipynb
# Importation des modules nécessaires
import iris
# La magie
iris.system.Version.GetVersion()

Vous pouvez exécuter ce notebook à l'aide de Jupyter Notebook:

jupyter notebook src/python/article/my_notebook.ipynb

Avantages

  • Développement interactif : les notebooks Jupyter vous permettent d'écrire et d'exécuter du code Python de manière interactive, ce qui est idéal pour l'analyse et l'exploration de données.
  • Résulltat riche : vous pouvez afficher des résultats riches, tels que des graphiques et des tableaux, directement dans le notebook.
  • Documentation : vous pouvez ajouter de la documentation et des explications à côté de votre code, ce qui rend

Inconvénients

  • Configuration délicate : la configuration des notebooks Jupyter avec IRIS peut s'avérer délicate, en particulier au niveau de la configuration du noyau.

Conclusion

Pour conclure, l'utilisation des notebooks Jupyter avec IRIS vous permet d'écrire et d'exécuter du code Python de manière interactive tout en profitant des fonctionnalités d'IRIS. Cependant, la configuration peut s'avérer délicate, en particulier au niveau du noyau.

Section supplémentaire

À partir de cette section, nous aborderons certains sujets avancés liés à Python dans IRIS, tels que le débogage à distance du code Python ou encore l'utilisation d'environnements virtuels.

La plupart de ces sujets ne sont pas officiellement pris en charge par InterSystems, mais il est utile de les aborder si vous souhaitez utiliser Python dans IRIS.

Utilisation d'un interpréteur natif (sans irispython)

Dans cette section, nous allons voir comment utiliser un interpréteur Python natif au lieu de l'interpréteur irispython.

Cela vous permet d'utiliser des environnements virtuels prêts à l'emploi et d'utiliser l'interpréteur Python auquel vous êtes habitué.

Utilisation

Pour utiliser un interpréteur Python natif, vous devez installer IRIS localement sur votre machine et disposer du package iris-embedded-python-wrapper installé.

Vous pouvez l'installer avec pip:

pip install iris-embedded-python-wrapper

Ensuite, vous devez configurer certaines variables d'environnement pour faire référence à votre installation IRIS:

export IRISINSTALLDIR=<installation_directory>
export IRISUSERNAME=<username>
export IRISPASSWORD=<password>
export IRISNAMESPACE=<namespace>

Ensuite, vous pouvez exécuter votre code Python à l'aide de votre interpréteur Python natif:

python3 src/python/article/irispython_example.py
# src/python/article/irispython_example.py
import requests
import iris

def run():
    response = requests.get("https://2eb86668f7ab407989787c97ec6b24ba.api.mockbin.io/")

    my_dict = response.json()

    for key, value in my_dict.items():
        print(f"{key}: {value}")  # message d'impression: Hello World

    return my_dict

if __name__ == "__main__":
    print(f"Iris version: {iris.cls('%SYSTEM.Version').GetVersion()}")
    run()

Pour plus de détails; consultez iris-embedded-python-wrapper documentation.

Avantages

  • Environnements virtuels : vous pouvez utiliser des environnements virtuels avec votre interpréteur Python natif, ce qui vous permet de gérer plus facilement les dépendances.
  • Workflow familier : vous pouvez utiliser votre interpréteur Python habituel, ce qui facilite l'intégration avec vos flux de travail existants.
  • Débogage : vous pouvez utiliser vos outils de débogage Python préférés, tels que pdb ou ipdb, pour déboguer votre code Python dans IRIS.

Inconvénients

  • Complexité de la configuration : la configuration des variables d'environnement et du package iris-embedded-python-wrapper peut s'avérer complexe, en particulier pour les débutants.
  • Non pris en charge officiellement : cette approche n'est pas prise en charge officiellement par InterSystems. Vous risquez donc de rencontrer des problèmes qui ne sont pas documentés ni pris en charge.

Edition communautaire de DB-API

Dans cette section, nous allons explorer l'édition communautaire de l'API DB, disponible sur GitHub.

Utilisation

Vous pouvez l'installer avec pip:

pip install sqlalchemy-iris

Cette option installe l'édition communautaire de DB-API.

Ou avec une version spécifique:

pip install https://github.com/intersystems-community/intersystems-irispython/releases/download/3.9.3/intersystems_iris-3.9.3-py3-none-any.whl

Ensuite, vous pouvez utiliser l'API DB pour vous connecter à une base de données IRIS et exécuter des requêtes SQL ou tout autre code Python qui utilise l'API DB, comme SQLAlchemy, Django, langchain, pandas, etc.

Exemple d'utilisation de DB-API

Vous pouvez l'utiliser comme n'importe quelle autre API Python DB. Exemple:

# src/python/article/dbapi_community_example.py
import intersystems_iris.dbapi._DBAPI as dbapi

config = {
    "hostname": "localhost",
    "port": 1972,
    "namespace": "USER",
    "username": "_SYSTEM",
    "password": "SYS",
}

with dbapi.connect(**config) as conn:
    with conn.cursor() as cursor:
        cursor.execute("select ? as one, 2 as two", 1)   # le deuxième argument est la valeur du paramètre
        for row in cursor:
            one, two = row
            print(f"one: {one}")
            print(f"two: {two}")

Vous pouvez exécuter ce script à l'aide de n'importe quel interpréteur Python:

python3 /irisdev/app/src/python/article/dbapi_community_example.py

Ou à l'aide de sqlalchemy:

from sqlalchemy import create_engine, text

COMMUNITY_DRIVER_URL = "iris://_SYSTEM:SYS@localhost:1972/USER"
OFFICIAL_DRIVER_URL = "iris+intersystems://_SYSTEM:SYS@localhost:1972/USER"
EMBEDDED_PYTHON_DRIVER_URL = "iris+emb:///USER"

def run(driver):
    # Création d'un moteur à l'aide du pilote officiel
    engine = create_engine(driver)

    with engine.connect() as connection:
        # Exécution d'une requête
        result = connection.execute(text("SELECT 1 AS one, 2 AS two"))

        for row in result:
            print(f"one: {row.one}, two: {row.two}")

if __name__ == "__main__":
    run(OFFICIAL_DRIVER_URL)
    run(COMMUNITY_DRIVER_URL)
    run(EMBEDDED_PYTHON_DRIVER_URL)

Vous pouvez exécuter ce script à l'aide de n'importe quel interpréteur Python:

python3 /irisdev/app/src/python/article/dbapi_sqlalchemy_example.py

Vous verrez le résultat:

one: 1, two: 2
one: 1, two: 2
one: 1, two: 2

Avantages

  • Meilleur prise en charge : il offre une meilleure prise en charge de SQLAlchemy, Django, langchain et d'autres bibliothèques Python qui utilisent l'API DB.
  • Développé par la communauté : il est maintenu par la communauté, ce qui signifie qu'il est susceptible d'être mis à jour et amélioré au fil du temps.
  • Compatibilité : il est compatible avec l'API DB officielle d'InterSystems, vous pouvez donc passer facilement de l'édition officielle à l'édition communautaire.

Inconvénients

  • Vitesse : la version communautaire n'est peut-être pas aussi optimisée que la version officielle, ce qui peut entraîner des performances plus lentes dans certains cas.

Débogage de code Python dans IRIS

Dans cette section, nous allons voir comment déboguer du code Python dans IRIS.

Par défaut, le débogage du code Python dans IRIS (dans objectscript avec la balise de langage ou %SYS.Python) n'est pas possible, mais la communauté a trouvé une solution pour vous permettre de déboguer le code Python dans IRIS.

Utilisation

Installez d'abord IoP Interopérabilité en Python:

pip install iris-pex-embedded-python
iop --init

Cela installera IoP et les nouvelles classes ObjectScript qui vous permettront de déboguer le code Python dans IRIS.

Ensuite, vous pouvez utiliser la classe IOP.Wrapper pour encapsuler votre code Python et activer le débogage.

Class Article.DebuggingExample Extends %RegisteredObject
{
ClassMethod Run() As %Status
{
    set myScript = ##class(IOP.Wrapper).Import("my_script", "/irisdev/app/src/python/article/", 55550) // Ajustez le chemin d'accès à votre module
    Do myScript.run()
    Quit $$$OK
}
}

Configurez ensuite VsCode pour utiliser le débogueur IoP en ajoutant la configuration suivante à votre fichier launch.json:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Python in IRIS",
            "type": "python",
            "request": "attach",
            "port": 55550,
            "host": "localhost",
            "pathMappings": [
                {
                    "localRoot": "${workspaceFolder}/src/python/article",
                    "remoteRoot": "/irisdev/app/src/python/article"
                }
            ]
        }
    ]
}

Vous pouvez désormais exécuter votre code ObjectScript qui importe le module Python, puis connecter le débogueur dans VsCode au port 55550.

Vous pouvez exécuter ce script à l'aide de la commande suivante:

iris session iris -U IRISAPP '##class(Article.DebuggingExample).Run()'

Vous pouvez ensuite définir des points d'arrêt dans votre code Python, et le débogueur s'arrêtera à ces points d'arrêt, ce qui vous permettra d'inspecter les variables et de parcourir le code.

Vidéo de débogage à distance en action (pour IoP, mais le concept est le même):

Et vous disposez également de tracebacks dans votre code Python, ce qui est très utile pour le débogage.

Avec les tracebacks activés:

Traceback enabled

Avec les tracebacks désactivés:

Traceback disabled

Avantages

  • Débogage à distance : vous pouvez déboguer à distance le code Python exécuté dans IRIS, ce qui, à mon avis, change la donne.
  • Fonctionnalités de débogage Python : vous pouvez utiliser toutes les fonctionnalités de débogage Python, telles que les points d'arrêt, l'inspection des variables et l'exécution du code pas à pas.
  • Tracebacks : vous pouvez voir le traceback complet des erreurs dans votre code Python, ce qui est très utile pour le débogage.

Inconvénients

  • Complexité de la configuration : La configuration de l'IoP et du débogueur peut s'avérer complexe, en particulier pour les débutants.
  • Solution communautaire : Il s'agit d'une solution communautaire, qui peut donc être moins stable ou moins bien documentée que les solutions officielles.

Conclusion

En conclusion, le débogage de code Python dans IRIS est possible grâce à la solution communautaire IoP, qui vous permet d'utiliser le débogueur Python pour déboguer votre code Python exécuté dans IRIS. Cependant, cela nécessite une certaine configuration et peut ne pas être aussi stable que les solutions officielles.

IoP (Interopérabilité en Python)

Dans cette section, nous allons explorer la solution IoP (Interopérabilité en Python), qui vous permet d'exécuter du code Python dans IRIS dans une approche "Python d'abord".

Je développe cette solution depuis un certain temps déjà, c'est mon bébé, elle essaie de résoudre ou d'améliorer tous les points précédents que nous avons vus dans cette série d'articles.

Points clés de l'IoP:

  • Python d'abord : vous pouvez écrire la logique de votre application en Python, ce qui vous permet de profiter des fonctionnalités et des bibliothèques de Python.
  • Intégration IRIS : vous pouvez facilement intégrer votre code Python aux fonctionnalités et aux caractéristiques d'IRIS.
  • Débogage à distance : vous pouvez déboguer à distance votre code Python exécuté dans IRIS.
  • Tracebacks : vous pouvez voir le traceback complet des erreurs dans votre code Python, ce qui est très utile pour le débogage.
  • Environnements virtuels : vous bénéficiez d'une prise en charge des environnements virtuels, ce qui vous permet de gérer plus facilement les dépendances.

Pour en savoir plus sur IoP, vous pouvez consulter la documentation officielle.

Vous pouvez ensuite lire les articles suivants pour en savoir plus sur IoP:

🐍❤️ Comme vous pouvez le constater, IoP offre un moyen puissant d'intégrer Python à IRIS, ce qui facilite le développement et le débogage de vos applications.

Vous n'avez plus besoin d'utiliser irispython, vous n'avez plus à définir manuellement votre sys.path, vous pouvez utiliser des environnements virtuels et vous pouvez déboguer votre code Python exécuté dans IRIS.

Conclusion

J'espère que vous avez apprécié cette série d'articles sur Python dans IRIS.

N'hésitez pas à me contacter si vous avez des questions ou des commentaires à propos de cette série d'articles.

Bonne chance, amusez-vous avec Python dans IRIS!

0
0 25
Article Iryna Mykhailova · Juin 17, 2025 5m read

Lorsque nous créons un référentiel FHIR dans IRIS, nous avons un point de terminaison pour accéder à l'information, créer de nouvelles ressources, etc. Mais il y a certaines ressources dans FHIR que nous n'aurons probablement pas dans notre référentiel, par exemple, la ressource Binary (cette ressource renvoie des documents, comme des PDF par exemple).

J'ai créé un exemple dans lequel, quand une ressource est demandée via "Binary", l'endpoint FHIR renvoie une réponse, comme si elle existait dans le référentiel. 

Tout d'abord, nous avons besoin du Namespace (espace de noms) et du FHIR endpoint (point d'accès FHIR). Ensuite, nous devons configurer une production d'interopérabilité - Interoperability production - qui sera connectée à l'endpoint FHIR. Cette production devrait contenir les éléments suivants:

  • Business Operation:
    • HS.Util.Trace.Operations (Ceci est évidemment facultatif, mais peut s'avérer très utile)
    • HS.FHIRServer.Interop.Operation, avec la propriété TraceOperations configurée à *FULL*
  • Business Service:
    • HS.FHIRServer.Interop.Service, avec la propriété TraceOperations configurée à *FULL* et Target Config Name configurée à  HS.FHIRServer.Interop.Operation name

La production se présente comme suit:

Après avoir créé cette production, nous devons la connecter avec l'endpoint FHIR. Il faut donc éditer l'endpoint FHIR et configurer le paramètre Service Config Name avec le nom du Business Service:

Maintenant, si nous commençons à envoyer des requêtes au référentiel FHIR, nous verrons toutes les traces dans l'Afficheur de messages:

Nous pouvons maintenant établir un Business Process pour contrôler ce qu'il convient de faire avec des chemins d'accès spécifiques.

Dans cet exemple, nous avons un Business Process qui reçoit toutes les demandes (maintenant le Business Service est connecté à ce Business Process, au lieu du Business Operation) et 2 nouvelles Business Operations qui effectuent d'autres actions dont nous parlerons plus tard:

Jetons un coup d'œil au Business Process appelé FHIRRouter:

En regardant, nous verrons que, si RequestPath contient "Binary/", alors nous ferons quelque chose avec cette requête: générer notre réponse Binary personnalisée. Sinon, nous enverrons la demande au référentiel FHIR directement.

Jetons un coup d'œil à la séquence appelée "Generate Binary":

Tout d'abord, nous créons une nouvelle instance de HS.FHIRServer.Interop.Response. Nous obtenons document ID à partir du chemin d'accès: Request Path. Comment? Chaque fois que quelqu'un veut une ressource binaire, elle doit être demandée avec l'identifiant du document dans le chemin de l'URL, quelque chose comme ceci: ..../fhir/r4/Binary/XXXXX. Ainsi, pour extraire l'identifiant du document du chemin d'accès, nous utilisons l'expression suivante:

$Replace(request.Request.RequestPath,"Binary/","")

(Ce n'est pas vraiment raffiné, mais cela fonctionne).

Si nous avons un identifiant de document, nous faisons appel à un Business Operation appelée Find pour rechercher le nom de fichier associé à cet identifiant de document:

En fait, cette recherche deBusiness OperationFind renvoie toujours le même nom de fichier:

L'exemple ci-dessus montre ce que nous pouvons faire.

Si nous avons un nom de fichier, alors, nous appelons un autre Business Operation appelé File pour obtenir le contenu de ce fichier, encodé en base64:

And finally, we can return 2 kind of responses:

  • Si nous n'avons pas de contenu de fichier (puisque nous n 'avons pas d 'identifiant de document ou que nous ne trouvons pas le nom de fichier ou le contenu associé), nous renvoyons une réponse 404, avec cette réponse personnalisée:
 set json = {
    "resourceType": "OperationOutcome",
    "issue": [
        {
            "severity": "error",
            "code": "not-found",
            "diagnostics": "<HSFHIRErr>ResourceNotFound",
            "details": {
                "text": "No resource with type 'Binary'"
            }
        }
    ]
 }
 set json.issue.%Get(0).details.text = json.issue.%Get(0).details.text_" and id '"_context.docId_"'"
 set qs = ##class(HS.SDA3.QuickStream).%New()
 do qs.Write(json.%ToJSON())
 set response.QuickStreamId = qs.%Id()
 set response.ContentType = "application/fhir+json"
 set response.CharSet = "UTF-8"
  • Si nous avons le contenu du fichier, nous renvoyons une réponse 200 avec cette réponse personnalisée:
 set json = {
  "resourceType": "Binary",
  "id": "",
  "contentType": "application/pdf",
  "securityContext": {
    "reference": "DocumentReference/"
  },
  "data": ""
 }
 set json.id = context.docId
 set json.securityContext.reference = json.securityContext.reference_json.id
 set json.data = context.content.Read(context.content.Size)
 
 set qs = ##class(HS.SDA3.QuickStream).%New()
 do qs.Write(json.%ToJSON())
 set response.QuickStreamId = qs.%Id()
 set response.ContentType = "application/fhir+json"
 set response.CharSet = "UTF-8"

La clé ici est de créer un HS.SDA3.QuickStream, qui contient l'objet JSON. Et d'ajouter ce QuickStream à la réponse.

Et maintenant, si nous testons notre point d'accès, si nous demandons un document de type Binary, nous verrons la réponse:

Et si nous requérons un document de type Binary qui n'existe pas (vous pouvez le tester sans spécifier l'identifiant du document), nous obtiendrons la réponse 404:

En résumé, en connectant notre endpoint FHIR avec l'interopérabilité, nous pouvons faire tout ce que nous voulons, avec toutes les capacités d'InterSystems IRIS.

0
0 24
Annonce Irène Mykhailova · Juin 16, 2025

Bonjour à tous,

L'équipe Certification d'InterSystems Learning Services développe actuellement deux nouveaux examens de certification HealthShare Unified Care Record. Nous sollicitons les commentaires de notre communauté afin de nous aider à évaluer et à définir leur contenu. Veuillez noter que ces examens remplaceront l'examen de spécialiste technique HealthShare Unified Care Record, que nous prévoyons de supprimer en janvier 2026. Les certifications obtenues dans cette technologie avant la suppression de l'examen resteront valables cinq ans à compter de la date d'obtention.

0
0 22
Article Guillaume Rongier · Juin 12, 2025 4m read

   

L'incroyable Iris-nator est arrivé en ville.

Il lit dans vos pensées : en vous posant quelques questions, il devine le personnage auquel vous pensez.

Oserez-vous vous y risquer?

Certains d'entre vous connaissent peut-être le jeu Akinator, où un génie devine le personnage auquel vous pensez en vous posant des questions et en vous laissant répondre par "oui" ou "non".

Pas d'IA qui analyse vos réseaux sociaux, pas de microphones qui vous écoutent... Alors comment ça marche?

Le secret réside dans un algorithme simple et dans le grand nombre de personnes qui jouent et alimentent la base de données.

Comment ça marche?

Définissons un terme: Nœud.

Un nœud peut être une question ou le nom d'un personnage.

Si c'est une question, elle aura deux réponses : Oui ou Non.

 

Attribuons-lui maintenant une valeur.

À la question, nous attribuerons l'ID 1, à la réponse affirmative, nous attribuerons l'ID 2 et à la réponse négative, l'ID 3.

Imaginons maintenant que les réponses affirmative et négative renvoient chacune une autre question, avec les caractères correspondants pour "oui" et "non".

 

Nous pouvons voir une tendance entre les questions et les réponses.

Les réponses affirmatives sont deux fois l'identifiant de la question, et les réponses négatives sont deux fois l'identifiant de la question plus un.

Ensuite, si nous avons le nœud n, le nœud suivant à afficher sera le nœud n*2 si la réponse est "oui" ou le nœud (n*2)+1 si la réponse est "non".

Prenons un exemple:

 

Supposons que je pense à Snoopy et que la question soit "Votre personnage est-il fictif?". La réponse "oui" nous indiquerait que le personnage auquel nous avons pensé est "Superman", mais ce n'est pas correct.

Comment transformer notre réponse en une question qui nous mène à Snoopy?

Nous avons besoin d'une caractéristique qui nous différencie de Superman, dans ce cas, nous demanderons "Votre personnage est-il un chien?". La réponse affirmative serait alors "Snoopy" et la réponse négative "Superman".

Cette nouvelle question remplacera l'ID du nœud "Superman", le personnage "Snoopy" aura le double du nœud de la nouvelle question et le personnage "Superman" aura le double du nœud de la nouvelle question plus un.

 

De cette façon, si nous créons beaucoup de questions et de réponses, notre Iris-nator sera capable de deviner n'importe quel personnage auquel vous avez pensé.

Fonctionnement d'Iris-nator?

Créez une table contenant les informations relatives aux nœuds:

Class Irisnator.Data.Nodes Extends%Persistent
{

/// NodeId (ID du nœud)Property NodeId As%Numeric;/// Texte du nœudProperty Text As%String(MAXLEN = "");/// Type de nœud (0 = texte, 1 = question)Property Question As%Boolean [ InitialExpression = 0 ];/// Verbe de la questionProperty Verb As%String(MAXLEN = ""); }

Remarque: Pourquoi y a-t-il un champ appelé "verbe"? Parce que la question s'affiche sous la forme {verbe} votre personnage {texte}? Il faut donc savoir quel est le verbe (est, avait, fait, etc.)

Le front-end est créé avec Angular19. Pour communiquer avec IRIS, j'ai créé plusieurs méthodes API:

GET localhost:52773/irisnator/api/node/:nodeId

Renvoie les informations relatives au nœud, y compris le NodId pour les réponses Oui et Non

{
    "nodeId": 1,
    "text": "a woman",
    "verb": "is",
    "question": true,
    "nodeYes": 2,
    "nodeNo": 3
}

GET localhost:52773/irisnator/api/score/:top

Renvoie le meilleur score. Ce meilleur score correspond au nombre de fois où un caractère a été atteint.

{
    "score": [
        {
            "characterName": "Superman",
            "score": 8
        },
        {
            "characterName": "Maddona",
            "score": 3
        },
        {
            "characterName": "Snoopy",
            "score": 1
        }
    ]
}

POST localhost:52773/irisnator/api/node

Lorsque Iris-nator ne parvient pas à deviner votre personnage, nous remplissons un formulaire avec les données du nouveau personnage et la question à poser pour le différencier du personnage auquel il correspondait.

Ensuite, déplacez le personnage en cours vers la réponse "non" et attribuez l'identifiant à la nouvelle question.

{
    "nodeId": 507,
    "newCharacter": "Snoopy",
    "oldCharacter": "Superman",
    "text": "a dog",
    "verb": "is"
}

De plus, Snoopy sera ajouté à la liste des personnages échoués.

POST localhost:52773/irisnator/api/score

Cette méthode définit le score d'un personnage, qu'il ait réussi ou non.

{
    "characterName": "Snoopy",
    "success": true
}

 

Découvrez le fonctionnement de l'application dans la vidéo suivante, profitez-en bien!!!

<iframe allowfullscreen="" frameborder="0" height="360" src="https://www.youtube.com/embed/v5GsiXJDgC8" width="640"></iframe>

0
0 34
Article Irène Mykhailova · Mai 23, 2025 2m read

Après avoir déployé un nouveau conteneur basé sur containers.intersystems.com/intersystems/irishealth:2023.1 cette semaine, nous avons soudainement constaté que notre dépôt FHIR affichait une erreur 500. Ce problème est dû à des violations de PROTECT sur le nouvel espace de noms et la nouvelle base de données HSSYSLOCALTEMP utilisés par cette version des composants FHIR d'IRIS for Health. Pour résoudre ce problème, ajoutez « %DB_HSSYSLOCALTEMP » aux applications Web qui gèrent les requêtes FHIR. Vous pouvez créer un script pour cela en exécutant la méthode de classe suivante dans les espaces de noms qui définissent ces applications Web

do ##class(HS.HealthConnect.FHIRServer.Upgrade.MethodsV6).AddLOCALTEMPRoleToCSP()

Dans notre cas, cela n'était pas suffisant. Dans certains de nos codes personnalisés, nous avions besoin d'accéder au jeton porteur JWT envoyé par le client. Nous pouvions le récupérer depuis l'élément AdditionalInfo « USER:OAuthToken », qui n'est plus présent dans la version 2023.6.1.809, comme décrit dans https://docs.intersystems.com/upgrade/results?product=ifh&amp;versionFrom=2023.1.0&amp;versionTo=2023.1.6&amp;categories=Business%20Intelligence,Cloud,Core,Development%20Tools,Driver%20Technologies,Embedded%20Python,External%20Languages,FHIR,Healthcare%20Interoperability,Interoperability,Machine%20Learning,Mirroring,Monitoring,Natural%20Language%20Processing,SQL,Security,Sharding,Web%20Applications&amp;audience=All&amp;changes=121 Nous avons contourné ce problème en ajoutant la logique suivante pour récupérer le jeton depuis le cache de jetons :

$$$ThrowOnError(##class(HS.HC.Util.InfoCache).GetTokenInfo(pInteropRequest.Request.AdditionalInfo.GetAt("USER:TokenId"), .pTokenInfo)) set OAuthToken = pTokenInfo("token_string")

0
0 23
InterSystems officiel Adeline Icard · Mai 22, 2025

Nous publions une version intermédiaire pour InterSystems IRIS, IRIS for Health et Health Connect 2025.1 (version 2025.1.0.225.1) afin de résoudre un problème d'interopérabilité critique affectant les utilisateurs utilisant des hôtes métier compatibles SDS.

Quel est le problème ?

0
0 21
Article Lorenzo Scalese · Mai 7, 2025 6m read

Introduction

À mesure que l'automatisation pilotée par l'IA devient un élément essentiel des systèmes d'information modernes, l'intégration des capacités d'IA dans les plateformes existantes doit être transparente et efficace. Le projet IRIS Agent montre comment l'IA générative peut fonctionner sans effort avec InterSystems IRIS, grâce à son puissant cadre d'interopérabilité, sans qu'il soit nécessaire d'apprendre Python ou de créer des workflows d'IA distincts à partir de zéro.
Ce projet examine la manière dont ChatGPT et Anthropic Claude, deux modèles d'IA parmi les plus avancés, peuvent interagir avec IRIS à l'aide de GPT personnalisés et du protocole MCP (Model Context Protocol). Plutôt que de créer des pipelines d'IA isolés, IRIS Agent traite l'IA comme un service d'interopérabilité, permettant ainsi aux organisations d'améliorer l'automatisation, la prise de décision et le traitement des données sans perturber leur architecture existante.
En s'appuyant sur des outils d'interopérabilité natifs d'IRIS, les développeurs peuvent intégrer des modèles d'IA de manière transparente, comme n'importe quel autre composant du système. Cette approche garantit la stabilité, la sécurité, l'évolutivité et l'auditabilité, tout en permettant une interaction en langage naturel, la récupération de données en temps réel et l'administration automatisée du système, le tout dans l'environnement familier d'IRIS.

Technologies sous-jacentes à IRIS Agent

Le projet IRIS Agent s'appuie sur un ensemble de technologies puissantes pour garantir efficacité, évolutivité et intégration transparente:

  • InterSystems IRIS – Une plateforme robuste dédiée au développement d'applications et à l'intégration de données, qui utilise ObjectScript pour le code côté serveur.
  • Custom GPT Bot – Un assistant IA personnalisé conçu pour rationaliser les interactions avec le système, basé sur ChatGPT.
  • Claude AI Desktop – Facilite la communication avec le serveur via le protocole MCP (Model Context Protocol).
  • Node.js – Gère les communications avec le serveur MCP
  • OpenAPI – Documentation API standardisée.
  • Docker – Compartimente l'application pour simplifier le déploiement et la gestion des dépendances.

Présentation interne

Voici à quoi ressemble notre projet sous le capot IRIS:

La Production comprend les éléments suivants:

  • LanguageModelIn: un service qui reçoit une requête API et la redirige vers l'opération responsable.
  • Meds: une opération qui recherche des médicaments sur une API tierce.
  • Metrics: une opération qui recherche des informations OPS telles que les journaux, les erreurs et les messages dans le système Iris.
  • Namespaces: une opération qui répertorie, recherche et modifie les espaces de noms dans le système Iris.
  • Users: une opération qui répertorie, recherche, crée et supprime des utilisateurs dans le système Iris.

Le fonctionnement du service est particulièrement visible dans l'afficheur de messages et les traces. Il peut nous aider à suivre les opérations et à diagnostiquer les problèmes, par exemple les requêtes:

…et les réponses:


L'un des points forts de ce projet réside dans le fait que le service LanguageModelIn génère automatiquement une documentation API ouverte pour les opérations métier dans le cadre de la production IRIS Interoperability. Cette API  nous permet de connecter facilement les GPT personnalisés à ChatGPT et au serveur MCP (Model Context Protocol) à Claude AI Desktop. 

Intégration avec ChatGPT 

Après avoir terminé tous les processus d'installation et de configuration, que vous trouverez dans notre fichier ReadMe, ReadMe, demandons à notre agent IRIS GPT d'OpenAI quelles sont ses fonctionnalités actuelles:

  

Et créez un nouvel utilisateur…

   


Vérification des mises à jour...

   

Intégration avec des Sources de données externes

L'une des fonctionnalités remarquables de l'agent IRIS est sa capacité à interroger de manière transparente non seulement les données stockées dans la base de données InterSystems IRIS, mais également des sources de données externes. Dans notre exemple, l'agent s'intègre à l'OpenFDA API pour fournir des informations en temps réel sur les médicaments. Cela permet aux utilisateurs de rechercher des informations sur les médicaments, des rapports de sécurité et des données de conformité réglementaire directement dans le système. 
Dans notre projet, l'API offre la possibilité de rechercher des médicaments par leur nom. Recherchons donc les médicaments dont le nom contient le mot "flu".

   

Si vous souhaitez l'essayer dès maintenant, suivez le lien et engagez une conversation avec notre IRIS Agent démo.

Intégration avec Claude AI Desktop

L'une des fonctionnalités clés de l'agent IRIS est sa capacité à interagir avec Claude AI Desktop, un assistant IA local développé par Anthropic. L'intégration est assurée par le protocole MCP (Model Context Protocol), qui facilite la communication entre Claude et les applications externes. Pour ce faire, l'agent IRIS utilise un serveur MCP Node.js dédié qui sert d'intermédiaire, traitant les requêtes entrantes et les acheminant entre Claude et le système IRIS.
Cette configuration permet aux utilisateurs d'interagir directement avec l'agent IRIS via l'interface Claude, en émettant des commandes en langage naturel pour récupérer des données système, gérer les configurations et exécuter des tâches administratives. Le serveur MCP garantit un échange de données fluide, tout en maintenant l'efficacité et la sécurité, et fournit aux administrateurs un assistant puissant basé sur l'IA pour la gestion du système.

         

Conclusion

Le projet IRIS Agent présente le potentiel de l'automatisation pilotée par l'IA dans les environnements d'entreprise modernes. En intégrant de manière transparente InterSystems IRIS, Claude AI et Custom GPT, il simplifie la gestion des systèmes, améliore l'efficacité et ouvre la voie à de futures innovations. Notre projet démontre également que vous êtes déjà prêt pour la révolution de l'IA avec InterSystems IRIS!


Si vous avez apprécié la découverte d'IRIS Agent et de ses fonctionnalités et que vous souhaitez nous soutenir, veuillez prendre quelques instants pour voter pour notre application ici https://openexchange.intersystems.com/contest/40. Je vous remercie!


Développeurs de projet:

Banksia Global est une société de conseil technologique de premier plan qui aide les organisations à exploiter pleinement le potentiel des solutions modernes de gestion des données. En mettant l'accent sur la plateforme InterSystems IRIS, Banksia Global fournit des conseils stratégiques, des services d'intégration de systèmes et de développement de logiciels personnalisés à des clients issus de divers secteurs. Son expertise réside dans la fourniture de solutions hautement performantes et évolutives qui permettent aux entreprises de stimuler l'innovation, de rationaliser leurs opérations et de saisir de nouvelles opportunités. Réputée pour son approche collaborative et agile, Banksia Global travaille en étroite collaboration avec ses clients afin de s'assurer que chaque solution est adaptée à leurs besoins spécifiques, favorisant ainsi des partenariats à long terme et une croissance durable.

0
0 59
Article Corentin Blondeau · Avr 28, 2025 5m read

Bonjour à tous,
Cet article fait suite à la question que j'avais posée à la communauté L'adaptateur UDP ne fonctionne pas
Dans cet article, je vais vous présenter les points suivants
1) Qu'est-ce que "UDP"?
2) L'état actuel d'Iris avec UDP
3) Ma solution avec l'adaptateur UDP


1) Qu'est-ce que "UDP"?

L'acronyme UDP signifie User Datagram Protocol (protocole de datagramme utilisateur). Il s'agit de l'un des principaux protocoles composant la suite IP (Internet Protocol), utilisé pour la transmission de données sur un réseau. Voici quelques fonctionnalités clés de l'UDP:

  1. Sans connexion : L'UDP n'établit pas de connexion avant d'envoyer des données, ce qui signifie qu'il peut envoyer des messages (datagrammes) sans échange préalable.
  2. Peu fiable : Il n'y a aucune garantie que les messages envoyés via l'UDP arriveront à destination. Il n'y a pas de récupération des erreurs ni de retransmission des paquets perdus.
  3. Vitesse : Étant donné que l'UDP est sans connexion et qu'il ne nécessite pas de vérification ou de récuperation des erreurs, il est généralement plus rapide que le TCP (Transmission Control Protocol), ce qui le rend approprié pour les applications où la vitesse est cruciale.
  4. Constrruit autour des datagrammes : L'UDP envoie des messages sous forme de paquets discrets, qui peuvent être de longueur variable. Chaque paquet est traité indépendamment.
  5. Cas d'utilisation : L'UDP est couramment utilisé dans les applications où la vitesse est plus importante que la fiabilité, telles que la diffusion vidéo en continu, les jeux en ligne, la voix sur IP (VoIP) et les communications en temps réel.

En général, l'UDP est un protocole léger qui est utile pour des applications spécifiques où une faible latence est essentielle.


2) L'état actuel d'Iris avec UDP

Bien entendu, InterSystems IRIS permet d'utiliser ce protocole pour envoyer et recevoir des données.
En tant que protocole REST, il y a deux façons de le faire :
- avec ##class(%Net.UDP).%New().
- avec EnsLib.UDP.OutboundAdapter et EnsLib.UDP.InboundAdapter

##class(%Net.UDP).%New()

Même si la documentation de la classe et très détaillée, voici le lien de la documentation d'InterSystems sur la façon de l'utiliser.
Pour envoyer/recevoir des données, il faut utiliser une instance de class(%Net.UDP).%New() et une méthode associée.
En résumé, pour envoyer des données (sur localhost avec le port 3001) :

SET client = ##class(%Net.UDP).%New()
SET addrbin = ##class(%Net.UDP).GetHostAddr("127.0.0.1")
Set status = client.Send("message text", addrbin, 3001)

Pour recevoir des données (sur localhost avec le port 3001) :

Set sobj = ##class(%Net.UDP).%New(3001,"127.0.0.1")
Set data = sobj.Recv()

 

EnsLib.UDP.OutboundAdapter and EnsLib.UDP.InboundAdapter

Ce dernier est plus simple : c'est un adaptateur.
La documentation : EnsLib.UDP.OutboundAdapter et EnsLib.UDP.InboundAdapter
Pour envoyer des données :

Set status = ..Adapter.SendStream(stream)

Pour obtenir des données :

Set status = ..Adapter.Receive(stream)


Cependant, cela ne fonctionne pas. J'ai posé ma question à la communauté "L'adaptateur UDP ne fonctionne pas" et j'ai créé un ticket pour le WRC.
La réponse a été formulée comme suit :

Cet exécutable sous-jacent n'est plus installé dans le produit depuis Ensemble 2018.1.

J'ai vérifié au niveau interne et le JIRA DP-437486 a été soumis pour mettre à jour ces adaptateurs afin d'utiliser la classe %Net.UDP, mais cela sera soumis à l'approbation de la gestion des produits et aux ressources de développement disponibles.

Malheureusement, la seule option possible actuellement est de créer votre propre adaptateur personnalisé en utilisant la classe %Net.UDP.

Voici les deux principales différences entre la classe (%Net.UDP) et l'adaptateur EnsLib.UDP.OutboundAdapter 

  • La classe %Net.UDP utilise la classe système $System.UDP, elle utilise donc le code du noyau Cache/IRIS pour envoyer/recevoir les messages UDP, alors que l'adaptateur UDP utilise un tuyau de commande pour appeler des exécutables externes afin d'envoyer/recevoir le message UDP.
  • La classe %Net.UDP envoie/lit une chaîne de caractères alors que l'adaptateur UDP utilise un flux pour envoyer/lire les messages.

3) Ma solution avec l'adaptateur UDP

J'ai donc écrit ma propre méthode (approuvée par le service d'assistance) pour envoyer des données :
 

/// Adaptateur pour l'envoi de données avec une connexion UDPClass USER.UDP.OutboundAdapter Extends Ens.Adapter
{

/// Hôte du serveur UDPProperty Host As%String [ Required ];/// Port du serveur UDPProperty Port As%Integer [ Required ];/// si 1, le texte qui sera envoyé est affichéProperty UDPTrace As%Integer(VALUELIST = ",0,1") [ InitialExpression = 0, Required ];Parameter SETTINGS = "Host:Basic,Port:Basic,UDPTrace:Basic";/// Envoi de "texte" par le biais de la connexion UDP Method SendDataText(text As%String) As%Status { Try { Set status = $$$OKIf..UDPTrace=1 { Do..ShowText(text) }

    <span class="hljs-keyword">Set</span> udpClient = <span class="hljs-keyword">##class</span>(<span class="hljs-built_in">%Net.UDP</span>).<span class="hljs-built_in">%New</span>()
    <span class="hljs-keyword">Set</span> addrbin = <span class="hljs-keyword">##class</span>(<span class="hljs-built_in">%Net.UDP</span>).GetHostAddr(<span class="hljs-built_in">..Host</span>)

    <span class="hljs-keyword">Set</span> sentBytes = udpClient.Send(text, addrbin, <span class="hljs-built_in">..Port</span>)
}
<span class="hljs-keyword">Catch</span> exception {
    <span class="hljs-keyword">Set</span> status = exception.AsStatus()
}    
<span class="hljs-keyword">Return</span> status

}

/// Conversion du "stream" en texte et son envoi via la connexion UDP Method SendDataStream(stream As%Stream.Object) As%Status { Try { Do stream.Rewind() Set text = ""While 'stream.AtEnd{ Set text = text _ stream.Read() }

    <span class="hljs-keyword">Set</span> status = <span class="hljs-built_in">..SendDataText</span>(text)
}
<span class="hljs-keyword">Catch</span> exception {
    <span class="hljs-keyword">Set</span> status = exception.AsStatus()
}    
<span class="hljs-keyword">Return</span> status

}

/// Conversion de l'"objet" en json et son envoi via la connexion UDP Method SendDataJSONObject(object As%RegisteredObject, format As%String = "iw") As%Status { Try { Set status = ##class(%ZEN.Auxiliary.jsonProvider).%WriteJSONStreamFromObject(.stream,object,,,,format) $$$ThrowOnError(status)

    <span class="hljs-keyword">Set</span> status = <span class="hljs-built_in">..SendDataStream</span>(stream)
}
<span class="hljs-keyword">Catch</span> exception {
    <span class="hljs-keyword">Set</span> status = exception.AsStatus()
}    
<span class="hljs-keyword">Return</span> status

}

/// Un texte est pris en entrée,/// Les traces de l'objet associé sont affichées Method ShowText(text As%String) { Set nbParty = $SYSTEM.SQL.CEILING($LENGTH(text)/1100) For ii=1:1:nbParty { $$$TRACE($EXTRACT(text,ii,ii+1100)) } }

}

J'espère que cet article a été, sinon utile, du moins intéressant.


Je n'ai pas testé EnsLib.UDP.InboundAdapter, donc n'hésitez pas à ajouter plus d'informations à la discussion.
Corentin

2
0 39
Article Sylvain Guilbaud · Avr 25, 2025 22m read

TLS, qu'est-ce que c'est ?

La TLS (Transport Layer Security ou "Sécurité de la couche de transport"), qui succède à SSL (Secure Sockets Layer ou "Couche de sockets sécurisée"), fournit de la sécurité (c'est-à-dire le chiffrement et l'authentification) sur une connexion TCP/IP. Si vous avez déjà remarqué le "s" sur les URLs "https" vous avez reconnu une connexion HTTP "sécurisée" par SSL/TLS. Dans le passé, seules les pages de connexion/autorisation sur le web utilisaient TLS, mais dans l'environnement hostile d'Internet d'aujourd'hui, les meilleures pratiques indiquent que nous devrions sécuriser toutes les connexions avec TLS.

Pourquoi utiliser TLS?

Alors, pourquoi mettre en œuvre TLS pour les connexions HL7 ? Alors que les violations de données, les rançongiciels et les vulnérabilités sont de plus en plus fréquents, chaque mesure que vous prenez pour renforcer la sécurité de ces précieuses sources de données devient plus cruciale. La TLS est une méthode éprouvée et bien comprise pour protéger les données en transit.

TLS fournit deux fonctionnalités principales qui nous sont bénéfiques : 1) le chiffrement et 2) l'authentification.

Chiffrement

Le chiffrement transforme les données en cours de transfert de sorte que seules les deux parties engagées dans la communication peuvent lire/comprendre les informations échangées. Dans la plupart des cas, seules les applications impliquées dans la connexion TLS peuvent interpréter les données transférées. Cela signifie que les acteurs malveillants opérant sur les serveurs ou réseaux de communication ne pourront pas lire les données, même s'ils parviennent à capturer les paquets TCP bruts à l'aide d'un renifleur de paquets (wiretap, wireshark, tcpdump, etc.).

Without TLS

Authentification

L'authentification garantit que chaque partie communique avec la partie prévue et non avec un imposteur. En s'appuyant sur l'échange de certificats (et la vérification de la preuve de propriété associée qui s'est produite lors d'un handshake TLS), lorsque vous utilisez TLS, vous pouvez être sûr que vous échangez des données avec une partie de confiance. Plusieurs attaques consistent à tromper un serveur pour qu'il communique avec un acteur malveillant en redirigeant le trafic vers le mauvais serveur (par exemple, l'emploi de DNS et d'ARP poisoning) Lorsque TLS est impliqué, les imposteurs doivent non seulement rediriger le trafic, mais aussi voler les certificats et les clés appartenant à la partie de confiance.

L'authentification protège non seulement contre les attaques intentionnelles de pirates informatiques ou de acteurs malveillants, mais aussi contre les erreurs de configuration accidentelles qui pourraient envoyer des données vers le ou les mauvais systèmes. Par exemple, si vous attribuez accidentellement l'adresse IP d'une connexion HL7 à un serveur qui n'utilise pas le certificat attendu, la vérification de la négociation TLS échouera avant l'envoi de données vers ce mauvais serveur.

Vérification d'hôte

Lors de la vérification, les clients ont la possibilité d'effectuer une vérification d'hôte. Cette vérification compare l'adresse IP ou le nom d'hôte utilisé dans la connexion avec les adresses IP et les noms d'hôte intégrés dans le certificat. Si cette vérification est activée et que l'adresse IP/l'hôte de la connexion ne correspond pas à une adresse IP/un hôte figurant dans le certificat, le handshake TLS échouera. Vous trouverez les adresses IP et les noms d'hôte dans les champs X.509 « Subject » et « Subject Alternative Name » présentés ci-dessous.

Preuve de la propriété d'un certificat avec une clé privée

Pour prouver la propriété des certificats échangés avec TLS, vous devez également avoir accès à la clé privée liée à la clé publique intégrée au certificat. Nous ne discuterons pas de la cryptographie employée pour la preuve de propriété avec une clé privée, mais vous devez savoir que l'accès à la clé privée de votre certificat est nécessaire pendant le handshake TLS.

TLS mutuel

Pour la plupart des connexions https établies par votre navigateur web, seul le certificat d'authenticité du serveur web est vérifié. Normalement, les serveurs web n'authentifient pas le client avec des certificats. Au lieu de cela, la plupart des serveurs web s'appuient sur l'authentification du client au niveau de l'application (formulaires de connexion, cookies, mots de passe, etc.).

Avec HL7, il est préférable que les deux côtés de la connexion soient authentifiés. Lorsque les deux côtés sont authentifiés, on parle de «TLS mutuel». Avec le TLS mutuel, le serveur et le client échangent leurs certificats et l'autre côté vérifie les certificats fournis avant de poursuivre la connexion et l'échange de données.

X.509 Certificats

X.509 Champs du certificat

Pour fournir le cryptage et l'authentification, les informations sur la clé publique et l'identité de chaque partie sont échangées dans des certificats [X.509] (https://en.wikipedia.org/wiki/X.509). Vous trouverez ci-dessous certains champs courants d'un certificat X.509 qui nous intéresseront:

  • Serial Number: numéro unique à un CA qui identifie ce certificat spécifique
  • Subject Public Key Info: clé publique du propriétaire
  • Subject: nom distinctif (DN) du serveur/service représenté par ce certificat
    • Ce champ peut être vide si des "Subject Alternative Names" (noms alternatifs du sujet) sont fournis.
  • Issuer: nom distinctif (DN) du CA qui a émis/signé ce certifica
  • Validity Not Before: date de mise en vigueur de ce certificat
  • Validity Not After: date d'expiration de ce certificat
  • Basic Constraints: indique s'il s'agit d'un CA ou non
  • Key Usage: l'utilisation prévue de la clé publique fournie par ce certificat
    • Valeurs d'exemple: digitalSignature, contentCommitment, keyEncipherment, dataEncipherment, keyAgreement, keyCertSign, cRLSign, encipherOnly, decipherOnly
  • Extended Key Usage: utilisations supplémentaires prévues de la clé publique fournie par ce certificat
    • Valeurs d'exemple: serverAuth, clientAuth, codeSigning, emailProtection, timeStamping, OCSPSigning, ipsecIKE, msCodeInd, msCodeCom, msCTLSign, msEFS
    • Pour les connexions TLS mutuelles, les deux modes d'utilisation serverAuth et clientAuth sont nécessaires.
  • Subject Key Identifier: identifie la clé publique du sujet fournie par ce certificat
  • Authority Key Identifier: identifie la clé publique du fournisseur utilisée pour vérifier ce certificat
  • Subject Alternative Name: contient un ou plusieurs noms alternatifs pour ce sujet
    • Les noms DNS et les adresses IP sont des noms alternatifs fréquemment fournis dans ce champ.
    • Subject Alternative Name est parfois abrégé en SAN.
    • Le nom DNS ou l'adresse IP utilisés dans la connexion doivent figurer dans cette liste ou dans le Common Name du Subject pour que la vérification de l'hôte soit réussie.

Noms distingués

Les champs Subject (Sujet) et Issuer (Émetteur) d'un certificat X.509 sont définis comme des Distinguished Names (DN, Noms Distingués). Les noms distingués sont constitués de plusieurs attributs, chaque attribut ayant le format <attr>=<value>. Voici une liste non exhaustive des attributs courants que l'on trouve dans les champs Subject et Issuer

AbréviationNomExempleRemarques
CNNom communCN=server1.domain.comLe nom de domaine complet (FQDN) d'un serveur/service
CPaysC=USCode pays à deux caractères
STÉtat (ou province)ST=MassachusettsNom complet de l'état/province
LLocalitéL=CambridgeVille, région, etc.
OOrganisationO=Best CorporationNom de l'organisation
OUUnité opérationnelleOU=FinanceDépartment, division, etc.

Selon les exemples du tableau ci-dessus, le DN complet pour cet exemple serait C=US, ST=Massachusetts, L=Cambridge, O=Best Corporation, OU=Finance, CN=server1.domain.com

Notez que le Common Name (nom commun) trouvé dans le Subject (sujet) est utilisé lors de la vérification de l'hôte et correspond normalement au nom de domaine complet (FQDN) du serveur ou du service associé au certificat. Les Subject Alternative Names (noms alternatifs du sujet) du certificat peuvent également être utilisés lors de la vérification de l'hôte.

Expiration du certificat

Les champs Validity Not Before (Validité avant la date) et Validity Not After (Validité après la date) du certificat fournissent une plage de dates entre lesquelles le certificat est valide

Normalement, les certificats feuille ont une validité d'un ou deux ans (bien que les sites Web soient encouragés à réduire leurs délais d'expiration à des périodes beaucoup plus courtes). Les autorités de certification ont généralement un délai d'expiration de plusieurs années.

L'expiration des certificats est une fonctionnalité TLS nécessaire mais peu pratique. Avant d'ajouter TLS à vos connexions HL7, assurez-vous d'avoir un plan pour remplacer les certificats avant leur expiration. Une fois qu'un certificat expire, vous ne pourrez plus établir de connexion TLS à l'aide de celui-ci.

Formats de certificat X.509

Les champs de ces certificats X.509 (ainsi que d'autres) sont structurés suivant le format ASN.1 et généralement enregistrés dans l'un des formats de fichier suivants :

Exemple d'encodage PEM d'un certificat X.509:

-----BEGIN CERTIFICATE-----
MIIEVTCCAz2gAwIBAgIQMm4hDSrdNjwKZtu3NtAA9DANBgkqhkiG9w0BAQsFADA7
MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVR29vZ2xlIFRydXN0IFNlcnZpY2VzMQww
CgYDVQQDEwNXUjIwHhcNMjUwMTIwMDgzNzU0WhcNMjUwNDE0MDgzNzUzWjAZMRcw
FQYDVQQDEw53d3cuZ29vZ2xlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IA
BDx/pIz8HwLWsWg16BG6YqeIYBGof9fn6z6QwQ2v6skSaJ9+0UaduP4J3K61Vn2v
US108M0Uo1R1PGkTvVlo+C+jggJAMIICPDAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0l
BAwwCgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQU3rId2EvtObeF
NL+Beadr56BlVZYwHwYDVR0jBBgwFoAU3hse7XkV1D43JMMhu+w0OW1CsjAwWAYI
KwYBBQUHAQEETDBKMCEGCCsGAQUFBzABhhVodHRwOi8vby5wa2kuZ29vZy93cjIw
JQYIKwYBBQUHMAKGGWh0dHA6Ly9pLnBraS5nb29nL3dyMi5jcnQwGQYDVR0RBBIw
EIIOd3d3Lmdvb2dsZS5jb20wEwYDVR0gBAwwCjAIBgZngQwBAgEwNgYDVR0fBC8w
LTAroCmgJ4YlaHR0cDovL2MucGtpLmdvb2cvd3IyLzlVVmJOMHc1RTZZLmNybDCC
AQMGCisGAQQB1nkCBAIEgfQEgfEA7wB2AE51oydcmhDDOFts1N8/Uusd8OCOG41p
wLH6ZLFimjnfAAABlIMTadcAAAQDAEcwRQIgf6SEH+xVO+nGDd0wHlOyVTbmCwUH
ADj7BJaSQDR1imsCIQDjJjt0NunwXS4IVp8BP0+1sx1BH6vaxgMFOATepoVlCwB1
AObSMWNAd4zBEEEG13G5zsHSQPaWhIb7uocyHf0eN45QAAABlIMTaeUAAAQDAEYw
RAIgBNtbWviWZQGIXLj6AIEoFKYQW4pmwjEfkQfB1txFV20CIHeouBJ1pYp6HY/n
3FqtzC34hFbgdMhhzosXRC8+9qfGMA0GCSqGSIb3DQEBCwUAA4IBAQCHB09Uz2gM
A/gRNfsyUYvFJ9J2lHCaUg/FT0OncW1WYqfnYjCxTlS6agVUPV7oIsLal52ZfYZU
lNZPu3r012S9C/gIAfdmnnpJEG7QmbDQZyjF7L59nEoJ80c/D3Rdk9iH45sFIdYK
USAO1VeH6O+kAtFN5/UYxyHJB5sDJ9Cl0Y1t91O1vZ4/PFdMv0HvlTA2nyCsGHu9
9PKS0tM1+uAT6/9abtqCBgojVp6/1jpx3sx3FqMtBSiB8QhsIiMa3X0Pu4t0HZ5j
YcAkxtIVpNJ8h50L/52PySJhW4gKm77xNCnAhAYCdX0sx76eKBxB4NqMdCR945HW
tDUHX+LWiuJX
-----END CERTIFICATE-----

Comme vous pouvez le voir, l'encodage PEM ajoute -----BEGIN CERTIFICATE----- et -----END CERTIFICATE----- aux données ASN.1 du certificat encodées en base64.

Établir la confiance avec les autorités de certification

Sur l'Internet ouvert, il serait impossible pour votre navigateur Web de connaître et de faire confiance au certificat de chaque site Web. Il y en a tout simplement trop! Pour contourner ce problème, votre navigateur Web délègue la confiance à un ensemble prédéterminé d'autorités de certification (AC). Les autorités de certification sont des entités qui vérifient qu'une personne demandant un certificat pour un site Web ou un domaine est bien propriétaire et responsable du serveur, du domaine ou des activités commerciales associés à la demande de certificat. Une fois que l'autorité de certification a vérifié un propriétaire, elle est en mesure d'émettre le certificat demandé.

Chaque autorité de certification est représentée par un ou plusieurs certificats X.509. Ces certificats CA sont utilisés pour signer tous les certificats émis par la CA. Si vous regardez dans le champ Issuer (Émetteur) d'un certificat X.509, vous trouverez une référence au certificat CA qui a créé et signé ce certificat.

Si un certificat est créé sans autorité de certification, il est appelé certificat auto-signé. Vous savez qu'un certificat est auto-signé si les champs Subject (Sujet) et Issuer (Émetteur) du certificat sont identiques.

En général, la CA crée un certificat root (racine) auto-signé avec une longue fenêtre d'expiration. Ce certificat racine est ensuite utilisé pour générer quelques autorités de certification intermédiaires, qui ont une fenêtre d'expiration légèrement plus courte. La CA racine sera sécurisée et rarement utilisée après la création des CA intermédiaires. Les CA intermédiaires seront utilisées pour émettre et signer les certificats leaf (feuille) au quotidien.

Les CA intermédiaires sont créées au lieu d'utiliser directement la CA racine afin de minimiser l'impact en cas de violation ou de mauvaise gestion d'un certificat. Si une seule CA intermédiaire est compromise, l'entreprise aura toujours les autres CA disponibles pour continuer à fournir le service.

Chaînes de certificats

Un certificat de connexion et tous les certificats CA impliqués dans l'émission et la signature de ce certificat peuvent être organisés en une structure appelée chaîne de certificats. Cette chaîne de certificats (décrite ci-dessous) sera utilisée pour vérifier et approuver le certificat de connexion.

Si vous suivez le certificat feuille d'une connexion jusqu'à la CA émettrice (en utilisant le champ Issuer) puis, à partir de cette CA, jusqu'à son émetteur (et ainsi de suite, jusqu'à ce que vous atteigniez un certificat racine auto-signé), vous aurez parcouru la chaîne de certificats.

Construction d'une chaîne de certificats

Faire confiance à un certificat

Votre navigateur Web et votre système d'exploitation conservent généralement une liste d'autorités de certification approuvées. Lors de la configuration d'une interface HL7 ou d'une autre application, vous dirigerez probablement votre interface vers un fichier CA-bundle contenant une liste de CA approuvées. Ce fichier contiendra généralement une liste d'un ou plusieurs certificats CA encodés au format PEM. Par exemple:

# Probablement, une CA intermédiaire
-----BEGIN CERTIFICATE-----
MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF
...
rqXRfboQnoZsG4q5WTP468SQvvG5
-----END CERTIFICATE-----

# Probablement, une CA racine
-----BEGIN CERTIFICATE-----
MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNV
...
WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg==
-----END CERTIFICATE-----

Lorsque votre navigateur Web (ou l'interface HL7) tente d'établir une connexion TLS, il utilise cette liste de certificats CA de confiance pour déterminer s'il fait confiance au certificat échangé lors du handshake TLS.

Le processus commence par le certificat racine et traverse la chaîne de certificats jusqu'au certificat CA suivant. Si le certificat CA n'est pas trouvé dans le magasin de confiance ou le fichier CA-bundle, le certificat racine n'est pas considéré comme fiable et la connexion TLS échoue.

Si le certificat CA ou le fichier CA-bundle est trouvé dans le magasin de confiance, le processus continue en remontant la chaîne de certificats, en vérifiant que chaque CA se trouvant sur le chemin est dans le magasin de confiance. Une fois que le certificat CA racine au sommet de la chaîne est vérifié (ainsi que tous les certificats CA intermédiaires se trouvant sur le chemin), le processus peut approuver le certificat feuille du serveur.

Détermination de la confiance

Le handshake TLS

Pour ajouter TLS à une connexion TCP/IP (comme un flux HL7), le client et le serveur doivent effectuer un handshake TLS après que la connexion TCP/IP a été établie. Ce handshake implique de s'accorder sur les chiffrements/méthodes de chiffrement, de s'accorder sur la version TLS, d'échanger des certificats X.509, de prouver la propriété de ces certificats et de valider que chaque partie fait confiance à l'autre.

Les étapes principales d'un handshake TLS sont les suivantes:

  1. Le client établit une connexion TCP/IP avec le serveur.
  2. Le client lance le handshake TLS.
  3. Le serveur envoie son certificat (et la preuve de sa propriété) au client.
  4. Le client vérifie le certificat du serveur.
  5. En cas de TLS mutuel, le client envoie son certificat (et la preuve de sa propriété) au serveur.
  6. En cas de TLS mutuel, le serveur vérifie le certificat du client.
  7. Le client et le serveur s'échangent des données encryptées.

Handshake TLS

1. Le client établit une connexion TCP/IP avec le serveur.

À l'étape n° 1, le client et le serveur effectuent un handshake TCP à la procédure de base « ternaire » [TCP 3-way handshake] (https://en.wikipedia.org/wiki/Transmission_Control_Protocol#Connection_establishment) pour établir une connexion TCP/IP entre eux. Dans un handshake à la procédure de base ternaire:

  1. Le client envoie un paquet SYN.
  2. Le serveur envoie un paquet SYN-ACK.
  3. Le client envoie un paquet ACK.

Une fois ce handshake terminé, la connexion TCP/IP est établie. L'étape suivante consiste à lancer le handshake TLS.

2. Le client lance le handshake TLS.

Une fois la connexion TCP établie, l'une des parties doit agir en tant que client et lancer le handshake TLS. Généralement, le processus qui a initié la connexion TCP est également responsable du lancement du handshake TLS, mais cela peut être inversé dans de rares cas.

Pour lancer le handshake TLS, le client envoie un message ClientHello au serveur. Ce message contient diverses options utilisées pour négocier les paramètres de sécurité de la connexion avec le serveur.

3. Le serveur envoie son certificat (et la preuve de sa propriété) au client.

Après avoir reçu le message ClientHello du client, le serveur répond à son tour par un message ServerHello. Celui-ci inclut les paramètres de sécurité négociés.

Après le message ServerHello, le serveur envoie également un message Certificate et CertificateVerify au client. Cela permet de partager la chaîne de certificats X.509 avec le client et de fournir la preuve de propriété de la clé privée associée au certificat.

4. Le client vérifie le certificat du serveur.

Une fois que le client a reçu les messages ServerHello, Certificate et CertificateVerify, il vérifie que le certificat est valide et approuvé (en comparant les CAs aux fichiers CA-bundle approuvés, au magasin de certificats du système opérationnel ou au magasin de certificats du navigateur web). Le client effectue également toute vérification de l'hôte (voir ci-dessus) pour s'assurer que l'adresse de connexion correspond aux adresses/IP du certificat.

5. S'il s'agit d'une connexion TLS mutuelle, le client envoie son certificat (et la preuve de propriété) au serveur.

S'il s'agit d'une connexion TLS mutuelle (déterminée par l'envoi d'un message CertificateRequest par le serveur), le client enverra un message Certificate incluant sa chaîne de certificats, puis un message CertificateVerify pour prouver qu'il est le propriétaire de la clé privée associée.

6. S'il s'agit d'une connexion TLS mutuelle, le serveur vérifie le certificat client.

Là encore, s'il s'agit d'une connexion TLS mutuelle, le serveur vérifie que la chaîne de certificats envoyée par le client est valide et approuvée.

7. Le client et le serveur s'échangent des données encryptées.

Si la négociation TLS se déroule sans erreur, le client et le serveur s'échangent des messages Finished (Terminé) pour achever la négociation. Après cela, les données encryptées peuvent être échangées entre le client et le serveur.

Configuration de TLS sur les interfaces HL7

Félicitations d'être arrivé jusqu'ici ! Maintenant que vous savez en quoi consiste TLS, comment procéderiez-vous pour mettre en œuvre le protocole TLS sur vos connexions HL7 ? De manière générale, voici les étapes à suivre pour configurer TLS sur vos connexions HL7.

  1. Choisissez une autorité de certification.
  2. Créez une clé et une demande de signature de certificat.
  3. Obtenez votre certificat auprès de votre CA.
  4. Obtenez la chaîne de certificats pour votre pair.
  5. Créez une configuration SSL pour la connexion.
  6. Ajoutez la configuration SSL à l'interface, faites rebondir l'interface et vérifiez le flux de messages.

1. Choisissez une autorité de certification.

La procédure que vous utiliserez pour obtenir un certificat et une clé pour votre serveur dépendra largement des politiques de sécurité de votre entreprise. Dans la plupart des cas, votre certificat sera signé par l'une des autorités de certification suivantes:

  1. Votre certificat sera signé par une CA interne à l'entreprise.
  • C'est mon option préférée, car votre entreprise dispose déjà de l'infrastructure nécessaire pour gérer les certificats et les CAs. Il vous suffit de travailler avec l'équipe qui possède cette infrastructure pour obtenir votre propre certificat pour vos interfaces HL7.
  1. Votre certificat sera signé par une CA publique.
  • Cette option est intéressante dans le sens où la CA publique dispose également de toute l'infrastructure nécessaire pour maintenir les certificats et les CAs. Cette option est sans doute exagérée pour la plupart des interfaces HL7, car les CA publiques fournissent généralement des certificats pour l'Internet ouvert ; les interfaces HL7 ont tendance à se connecter via un intranet privé, et non via l'Internet public.
  • L'obtention de certificats auprès d'une CA publique peut également entraîner des frai.
  1. Votre certificat sera signé par une CA que vous créerez et maintiendrezvous-même.
  • Cette option peut vous convenir, mais malheureusement, cela signifie que vous supportez la charge de la maintenance et de la sécurisation de votre configuration CA et de votre logiciel.
  • Vous l'utilisez à vos risques et périls!
  • Cette option est la plus complexe. Préparez-vous à une courbe d'apprentissage abrupte.
  • Vous pouvez utiliser des progiciels open source éprouvés pour gérer votre CA et vos certificats. La suite OpenSSL est une excellente option. Les autres options sont EJBCA, step-ca et cfssl.

2. Créez une clé et une demande de signature de certificat.

Après avoir choisi votre CA, l'étape suivante consiste à créer une clé privée et une demande de signature de certificat (CSR) . La manière dont vous générez la clé et la CSR dépendra de la politique de votre entreprise et de la CA choisie. Pour l'instant, nous allons simplement parler des étapes de manière générale.

Lors de la génération d'une clé privée, la clé publique associée est également générée. La clé publique sera intégrée à votre CSR et à votre certificat signé. Ces deux clés seront utilisées pour prouver la propriété de votre certificat signé lors de l'établissement d'une connexion TLS.

ATTENTION! Veillez à enregistrer votre clé privée dans un endroit sûr (de préférence dans un format protégé par un mot de passe). Si vous perdez cette clé, votre certificat ne sera plus utilisable. Si quelqu'un d'autre accède à cette clé, il pourra se faire passer pour votre serveur.

La demande de signature de certificat inclura des informations sur votre serveur, votre entreprise, votre clé publique, la manière d'utiliser le certificat, etc. Elle inclura également la preuve que vous possédez la clé privée associée. Cette CSR sera ensuite fournie à votre CA pour générer et signer votre certificat.

REMARQUE: lors de la création de la CSR, assurez-vous de demander une Extended Key Usage (utilisation étendue de la clé) à la fois pour serverAuth et clientAuth, si vous utilisez le TLS mutuel. La plupart des CA sont habituées à signer des certificats avec uniquement la clé serverAuth. Malheureusement, cela signifie que le certificat ne peut pas être utilisé comme certificat client dans une connexion TLS mutuelle.

3. Obtenez votre certificat auprès de votre CA.

Après avoir créé votre clé et votre CSR, soumettez la CSR à votre autorité de certification. Après avoir effectué plusieurs vérifications, votre CA devrait être en mesure de vous fournir un certificat signé et la chaîne de certificats associée. Ce certificat et cette chaîne doivent être enregistrés au format PEM. Si la CA a fourni votre certificat dans un format différent, vous devrez le convertir à l'aide d'un outil tel qu'OpenSSL.

4. Obtenez la chaîne de certificats pour votre homologue.

Les étapes précédentes étaient axées sur l'obtention d'un certificat pour votre serveur. Vous devriez pouvoir utiliser ce certificat (et la clé associée) avec chaque connexion HL7 vers/depuis ce serveur. Vous devrez également obtenir les chaînes de certificats pour chacun des systèmes/homologues auxquels vous vous connecterez.

Les chaînes de certificats de chaque homologue devront être enregistrées dans un fichier au format PEM. Ce CA-bundle n'aura pas besoin de contenir les certificats feuille ; il doit uniquement contenir les certificats CA intermédiaires et racine.

Veillez à fournir à votre homologue un CA-bundle contenant vos CA intermédiaires et racine. Cela lui permettra de faire confiance à votre certificat lorsque vous établirez une connexion.

5. Créez une configuration SSL pour la connexion.

Dans Health Connect d'InterSystems, il vous faudra créer des configurations SSL client et serveur pour chaque système auquel votre serveur se connectera. Ces configurations SSL dirigeront vers le fichier CA-bundle du système associé et vers les fichiers clé et de certificat de votre serveur.

Les configurations SSL client sont utilisées lors des opérations pour lancer le handshake TLS. Les configurations SSL serveur sont utilisées sur les services pour répondre aux handshakes TLS. Si un système dispose à la fois de services entrants et de services sortants, il faudra configurer à la fois une configuration SSL client et une configuration SSL serveur pour ce système.

Pour créer une configuration SSL client:

  1. Accédez à System Administration > Security > SSL/TLS Configurations (Administration système > Sécurité > Configurations SSL/TLS).
  2. Appuyeze sur Create New Configuration (Créer une nouvelle configuration).
  3. Donnez un Configuration Name (Nom de configuration) et une Description (Description) à votre configuration SSL.
  4. Assurez-vous que votre configuration SSL est Enabled (Activée).
  5. Choisissez Client comme Type.
  6. Choisissez Require (Obligatoire) pour le champ Server certificate verification (Vérification du certificat serveur). Cela effectue une vérification de l'hôte sur la connexion.
  7. Dirigez le champ File (Fichier) contenant le(s) certificat(s) CA de confiance vers le fichier CA-bundle contenant les CA intermédiaires et racines (au format PEM) du système auquel vous vous connectez.
  8. Dirigez le champ File (Fichier) contenant le certificat de ce client vers le fichier contenant le certificat X.509 de votre serveur au format PEM.
  9. Dirigez le champ File (Fichier) contenant la clé privée associée vers le fichier contenant la clé privée de votre certificat.
  10. Le Private key type (type de clé privée) sera très probablement RSA (chiffrement RSA). Cela devrait correspondre au type de votre clé privée.
  11. Si votre clé privée est protégée par un mot de passe (comme cela devrait être le cas), saisissez le mot de passe dans les champs Private key password (mot de passe de la clé privée) et Private key password (confirm) (confirmer le mot de passe de la clé privée).
  12. Vous pouvez probablement laisser les autres champs à leurs valeurs par défaut.

Pour créer une configuration de serveur SSL:

  1. Go to System Administration > Security > SSL/TLS Configurations.
  2. Appuyeze sur Create New Configuration (Créer une nouvelle configuration).
  3. Donnez un Configuration Name (Nom de configuration) et une Description (Description) à votre configuration SSL.
  4. Assurez-vous que votre configuration SSL est Enabled (Activée).
  5. Choisissez Server comme Type.
  6. Choisissez Require (Obligatoire) pour le champ Client certificate verification (Vérification du certificat client). Cela permettra de s'assurer que le TLS mutuel est exécuté.
  7. Dirigez File containing trusted Certificate Authority certificate(s) (Fichier contenant le(s) certificat(s) de l'autorité de certification de confiance) vers le fichier CA-bundle contenant les CA intermédiaires et racines (au format PEM) du système auquel vous vous connectez.
  8. Dirigez File containing this server's certificate (Fichier contenant le certificat de ce serveur) vers le fichier contenant le certificat X.509 de votre serveur au format PEM.
  9. Dirigez File containing associated private key (Fichier contenant la clé privée associée) vers le fichier contenant la clé privée de votre certificat.
  10. Le Private key type (type de clé privée) sera très probablement RSA (chiffrement RSA). Cela devrait correspondre au type de votre clé privée.
  11. Si votre clé privée est protégée par un mot de passe (comme cela devrait être le cas), saisissez le mot de passe dans les champs Private key password (mot de passe de la clé privée) et Private key password (confirm) (confirmer le mot de passe de la clé privée).
  12. Vous pouvez probablement laisser les autres champs à leurs valeurs par défaut.

configuration de configuration SSL

6. Ajoutez la configuration SSL à l'interface, relancez l'interface et vérifiez le flux de messages.

Une fois que vous avez créé les configurations SSL client et serveur, vous êtes prêt à activer TLS sur les interfaces. Pour chaque service ou opération, choisissez la configuration SSL associée dans le menu déroulant Connection Settings > SSL Configuration (Paramètres de connexion > Configuration SSL) qui se trouve dans l'onglet Settings (Paramètres) de l'interface.

Après avoir relancé l'interface, vous verrez la connexion se rétablir. Lorsqu'un nouveau message est transféré, un statut Completed (Terminé) indique que TLS fonctionne. Si TLS ne fonctionne pas, la connexion sera interrompue à chaque tentative de message.

Pour vous aider à déboguer les problèmes avec TLS, il se peut que vous ayez besoin d'utiliser des outils tels que tcpdump, Wireshark ou l'utilitaire s_client d'OpenSSL.

Conclusion

Nous avons fait une analyse très approfondie du sujet SSL/TLS. Il y a tellement d'autres informations qui n'ont pas été incluses dans cet article. J'espère que cet article vous a fourni un aperçu suffisant du fonctionnement de TLS pour que vous puissiez rechercher les détails et obtenir plus d'informations si nécessaire.

Si vous recherchez une ressource approfondie sur TLS, consultez le site Web d'Ivan Ristić, fiestyduck.com et son livre, Bulletproof TLS and PKI. J'ai trouvé que ce livre était une excellente ressource pour en savoir plus sur l'utilisation de TLS.

0
0 48
Article Guillaume Rongier · Avr 14, 2025 5m read

Les référentiels, applications et serveurs FHIR servent généralement des données cliniques en petites quantités, par exemple pour renvoyer des données sur un patient, ses médicaments, ses vaccins, ses allergies, ou d'autres renseignements. Cependant, il est courant qu'une grande quantité de données au format FHIR/JSON soit demandée pour être utilisée pour charger des Data Lakes, identifier des cohortes étudiées, la santé de la population ou transférer des données d'un DME (dossier médical électronique) à un autre. Pour répondre à ces scénarios d'activités commerciales qui nécessitent d'importantes extractions et charges de données, il est recommandé d'utiliser la fonctionnalité d'accès aux données en masse FHIR fournie par l'institution HL7.

InterSystems IRIS for Health met en œuvre l' ccès aux données de masse FHIR (FHIR Bulk Data Access) avec la fonctionnalité BFC - Bulk FHIR Coordinator (https://docs.intersystems.com/irisforhealthlatest/csp/docbook/DocBook.UI.Page.cls?KEY=HXFHIR_bulk). Selon la documentation d'InterSystems, le BFC « simplifie l'interaction des données de masse FHIR pour les clients et, pour ne pas surcharger un serveur FHIR avec des demandes de données de masse, le Bulk FHIR Coordinator (BFC) d'InterSystems sert d'intermédiaire dans l'interaction entre un client de données de masse et un point d'extrémité de serveur de ressources FHIR pour les demandes de données de masse. Le Bulk FHIR Coordinator peut faciliter l'exportation de données de masse FHIR pour les serveurs de ressources FHIR qui ne prennent pas en charge nativement l'interaction de données de masse". Le diagramme de la documentation illustre comment le coordinateur FHIR en bloc sert d'intermédiaire dans l'interaction entre un client et les endpoints FHIR:

Le Coordinateur Bulk FHIR sert d'intermédiaire entre un client et un endpoint FHIR

Ainsi, si vous souhaitez migrer d'un serveur FHIR vers IRIS for Health, vous pouvez utiliser BFC pour vous connecter à un serveur FHIR cible afin d'obtenir toutes les données dont vous avez besoin sous forme de fichiers json (ressources ndjson), et les importer dans votre serveur FHIR InterSystems.

Dans cet article, vous découvrirez étape par étape les différentes manières de configurer et d'utiliser BFC pour obtenir toutes les données patient d'un référentiel FHIR dans des fichiers JSON en vue d'une utilisation ultérieure.

Étape 1 - Obtenir/configurer une instance IRIS for Health pour utiliser BFC

Si vous n'avez pas d'instance IRIS for Health, cliquez sur le lien suivant pour en obtenir une: https://openexchange.intersystems.com/package/iris-fhir-template. Suivez les procédures d'installation suivantes:

1.1 Installation de Docker:

Clone/git extrait le référentiel dans n'importe quel répertoire local

git clone https://github.com/intersystems-community/iris-fhir-template.git

Ouvrez le terminal dans ce répertoire et lancez:

docker-compose up -d


1.2 Ou installation de l'IPM (nécessite un IRIS for Health en cours d'exécution):

Ouvrez l'installation d'IRIS for Health avec le client IPM installé. Appel dans n'importe quel espace de nom:

USER>zpm "install fhir-server"

Ainsi, le serveur FHIR sera installé dans l'espace de noms FHIRSERVER.

Ou encore, pour une installation programmée, on peut appeler ce qui suit:

set sc=$zpm("install fhir-server")

Étape 2 - Création d'un nouveau justificatif d'identité

1. Access the Management Portal for the namespace FHIRSERVER (http://localhost:32783/csp/sys/%25CSP.Portal.Home.zen?$NAMESPACE=FHIRSERVER).

2. Accédez à l'Interopérabilité > Configuration > Informations d'identification:

3. Paramétrez les valeurs BulkCreds et enregistrez:

  • Identifiant: BulkCreds
  • Nom d'utilisateur: _SYSTEM
  • Mot de passe: SYS

Étape 3 - Configuration du BFC (Bulk Data Coordinator)

1. Accédez à BFC UI (http://localhost:32783/csp/healthshare/fhirserver/bulkfhir/index.html):

2. Appuyez sur le bouton + Nouvelle configuration > Création d'une nouvelle:

3. Configuration des paramètres:

  • Nom: BFC_Patients
  • Endpoint BFC (tout chemin relatif): /bulkfhir/patients
  • Gardez tous les autres paramètres tels quels

4. Appuyez sur le bouton Next.

5. Selectionnez HS.BulkFHIR.Auth.BasicAuth.Adapter et appuyez sur le bouton Next

6. Selectionnez HS.BulkFHIR.Fetch.PureFHIR.Adapter pour le champ Fetch Adapter et définissez les valeurs suivantes:

  • URL de l'endpoint: http://fhir-template:52773/fhir/r4
  • Configuration SSL: BFC_SSL
  • Type d'autorisation: HTTP
  • Identifiant HTTP: BulkCreds
  • Acceptez les valeurs par défaut pour tous les autres champs

7. Appuyez sur le bouton Next.

8. Selectionnez la valeur de HS.BulkFHIR.Storage.File.Adapter pour le champ Storage Adapter et définissez les valeurs suivantes:

  • Storage Adapter: HS.BulkFHIR.Storage.File.Adapter
  • URL du fichier: /bulkfhir/file
  • Répertoire: /usr/irissys/mgr/Temp/BulkFHIR/FHIRSERVER/

9. Appuyez sur le bouton Next.

10. Vérifiez la configuration et cliquez sur le bouton de configuration "Configure" en bas de la page:

11. Vous verrez le message de réussite: 

Étape 4 (étape finale) - Récupération de vos données de masse

1. Accéder à Exportations (Exports):

2. Appuyez sur le bouton + Nouvelle demande d'exportation:

3. Sélectionnez la valeur du champ de configuration BFC_Patients et appuyez sur le bouton Next

4. Sélectionnez l'option Patient et appuyez sur le bouton Export Now (Exportation immédiate):

5. Vous verrez le message de réussite:

6. Appuyez sur le bouton d'actualisation "Refresh" en haut de la page:

7. Consultez la session de configuration BFC_Patients terminée:

8. Appuyez sur le dernier bouton de téléchargement "Download" ():

9. Consultez la liste des fichiers json exportés:

10. Téléchargez n'importe quel fichier et consultez son contenu:

11. Pour lancer une exportation FHIR en masse à partir d'un client REST, envoyez une requête GET à votre endpoint BFC en indiquant l'opération souhaitée, par exemple:

  •     Système — GET https://bfcEndpoint/$export
  •     Patient — GET https://bfcEndpoint/Patient/$export
  •     Groupe — GET https://bfcEndpoint/Group/groupID/$export

12. Plus de détails sur l'utilisation via l'API: https://docs.intersystems.com/healthconnectlatest/csp/docbook/DocBook.UI.Page.cls?KEY=HXFHIR_bulk#HXFHIR_bulk_export_rest_initiate

13. Plus de détails sur l'utilisation de BFC:

  • https://docs.intersystems.com/healthconnectlatest/csp/docbook/DocBook.UI.Page.cls?KEY=HXFHIR_bulk#HXFHIR_bulk_intro
  • https://www.youtube.com/watch?v=J-AVP9MFMWI

Profitez-en!!

0
0 35
Article Iryna Mykhailova · Avr 10, 2025 3m read

Le mappeur d'enregistrements complexes peut vous aider à transformer des données de fichiers texte composées de différents types d'enregistrements en messages persistants dans IRIS. Pour comprendre les bases du mappeur d'enregistrements complexes et découvrir un exemple de mise en œuvre en production, visionnez la vidéo des services d'apprentissage.

0
0 32
Article Iryna Mykhailova · Avr 7, 2025 11m read

Lors de la création d'un bundle à partir de données héritées, je (et d'autres) souhaitais pouvoir contrôler si les ressources étaient générées avec une méthode de requête FHIR PUT plutôt qu'avec la méthode POST codée en dur. J'ai étendu les deux classes responsables de la transformation de SDA en FHIR dans une production d'interopérabilité afin de prendre en charge un paramètre permettant à l'utilisateur de contrôler la méthode de requête.

0
0 19
Article Sylvain Guilbaud · Fév 26, 2025 7m read

L'utilisation de Embedded Python lors de la création d'une solution basée sur InterSystems peut ajouter des fonctionnalités très puissantes et approfondies à votre boîte à outils.

J'aimerais partager un exemple de cas d'utilisation que j'ai rencontré : l'activation d'un CDC (Change Data Capture) pour une collection mongoDB - la capture de ces modifications, leur digestion via un flux d'interopérabilité et, pour finir, la mise à jour d'un EMR via une API REST.

0
0 39
Article Iryna Mykhailova · Jan 27, 2025 1m read

Dans votre production d'interopérabilité, vous pouvez toujours avoir une Business Operation qui est un client HTTP, qui utilise OAuth 2.0 pour l'authentification, mais vous avez du personnaliser l'opération pour cette méthodologie d'authentification. Depuis la version v2024.3, qui a été récemment publiée, il existe une nouvelle fonctionnalité, fournissant de nouveaux paramètres, pour gérer cela plus facilement.

Dans votre Business Operation qui utilise l'outbound adaptateur HTTP, vous trouverez de nouveaux paramètres, sous le groupe OAuth.

0
0 42
Article Lorenzo Scalese · Jan 22, 2025 5m read

Mise en œuvre de l'idée DPI-I-456

Idée

Le rôle de cet échantillon

Cet exemple a été cloné à partir de la version iris-interoperability-template. J'ai reconfiguré la production d' interopérabilité Production avec un adaptateur Inbound HTTP Adapter qui est utilisé par un service métier HTTP Business Service. Les détails de la configuration du service métier sont spécifiés dans la rubrique des paramètres par défaut du système System Default Settings. J'ai configuré le paramètre de l'intervalle d'appel pour appeler le serveur HTTPS une fois par heure. Vous pouvez modifier l'URL et la fréquence dans les paramètres du service. Screenshot

À l'origine, le service HTTP avait deux cibles. Le corps de réponse de chaque appel était envoyé en tant que message générique HTTP à un processus métier BPL et à une opération de fichier qui sauvegardait les données dans un dossier iris-http-calls.

Le service HTTP envoie un message générique HTTP à une opération de fichier. Ensuite, un service de fichiers envoie le fichier à un processus métier BPL.

Conditions préalables

Assurez-vous d'avoir installé git et Docker desktop.

Installation: ZPM

Ouverture de l'espace de noms IRIS avec l'interopérabilité activée. Ouvrez le terminal et appelez: USER>zpm "install iris-http-calls"

Installation: Docker

Clone/git extrait le référentiel dans n'importe quel répertoire local.

git clone https://github.com/oliverwilms/iris-http-calls.git

Ouvrez le terminal dans ce répertoire et lancez:

docker-compose build
  1. Lancez le conteneur IRIS avec votre projet:
docker-compose up -d

Comment exécuter l'échantillon

Ouvrez la production et lancez-la si elle n'est pas déjà en cours d'exécution. Il effectue des appels HTTP vers le serveur HTTPS à l'aide d'une URL.

Comment modifier le modèle

Ce référentiel est prêt à être codé dans VSCode avec le plugin ObjectScript. Installez VSCode, Docker et le pluginObjectScript et ouvrez le dossier dans VSCode.

Utilisez le menu pratique VSCode pour accéder à l'éditeur de règles de production et de règles métier et lancez un terminal: Screenshot 2020-10-29 at 20 15 56

utilisation des variables d'environnement

Cet exemple montre la façon dont vous pouvez introduire des variables env dans votre environnement dev. Supposons que vous ayez besoin de configurer la production avec un jeton secret pour accéder à une API à accès limité. Bien sûr, vous ne voulez pas exposer le secret à GitHub. Dans ce cas, le mécanisme des variables Env peut être utile. Tout d'abord, introduisez le fichier .env et configurez .gitignore pour filtrer .env à partir de git.

Ajoutez ensuite le jeton secret dans .env sous la forme ENV_VARIABLE="TOKEN VALUE"

L'introduction suivante consiste à faire importer les variables d'environnement dans dockerfile. Pour que cela fonctionne, ajoutez la section environnement dans [docker-compose.yml] (https://github.com/intersystems-community/iris-interoperability-template/blob/d2d7114de7c551e308e742359babebff5d535821/docker-compose.yml), par exemple:

environnement:
      - SAMPLE_TOKEN=${SAMPLE_TOKEN}

Ensuite, vous pourrez initialiser le conteneur en cours d'exécution avec les données des variables env, par exemple avec l'appel suivant, qui utilise la valeur du fichier .env comme paramètre de la production:

USER> d ##class(dc.Demo.Setup).Init($system.Util.GetEnviron("SAMPLE_TOKEN"))

paramètres de production du gestionnaire de paquets

Les utilisateurs de ce module peuvent utiliser des paramètres pour transmettre des données au module lors de l'installation et personnaliser le chemin d'accès au fichier pour l'opération de fichier et le service de fichier, ainsi que modifier l'URL. Il peut être utile lorsque les paramètres de configuration sont des jetons secrets permettant d'accéder à une API particulière. En tant que spécialiste, vous pouvez fournir de tels paramètres avec une balise par défaut dans module.xml.

<Default Name="FilePath" Value="iris_http_calls" />
<Default Name="UrlModify" Value="/Patient?_id=egqBHVfQlt4Bw3XGXoxVxHg3" />

Ces paramètres par défaut permettent aux utilisateurs d'appeler l'installation du paquet avec la possibilité de transmettre des paramètres. Par exemple, l'appel à l'installation peut être exécuté sous la forme suivante:

zpm "install iris-http-calls -D FilePath=iris_http_calls -D UrlModify=/MedicationStatement?patient=egqBHVfQlt4Bw3XGXoxVxHg3"
USER>zpm "install iris-http-calls -D FilePath=iris_http_calls -D UrlModify=/MedicationStatement?patient=egqBHVfQlt4Bw3XGXoxVxHg3"

[USER|iris-http-calls]        Reload START (/usr/irissys/mgr/.modules/USER/iris-http-calls/0.3.37/)
[USER|iris-http-calls]        Reload SUCCESS
[iris-http-calls]       Module object refreshed.
[USER|iris-http-calls]        Validate START
[USER|iris-http-calls]        Validate SUCCESS
[USER|iris-http-calls]        Compile START
[USER|iris-http-calls]        Compile SUCCESS
[USER|iris-http-calls]        Activate START
[USER|iris-http-calls]        Configure START
[USER|iris-http-calls]        Configure SUCCESS
[USER|iris-http-calls]        Activate SUCCESS

Les paramètres par défaut sont utilisés pour configurer la production dans l'appel suivant:

<Invoke Class="dc.Demo.Setup" Method="Init" >
  <Arg>${FilePath}</Arg>
  <Arg>${UrlModify}</Arg>
</Invoke>

La méthode Init de la classe dc.Demo.Setup configure le service et l'opération de fichier à l'aide du paramètre FilePath. Le paramètre UrlModify est utilisé pour modifier l'URL du service HTTP.

La production appelle le serveur HTTPS à l'aide de l'URL modifiée selon CallInterval. Le corps de réponse est envoyé dans un StreamContainer à une FileOperation. Un service de fichiers lit le fichier et transmet un conteneur de flux à un processus BPL.

0
0 34
Article Lorenzo Scalese · Jan 6, 2025 6m read

Salut la Communauté,

image
Dans cet article, je présenterai mon application iris-HL7v2Gen.

IRIS-HL7v2Gen est une application CSP qui facilite la génération dynamique de messages de test HL7. Ce processus est essentiel pour tester, déboguer et intégrer les systèmes de données de soins de santé. L'application permet aux utilisateurs de générer une grande variété de types de messages HL7, de valider leur structure par rapport aux spécifications HL7, d'explorer la hiérarchie des messages et de transmettre les messages par TCP/IP aux systèmes de production. Ces fonctionnalités sont particulièrement utiles dans les contextes où la conformité aux normes HL7 est obligatoire pour assurer l'interopérabilité entre différents organismes ou systèmes de soins de santé.

Fonctionnalités de l'application

  • Génération Dynamique de Messages HL7: Création instantanée de messages HL7 pour une gamme de types de messages, facilitant ainsi les tests complets.
  • Exploration de la structure des messages: Visualisation de la structure des messages générés sur la base des spécifications HL7.
  • Visualisation des jeux de valeurs: Visualisation des jeux de valeurs codées prédéfinis pour des champs spécifiques.
  • Validation des messages: Validation des messages par rapport aux normes HL7 pour garantir la conformité.
  • Communication TCP/IP: Transmission facile de messages à la production à l'aide de paramètres TCP/IP.
  • Prise en charge d'un grand nombre de types de messages: Prise en charge de 184 types de messages HL7, garantissant la polyvalence pour les différents besoins d'intégration des soins de santé.
  • ClassMethod: Génération d'un message de test par l'invocation d'une méthode de classe
  • Version prise en charge: Actuellement, la version 2.5 de HL7 est prise en charge
0
0 55
Article Sylvain Guilbaud · Jan 2, 2025 10m read

Votre mission

Imaginons que vous êtes un espion international qui consacre sa vie à protéger les habitants de notre planète contre les dangers. La mission suivante vous est confiée:

Cher agent IRIS,

Nous sommes désolés d'interrompre vos vacances aux Bahamas, mais notre agent à Londres vient de nous informer qu'une "bombe à explosion retardée" est prête à exploser dans une zone très peuplée de Los Angeles. Selon nos informateurs, la "bombe à explosion retardée" devrait se déclencher à 15h14 aujourd'hui.

Dépêchez-vous, les citoyens comptent sur vous!

Le problème

Alors que vous vous précipitez et vous préparez à partir pour Los Angeles, vous vous rendez compte qu'il vous manque un renseignement essentiel : cette "bombe à explosion retardée" explosera-t-elle à 15h14 heure des Bahamas ou à 15h14 heure de Los Angeles? ...ou peut-être même à 15h14 heure de Londres.

Vous comprenez bien vite que l'heure fournie (15h14) ne vous donne pas assez de renseignements pour déterminer le moment où vous devez vous rendre à Los Angeles.

L'heure indiquée (15h14) était ambiguë. Vous avez besoin de plus de renseignements pour déterminer une heure exacte.

Quelques solutions

Lorsque vous réfléchissez au problème, vous vous rendez compte qu'il existe des méthodes pour surmonter l'ambiguïté de l'heure indiquée qui vous a été fournie:

  1. Votre informateur aurait pu vous fournir le lieu où l'heure locale était 3:14 PM. Par exemple, Los Angeles, les Bahamas, ou Londres.

  2. Votre informateur aurait pu utiliser un standard telle que l'UTC (temps universel coordonné) pour vous fournir un décalage par rapport à un lieu convenu (tel que Greenwich, Londres).

La fin heureuse

Vous téléphonez à votre informateur et confirmez que l'heure fournie était bien 15h14 heure de Los Angeles. Vous pouvez vous rendre à Los Angeles, désamorcer la "bombe à explosion retardée" avant 15h14, et retourner rapidement aux Bahamas pour y terminer vos vacances.

Le but

Quel est donc le but de cet exercice de réflexion? Je doute qu'aucun d'entre nous soit confronté au problème présenté ci-dessus, mais si vous travaillez avec une application ou un code qui déplace des données d'un lieu à un autre (en particulier si les lieux se trouvent dans des fuseaux horaires différents), vous devez savoir comment gérer les dates-heures et les fuseaux horaires.

Les fuseaux horaires, C'EST DUR!

Eh bien, les fuseaux horaires ne sont pas si mauvais. Ce sont l'heure d'été et les périmètres politiques qui rendent les fuseaux horaires si difficiles à gérer.

Je croyais avoir toujours compris l'idée "générale" des fuseaux horaires: le globe est divisé en tranches verticales par fuseau horaire, où chaque fuseau horaire est en retard d'une heure par rapport au fuseau horaire situé à l'Est.

Les fuseaux horaires sur la carte du monde (simplification)

Bien que cette simplification soit valable pour de nombreux endroits, il existe malheureusement de nombreuses exceptions à cette règle.

Fuseaux horaires du monde (Wikipedia) Référence: Fuseaux horaires du monde (Wikipedia)

Représentation du temps UTC ("l'origine")

Pour simplifier la communication de l'heure spécifique, le monde a décidé d'utiliser l'UTC (le temps universel coordonné). Ce standard fixe "l'origine" à la longitude 0° qui passe par Greenwich, Londres.

Définition du "décalage"

En utilisant le temps universel coordonné (UTC) comme base, tous les autres fuseaux horaires peuvent être définis par rapport à l'UTC. Cette relation est appelée décalage UTC.

Si vous connaissez l'heure locale et le décalage, vous n'avez plus d'heure ambiguë (comme dans notre exemple d'espionnage ci-dessus) ; vous avez une heure définie et spécifique, sans ambiguïté.

Le format type utilisé pour indiquer le décalage UTC est le suivant: ±HHMM[SS[.ffffff]].

  • Le symbole moins - indique un décalage à l'ouest de l'UTC.
  • Le signe plus + indique un décalage à l'est de l'UTC..
  • HH indique les heures (avec un zéro initial)
  • MM indique les minutes (avec un zéro initial)
  • SS indique les secondes (avec un zéro initial)
  • .ffffff indique les fractions de secondes

Par exemple, en Amérique, le fuseau horaire de l'Est (EST) est défini comme -0500 UTC. Cela signifie que toutes les localités situées dans le fuseau horaire EST sont en retard de 5 heures par rapport à l'UTC. Si l'heure est 9:00 PM à UTC, l'heure locale à EST est 4:00 PM.

Dans le fuseau horaire central occidental d'Australie (ACWST), le décalage est défini comme +0845 UTC. Si l'heure est 21h00 à UTC, l'heure locale d'EST est 16h00.

Heure d'été

Revenons aux cartes des fuseaux horaires ci-dessus. Vous y trouverez de nombreux fuseaux horaires qui suivent les frontières politiques des pays et des régions. Cela complique légèrement le calcul des fuseaux horaires, mais c'est assez facile à comprendre.

Malheureusement, il y a un autre élément à prendre en compte lorsque l'on travaille avec des heures et des fuseaux horaires. Regardons Los Angeles.

Cette carte indique que le décalage UTC pour Los Angeles est de -8 en Standard Time. L'heure normale est généralement suivie pendant les mois d'hiver, tandis que l'heure d'été est généralement suivie pendant les mois d'été.

L'heure d'été (en anglais; Daylight Savings Time (DST) avance les horloges d'un fuseau horaire donné (généralement d'une heure pendant les mois d'été). Les régions politiques peuvent choisir de suivre l'heure d'été pour plusieurs raisons (économies d'énergie, meilleure utilisation de la lumière du jour, etc.) La difficulté et la complexité de l'heure d'été résident dans le fait que l'heure d'été n'est pas appliquée de manière uniforme dans le monde entier. Selon votre situation géographique, votre région peut suivre ou non l'heure d'été.

Base de données de fuseaux horaires

La combinaison des frontières politiques et de l'heure d'été augmentant considérablement la complexité de la détermination d'une heure spécifique, une base de données des fuseaux horaires est nécessaire pour faire correspondre correctement les heures locales à des heures spécifiques par rapport à l'UTC. La base de données des fuseaux horaires de l'IANA (Internet Assigned Numbers Authority) est la source commune de renseignements sur les fuseaux horaires utilisée par les systèmes d'exploitation et les langages de programmation.

La base de données comprend les noms et alias de tous les fuseaux horaires, des renseignements sur le décalage, des renseignements sur l'utilisation de l'heure d'été, les abréviations des fuseaux horaires et les plages de données auxquelles les différentes règles s'appliquent.

Des copies et des renseignements concernant la base de données sur les fuseaux horaires sont disponibles sur le site web de l'IANA.

La plupart des systèmes UNIX disposent d'une copie de la base de données qui est mise à jour par le gestionnaire de paquetages du système d'exploitation (généralement installé dans /usr/share/zoneinfo). Certains langages de programmation ont la base de données intégrée. D'autres la rendent disponible par le biais d'une bibliothèque ou peuvent lire la copie de la base de données du système.

Noms et identifiants des fuseaux horaires

La base de données des fuseaux horaires contient un grand nombre de noms et d'alias pour des fuseaux horaires spécifiques. La plupart des saisies incluent un pays (ou un continent) et une grande ville dans le nom. Par exemple:

  • Amérique/New_York
  • Amérique/Los_Angeles
  • Europe/Rome
  • Australie/Melbourne

Conversion et formatage à l'aide d'ObjectScript

Ainsi, voici ce que nous savons:

  • les heures locales (heures ambiguës sans décalage ni emplacement)
  • les décalages UTC (le décalage relatif d'un horodatage ou d'un emplacement par rapport à l'« origine » UTC à Greenwich, Londres)
  • l'heure d'été (une tentative d'aider la civilisation au détriment des décalages de fuseaux horaires)
  • base de données des fuseaux horaires (qui contient des renseignements sur les fuseaux horaires et le respect de l'heure d'été dans de nombreux lieux et régions).

Sachant cela, comment pouvons-nous travailler avec les heures-dates et les fuseaux horaires en ObjectScript?

***Note: Je crois que toutes les affirmations suivantes sont vraies à propos d'ObjectScript, mais n'hésitez pas à me faire savoir si j'ai mal expliqué comment ObjectScript fonctionne avec les fuseaux horaires et les décalages.

Variables et fonctions intégrées

Si vous avez besoin de convertir des horodatages entre différents formats dans le fuseau horaire du processus exécutant IRIS, les fonctionnalités intégrées d'ObjectScript devraient être suffisantes. Voici une brève liste des variables/fonctions relatives au temps dans ObjectScript:

  • $ZTIMESTAMP / $ZTS

    • Format interne d'IRIS en tant que valeur UTC (décalage +0000).
    • Format: ddddd,sssss.fffffff
  • $NOW(tzmins)

    • Heure locale du système actuel avec le décalage de tzmins donné par rapport à UTC.
    • Heure d'été n'est pas prise en compte.
    • Par défaut, tzmins est basé sur la variable $ZTIMEZONE.
    • Format: ddddd,sssss.fffffff
  • $HOROLOG

    • Heure locale actuelle du système (basée sur $ZTIMEZONE), avec prise en compte de l'heure d'été.
    • Format: ddddd,sssss.fffffff
  • $ZTIMEZONE

    • Renvoie ou définit le décalage UTC local du système en minutes.
  • $ZDATETIME() / $ZDT()

    • Conversion du format $HOROLOG en un format d'affichage spécifique.
    • Peut être utilisé pour la conversion de l'heure locale du système à l'heure UTC (+0000).
  • $ZDATETIMEH() / $ZDTH()

    • Conversion d'une chaîne de date au format interne $HOROLOG.
    • Peut être utilisé pour convertir l'heure UTC (+0000) en heure locale.

Pour autant que je sache, ces fonctionnalités ne peuvent manipuler les dates qu'en utilisant le fuseau horaire du système local. Il ne semble pas y avoir de moyen de travailler avec des fuseaux horaires arbitraires en ObjectScript.

Accès à la bibliothèque tz sur Open Exchange

Pour faciliter la conversion vers et depuis des fuseaux horaires arbitraires, j'ai créé la bibliothèque de conversion de fuseaux horaires ObjectScript tz - ObjectScript Time Zone Conversion Library.

Cette bibliothèque accède à la base de données des fuseaux horaires installée sur votre système afin d'offrir un support pour la conversion des horodatages entre les fuseaux horaires et les formats.

Par exemple, si vous disposez de l'heure locale de Los Angeles (Amérique/Los_Angeles), vous pouvez la convertir dans le fuseau horaire utilisé aux Bahamas (Amérique/New_York) ou dans le fuseau horaire utilisé à Londres (Europe/Londres):

USER>zw ##class(tz.Ens).TZ("2024-12-20 3:14 PM", "America/Los_Angeles", "America/New_York")
"2024-12-20 06:14 PM"

USER>zw ##class(tz.Ens).TZ("2024-12-20 3:14 PM", "America/Los_Angeles", "Europe/London")
"2024-12-20 11:14 PM"

Si l'on vous donne un horodatage avec un décalage, vous pouvez le convertir en heure locale à Eucla, Australie (Australie/Eucla), même si vous ne connaissez pas le fuseau horaire d'origine:

USER>zw ##class(tz.Ens).TZ("2024-12-20 08:00 PM -0500", "Australia/Eucla")
"2024-12-21 09:45 AM +0845"

Si vous travaillez avec des messages HL7, la bibliothèque tz dispose de plusieurs méthodes associées aux règles d'interopérabilité et aux DTL pour vous aider à convertir facilement les fuseaux horaires, les heures locales, les heures avec décalage, etc.:

// Conversion de l'heure locale d'un fuseau horaire à l'autre 	 
set datetime = "20240102033045"
set newDatetime = ##class(tz.Ens).TZ(datetime,"America/New_York","America/Chicago")

// Conversion de l'heure locale en décalage 	 
set datetime = "20240102033045"
set newDatetime = ##class(tz.Ens).TZOffset(datetime,"America/Chicago","America/New_York")

// Conversion du décalage en heure locale 	 
set datetime = "20240102033045-0500"
set newDatetime = ##class(tz.Ens).TZLocal(datetime,"America/Chicago")

// Conversion vers un format alternatif au HL7 	 
set datetime = "20240102033045-0500"
set newDatetime = ##class(tz.Ens).TZ(datetime,"America/Chicago",,"%m/%d/%Y %H:%M:%S %z")

Résumé

Je vous remercie de m'avoir suivi dans ce "voyage à travers le monde" où nous avons rencontré des fuseaux horaires, l'heure d'été, les cartes du monde et les "bombes à explosion retardée". J'espère que ce travail vous a permis d'éclairer (et de simplifier) les nombreuses complexités liées à l'utilisation des dates et des fuseaux horaires.

Consultez la bibliothèque tz - ObjectScript Time Zone Conversion Library et faites-moi savoir si vous avez des questions (ou des corrections/clarifications à propos de quelque chose que j'ai dit ici.

Merci!

Références / Liens intéressants

0
0 85
InterSystems officiel Adeline Icard · Déc 9, 2024

Cela fait un moment que je n'ai pas publié d'article sur Embedded Git sur la Communauté des développeurs, et j'aimerais faire le point sur l'énorme quantité de travail que nous avons accompli cette année et sur la direction que nous allons prendre ensuite.

Contexte

Si vous créez des solutions sur IRIS et que vous souhaitez utiliser Git, c'est parfait ! Utilisez simplement VSCode avec un dépôt git local et transmettez vos modifications sur le serveur : c'est aussi simple que cela.

Mais que se passe-t-il si :

0
0 45
Article Iryna Mykhailova · Nov 28, 2024 1m read

La possibilité de renvoyer facilement des messages a toujours été une caractéristique importante de nos capacités d'interopérabilité.

Avec la sortie de la version 2024.3, nous avons rendu cela encore plus facile !

0
0 43
Article Guillaume Rongier · Juil 25, 2024 28m read

Cet article a pour objectif de fournir au lecteur les informations suivantes:

  • Configuration et utilisation du serveur FHIR
  • Création d'un serveur d'autorisation OAuth2
  • Liaison entre le serveur FHIR et le serveur d'autorisation OAuth2 pour la prise en charge de SMART sur FHIR
  • Utilisation des capacités d'interopérabilité dans "IRIS for Health" pour filtrer les ressources FHIR
  • Création d'une opération personnalisée sur le serveur FHIR

Schéma de l'article:

Schema

Flux de travail de l'article:

Workflow

1. Table des matières

2. Objectifs

Cette session de formation vise à fournir aux participants les compétences suivantes:

  • Configuration et utilisation du serveur FHIR
  • Création d'un serveur d'autorisation OAuth2
  • Liaison entre le serveur FHIR et le serveur d'autorisation OAuth2 pour la prise en charge de SMART sur FHIR
  • Utilisation des capacités d'interopérabilité dans "IRIS for Health" pour filtrer les ressources FHIR
  • Création d'une opération personnalisée sur le serveur FHIR

3. Installation

Pour installer l'environnement de formation, vous devez avoir installé Docker et Docker Compose sur votre machine.

Vous pouvez installer Docker et Docker Compose en suivant les instructions sur le site Docker website.

Une fois Docker et Docker Compose installés, vous pouvez cloner ce dépôt et exécuter la commande suivante:

docker-compose up -d

Cette commande démarre le conteneur "IRIS for Health" et le conteneur "Web Gateway" pour exposer le serveur FHIR via HTTPS.

3.1. Accès au serveur FHIR

Une fois les conteneurs démarrés, vous pouvez accéder au serveur FHIR à l'URL suivante:

https://localhost:4443/fhir/r5/

3.2. Accés au Portail de Gestion d'InterSystems IRIS

Vous pouvez accéder au portail de gestion InterSystems IRIS à l'adresse suivante:

http://localhost:8089/csp/sys/UtilHome.csp

Le nom d'utilisateur et le mot de passe par défaut sont "SuperUser" et "SYS" respectivement.

4. Configuration du serveur d'autorisation OAuth2

Pour configurer le serveur d'autorisation OAuth2, il faut se connecter au portail de gestion InterSystems IRIS et naviguer jusqu'à l'administration du système: System Administration > Security > OAuth 2.0 > Servers.

OAuth2 Servers

Ensuite, nous remplirons le formulaire pour créer un nouveau serveur d'autorisation OAuth2.

4.1. Onglet Généralités

Nous commençons d'abord par l'onglet Généralités.

General Tab

Les paramètres sont les suivants:

  • Description: La description du serveur d'autorisation OAuth2
    • Serveur d'autorisation Oauth2 Auth
  • Émetteur: L'URL du serveur d'autorisation OAuth2
    • https://webgateway/oauth2
    • REMARQUE : Nous utilisons ici l'URL de la passerelle Web Gateway pour exposer le serveur FHIR via HTTPS. Il s'agit du nom DNS interne du conteneur de la passerelle Web Gateway.
  • Types de subventions pris en charge: Les types de subventions pris en charge par le serveur d'autorisation OAuth2
    • Code d'autorisation
    • Informations d'identification du client
    • Autorisation JWT
    • REMARQUE : Nous utiliserons le type de subvention de Client Credentials (informations d'identification du client) pour authentifier le serveur FHIR auprès du serveur d'autorisation OAuth2.
  • Configuration SSL/TLS: La configuration SSL/TLS à utiliser pour le serveur d'autorisation OAuth2.
    • Par défaut: BFC_SSL

4.2. Onglet Périmètre

Ensuite, nous passons à l'onglet Périmètre.

Scope Tab

Nous allons créer 3 périmètres:

  • user/Patient.read: Le périmètre de lecture des ressources disponibles pour les patients
  • VIP: Le périmètre de lecture des ressources disponibles pour les patients VIP
  • user/.: Le périmètre de lecture toutes les ressources, à des fins administratives

4.3. Onglet JWT

Ensuite, nous passons à l'onglet JWT.

JWT Tab

Ici, nous sélectionnons simplement l'algorithme à utiliser pour le JWT..

Nous utiliserons l'algorithme RS256.

Si nécessaire, nous pouvons sélectionner le cryptage pour le JWT. Nous n'utiliserons pas de cryptage pour cette session de formation.

4.4. Onglet Personnalisation

Ensuite, nous passons à l'onglet Personnalisation.

Customization Tab

Voici toutes les classes de personnalisation pour le serveur d'autorisation OAuth2.

Nous changeons les classes suivantes:

  • Classe de génération du jeton: La classe à utiliser pour générer le jeton
    • FROM : %OAuth2.Server.Generate
    • TO : %OAuth2.Server.JWT

Nous pouvons maintenant enregistrer le serveur d'autorisation OAuth2.

Félicitations, nous avons maintenant configuré le serveur d'autorisation OAuth2. 🥳

5. Configuration du Client

Pour configurer le Client, il faut se connecter au portail de gestion InterSystems IRIS et naviguer jusqu'à l'administration du système: System Administration > Security > OAuth 2.0 > Client.

OAuth2 Clients

Pour créer un nouveau client, il faut d'abord enregistrer le serveur d'autorisation OAuth2.

5.1. Enregistrement du serveur d'autorisation OAuth2

Sur la page client, cliquez sur le bouton de création d'une description de serveur Create Server Description.

Create Server Description

5.2. Description du serveur

Dans le formulaire Description du serveur, nous devons remplir les paramètres suivants:

Server Description

  • URL du serveur: L'URL du serveur d'autorisation OAuth2
  • Configuration SSL/TLS: La configuration SSL/TLS à utiliser pour le serveur d'autorisation OAuth2
    • Par défaut: BFC_SSL

Cliquez sur le bouton Discover and Save (Découvrir et enregistrer). Félicitations, nous avons maintenant enregistré le serveur d'autorisation OAuth2.

Server Description

5.3. Création d'un nouveau client

Ensuite, nous pouvons créer un nouveau client.

Sur la page client, nous avons un nouveau bouton Client Configuration (Configuration Client).

Client Configuration

Cliquez sur le bouton de lien Client Configuration vers la description du serveur.

Nous pouvons maintenant créer un nouveau client..

Create Client

5.3.1. Onglet Généralités

Nous commençons d'abord par l'onglet Généralités.

General Tab

Les paramètres sont les suivants:

  • Nom de l'application: Le nom du client
    • App
    • REMARQUE : C'est le nom du client.
  • Nom du client: Le nom du client
    • App
  • *Type de client: Le type du client
    • Confidentiel
    • REMARQUE : Nous utiliserons le type de client "confidentiel" pour authentifier le serveur FHIR auprès du serveur d'autorisation OAuth2.
  • URI de redirection: L'URI de redirection du client
    • https://webgateway/oauth2
    • REMARQUE : Nous utilisons ici l'URL de la passerelle Web Gateway pour exposer le serveur FHIR via HTTPS. Il s'agit du nom DNS interne du conteneur de la passerelle Web Gateway.
    • REMARQUE : Ceci ne sera pas utilisé dans cette session de formation.
  • Types de subventions: Les types de subventions pris en charge par le client
    • Informations d'identification du client
    • REMARQUE : Nous utiliserons le type de subvention de Client Credentials (informations d'identification du client) pour authentifier l'application client (Client Application) auprès du serveur d'autorisation OAuth2.
  • Type d'authentification: Le type d'authentification du client
    • Basique
    • REMARQUE : Nous utiliserons le type d'authentification Basique pour authentifier l'application client (Client Application) auprès du serveur d'autorisation OAuth2.

Maintenant, nous pouvons cliquer sur le bouton Dynamic Registration (Enregistrement dynamique)..

Félicitations, nous avons maintenant créé le client. 🥳

Si nous allons dans l'onglet Client Credentials (Informations d'identification du client), nous pouvons voir les informations d'identification du client.

Notez que les informations d'identification du client sont Client ID et Client Secret (l'Identifiant du client et le Secret du client).

6. Configuration du serveur FHIR

⚠️ AVERTISSEMENT ⚠️ : Assurez-vous d'être sur l'espace de noms FHIRSERVER.

Namespace

Pour configurer le serveur FHIR, il faut se connecter au portail de gestion InterSystems IRIS et naviguer: Health > FHIR Configuration > Servers.

FHIR Servers

Ensuite, nous allons créer un nouveau serveur FHIR.

Cliquez sur le bouton Server Configuration (Configuration du Serveur).

Server Configuration

6.1. Création un nouveau serveur FHIR

Dans le formulaire Configuration du serveur, nous devons remplir les paramètres suivants:

Server Configuration

  • Paquet de base FHIR: Le paquet de base FHIR à utiliser pour le serveur FHIR
    • r5
  • Adresse URL: L'URL du serveur FHIR
    • /fhir/r5
  • Stratégie d'interactions: La stratégie d'interactions à utiliser pour le serveur FHIR
    • FHIR.Python.InteractionsStrategy
    • ⚠️ AVERTISSEMENT ⚠️ : Pas comme sur la photo, il faut sélectionner la stratégie d'interactions FHIR.Python.InteractionsStrategy.

Cliquer sur le bouton Add.

Cela peut prendre quelques minutes. 🕒 Allons prendre un café. ☕️

Félicitations, nous avons maintenant créé le serveur FHIR. 🥳

6.2. Liaison entre le serveur FHIR et le serveur d'autorisation OAuth2

Sélectionnez le serveur FHIR et descendez jusqu'au bouton Edit (modifier).

FHIR Server

Dans le formulaire Serveur FHIR , nous devons remplir les paramètres suivants:

FHIR Server

  • Nom du Client OAuth2: Le nom du Client
    • App

Cliquez sur le bouton Save (sauvegarder).

Félicitations, nous avons maintenant lié le serveur FHIR au serveur d'autorisation OAuth2. 🥳

6.3. Test du serveur FHIR

Pour tester le serveur FHIR, vous pouvez utiliser la commande suivante:

GET https://localhost:4443/fhir/r5/Patient

Sans l'en-tête Authorization, vous obtiendrez une réponse 401 Unauthorized.

Pour authentifier la demande, vous devez ajouter l'en-tête Authorization avec le jeton Bearer.

Pour ce faire, demandons un jeton au serveur d'autorisation OAuth2.

POST https://localhost:4443/oauth2/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic <client_id>:<client_secret>

grant_type=client_credentials&scope=user/Patient.read&aud=https://localhost:4443/fhir/r5

Vous obtiendrez une réponse 200 OK avec le jeton d'accès access_token et le type de jeton token_type.

Maintenant, vous pouvez utiliser jeton d'accès access_token pour authentifier la demande auprès du serveur FHIR.

GET https://localhost:4443/fhir/r5/Patient
Authorization: Bearer <access_token>
Accept: application/fhir+json

Félicitations, vous avez maintenant authentifié la demande sur le serveur FHIR. 🥳

7. Filtrage des ressources FHIR avec "InterSystems IRIS for Health"

Eh bien, nous aborderont maintenant un grand sujet.

Le but de ce sujet sera de mettre en place les capacités d'interopérabilité d'IRIS for Health entre le serveur FHIR et l'application cliente.

Ci-dessous, une vue macro de l'architecture:

Interoperability

Et voici le flux de travail:

Workflow

Ce que nous remarquons ici, c'est que l'EAI (capacités d'interopérabilité d'IRIS for Health) servira de chemin d'accès pour les demandes entrantes vers le serveur FHIR. Il filtrera la réponse du serveur FHIR en fonction des champs d'application et enverra la réponse filtrée à l'application cliente.

Avant d'aller plus loin, permettez-moi de vous présenter rapidement les capacités d'interopérabilité d'IRIS for Health.

7.1. Cadre d'Interopérabilité

Il s'agit du cadre IRIS Framework.

FrameworkFull

L'objectif de ce cadre est de fournir un moyen de relier différents systèmes entre eux.

Nous avons 4 composants principaux:

  • Services métiers: Le point d'entrée du cadre. Il reçoit la demande entrante et l'envoie à la production.
  • Processus métier: Le flux de travail du cadre. Il traite la demande entrante et l'envoie à l'opération métier.
  • Operations métier: Le point de sortie du cadre. Il traite la demande entrante et l'envoie au service métier.
  • Messages: Les données du cadre. Elles contiennent la requête entrante et la réponse sortante.

Pour cette session de formation, nous utiliserons les composants suivants:

  • Un service métier Business Service pour recevoir la demande de l'application cliente.
  • Un processus métier Business Process pour filtrer la réponse du serveur FHIR en fonction des péramètres.
  • Une opération métier Business Operation pour envoyer les messages au serveur FHIR.

Pour cette session de formation, nous utiliserons une production d'interopérabilité pré-construite.

Nous nous concentrerons uniquement sur le processus métier Business Process permettant de filtrer la réponse du serveur FHIR en fonction des périmètres.

7.2. Installation de l'IoP

Pour cette partie, nous utiliserons l'outil IoP. IoP signifie l'Interopérabilité sur Python..

Vous pouvez installer l'outil IoP en suivant les instructions du référentiel de l'IoP

L'outil IoP est pré-installé dans l'environnement de formation.

Connectez-vous au conteneur en cours d'exécution:

docker exec -it formation-fhir-python-iris-1 bash

Et exécutez la commande suivante:

iop --init

Ainsi l'IoP sera installée sur le conteneur IRIS for Health.

7.3. Création de la Production d'Interopérabilité

Toujours dans le conteneur, exécutez la commande suivante:

iop --migrate /irisdev/app/src/python/EAI/settings.py

Ainsi, la production d'interopérabilité sera créée.

Vous pouvez maintenant accéder à la production d'interopérabilité à l'adresse URL suivante:

http://localhost:8089/csp/healthshare/eai/EnsPortal.ProductionConfig.zen?$NAMESPACE=EAI&$NAMESPACE=EAI&

Vous pouvez maintenant lancer la production.

Félicitations, vous avez créé la production d'interopérabilité. 🥳

7.3.1. Test de la Production d'Interopérabilité

Obtenez un jeton du serveur d'autorisation OAuth2.

POST https://localhost:4443/oauth2/token
Content-Type: application/x-www-form-urlencoded
Authorization : Basic <client_id>:<client_secret>

grant_type=client_credentials&scope=user/Patient.read&aud=https://webgateway/fhir/r5

⚠️ AVERTISSEMENT ⚠️ : we change the aud parameter to the URL of the Web Gateway to expose the FHIR server over HTTPS.

Faites passer un patient par la production d'interopérabilité.

GET https://localhost:4443/fhir/Patient
Authorization : Bearer <Token>
Accept: application/fhir+json

Vous pouvez voir la trace de la requête dans la production d'interopérabilité.

http://localhost:8089/csp/healthshare/eai/EnsPortal.MessageViewer.zen?SOURCEORTARGET=Python.EAI.bp.MyBusinessProcess

7.4. Modification du processus métier

Tout le code pour le processus métier Business Process se trouve dans le fichier suivant : https://github.com/grongierisc/formation-fhir-python/blob/main/src/python/EAI/bp.py

Pour cette session de formation, nous adopterons une approche de développement piloté par les tests, TTD (Test Driven Development)..

Tous les tests pour le processus métier Business Process se trouve dans le fichier suivant : https://github.com/grongierisc/formation-fhir-python/blob/main/src/python/tests/EAI/test_bp.py

7.4.1. Préparation de votre environnement de développement

Pour préparer votre environnement de développement, il faut créer un environnement virtuel.

python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

7.4.2. Exécution des tests

Pour exécuter les tests, vous pouvez utiliser la commande suivante:

pytest

Les tests échouent.

7.4.3. Mise en œuvre du code

Nous avons 4 fonctions à mettre en œuvre:

  • check_token
  • on_fhir_request
  • filter_patient_resource
  • filter_resources

Vous pouvez mettre en œuvre le code dans https://github.com/grongierisc/formation-fhir-python/blob/main/src/python/EAI/bp.py file.

7.4.3.1. check_token

Cette fonction vérifie si le jeton est valide et si le champ d'application contient le périmètre VIP. Si le jeton est valide et que le périmètre contient le périmètre VIP, la fonction renvoie True (vrai), sinon elle renvoie False (faux). Nous utiliserons la bibliothèque jwt pour décoder le jeton.

Cliquez pour voir le code
def check_token(self, token:str) -> bool:

    # décoder le jeton
    try:
        decoded_token= jwt.decode(token, options={"verify_signature": False})
    except jwt.exceptions.DecodeError:
        return False

    # vérifier si le jeton est valide
    if 'VIP' in decoded_token['scope']:
        return True
    else:
        return False

7.4.3.2. filter_patient_resource

Cette fonction filtrera la ressource patient.

Cela supprimera les champ name, address, telecom and birthdate (nom, adresse, télécom et date de naissance) de la ressource patient..

La fonction renverra la ressource patient filtrée sous forme de chaîne.

Nous utiliserons la bibliothèque fhir.resources pour analyser la ressource patient.

Notez la signature de la fonction.

La fonction prend une chaîne en entrée et renvoie une chaîne comme le résultat.

Nous devons donc analyser la chaîne d'entrée en un objet fhir.resources.patient.Patient, puis analyser l'objet fhir.resources.patient.Patient en une chaîne.

Cliquez pour voir le code
def filter_patient_resource(self, patient_str:str) -> str:
    # filtrer le patient
    p = patient.Patient(**json.loads(patient_str))
    # supprimer le nom
    p.name = []
    # supprimer l'adresse
    p.address = []
    # supprimer le télécom
    p.telecom = []
    # supprimer la date de naissance
    p.birthDate = None

    return p.json()

7.4.3.3. filter_resources

Cette fonction filtrera les ressources.

Nous devons vérifier le type de ressource et filtrer la ressource en fonction du type de ressource.

Si le type de ressource est Bundle (Paquet), nous devons filtrer toutes les entrées du paquet qui sont de type Patient.

Si le type de ressource est Patient, nous devons filtrer la resource de type patient.

La fonction renverra la ressource filtrée sous forme de chaîne.

Nous utiliserons la bibliothèque fhir.resources pour analiser la ressource.

Cliquez pour voir le code
    def filter_resources(self, resource_str:str) -> str:
        # analyser le payload
        payload_dict = json.loads(resource_str)

        # quel est le type de ressource?
        resource_type = payload_dict['resourceType'] if 'resourceType' in payload_dict else 'None'
        self.log_info('Resource type: ' + resource_type)

        # c'est un paquet?
        if resource_type == 'Bundle':
            obj = bundle.Bundle(**payload_dict)
            # filtrer le paquet
            for entry in obj.entry:
                if entry.resource.resource_type == 'Patient':
                    self.log_info('Filtering a patient')
                    entry.resource = patient.Patient(**json.loads(self.filter_patient_resource(entry.resource.json())))

        elif resource_type == 'Patient':
            # filtrer le patient
            obj = patient.Patient(**json.loads(self.filter_patient_resource(resource_str)))
        else:
            return resource_str

        return obj.json()

7.4.3.4. on_fhir_request

Cette fonction sera le point d'entrée du processus métier Business Process.

Elle recevra la demande du service métier Business Service, vérifiera le jeton, filtrera la réponse du serveur FHIR en fonction des champs d'application et enverra la réponse filtrée au service métier Business Service.

La fonction renverra la réponse du serveur FHIR.

Nous utiliserons la bibliothèque iris pour envoyer la requête au serveur FHIR.

Le message sera un objet iris.HS.FHIRServer.Interop.Request.

Cet objet contient la requête au serveur FHIR.

Il consiste des composant suivants: Method, URL, Headers et Payload.

Pour vérifier le jeton, nous utiliserons la fonction check_token et pour obtenir un jeton, il faut utiliser l'en-tête USER:OAuthToken.

Pour filtrer la reponse, nous utiliserons la fonction filter_resources et pour lire la réponse du serveur FHIR, nous utiliserons QuickStream.

Cliquez pour voir le code
def on_fhir_request(self, request:'iris.HS.FHIRServer.Interop.Request'):
    # Faire quelque chose avec la requête
    self.log_info('Received a FHIR request')

    # La passer à la cible
    rsp = self.send_request_sync(self.target, request)

    # Essayer d'obtenir le jeton de la requête
    token = request.Request.AdditionalInfo.GetAt("USER:OAuthToken") or ""

    # Faire quelque chose avec la réponse
    if self.check_token(token):
        self.log_info('Filtering the response')
        # Filtrer la réponse
        payload_str = self.quick_stream_to_string(rsp.QuickStreamId)

        # Si le payload est vide, renvoyer la réponse
        if payload_str == '':
            return rsp

        filtered_payload_string = self.filter_resources(payload_str)
        if filtered_payload_string == '':
            return rsp

        # écrire la chaîne json dans un flux rapide
        quick_stream = self.string_to_quick_stream(filtered_payload_string)

        # renvoyer la réponse
        rsp.QuickStreamId = quick_stream._Id()

    return rsp

7.4.4. Exécution des tests

Pour exécuter les tests, vous pouvez utiliser la commande suivante:

pytest

Les tests passent. 🥳

Vous pouvez maintenant tester le processus métier Business Process avec la production d'interopérabilité.

8. Création de l'opération personnalisée

Dernière partie de la session de formation. 🏁

Nous allons créer une opération personnalisée sur le serveur FHIR.

L'opération personnalisée sera opération de fusion de patients Patient et le résultat sera la différence entre les deux patients.

exemple:

POST https://localhost:4443/fhir/r5/Patient/1/$merge
Authorization : Bearer <Token>
Accept: application/fhir+json
Content-Type: application/fhir+json

{
  "resourceType": "Patient",
  "id": "2",
  "meta": {
    "versionId": "2"
  }
}

La réponse sera la différence entre les 2 patients.

{
    "values_changed": {
        "root['address'][0]['city']": {
            "new_value": "fdsfd",
            "old_value": "Lynnfield"
        },
        "root['meta']['lastUpdated']": {
            "new_value": "2024-02-24T09:11:00Z",
            "old_value": "2024-02-28T13:50:27Z"
        },
        "root['meta']['versionId']": {
            "new_value": "1",
            "old_value": "2"
        }
    }
}

Avant de poursuivre, permettez-moi de présenter rapidement l'opération personnalisée sur le serveur FHIR..

L'opération de personnalisation se décline en trois types:

  • Opération d'instance: L'opération est effectuée sur une instance spécifique d'une ressource.
  • Opération de type: L'opération est effectuée sur un type de ressource.
  • Opération de système: L'opération est effectuée sur le serveur FHIR.

Pour cette session de formation, pour la création de l'opération personnalisée nous utiliserons l'Instance Operation.

8.1. Codage de l'opération personnalisée

Une opération personnalisée doit hériter de la classe OperationHandler à partir du module FhirInteraction.

Voici la signature de la classe OperationHandler:

class OperationHandler(object):

    @abc.abstractmethod
    def add_supported_operations(self,map:dict) -> dict:
        """
        @API Enumerate the name and url of each Operation supported by this class
        @Output map : A map of operation names to their corresponding URL.
        Example:
        return map.put("restart","http://hl7.org/fhir/OperationDefinition/System-restart")
        """

    @abc.abstractmethod
    def process_operation(
        self,
        operation_name:str,
        operation_scope:str,
        body:dict,
        fhir_service:'iris.HS.FHIRServer.API.Service',
        fhir_request:'iris.HS.FHIRServer.API.Data.Request',
        fhir_response:'iris.HS.FHIRServer.API.Data.Response'
    ) -> 'iris.HS.FHIRServer.API.Data.Response':
        """
        @API Process an Operation request.
        @Input operation_name : The name of the Operation to process.
        @Input operation_scope : The scope of the Operation to process.
        @Input fhir_service : The FHIR Service object.
        @Input fhir_request : The FHIR Request object.
        @Input fhir_response : The FHIR Response object.
        @Output : The FHIR Response object.
        """

Comme nous l'avons fait dans la partie précédente, nous utiliserons une approche TTD (Développement piloté par les tests).

Tous les tests pour le Processus d'Affaires sont dans ce fichier : https://github.com/grongierisc/formation-fhir-python/blob/main/src/python/tests/FhirInteraction/test_custom.py

8.1.1. add_supported_operations

Cette fonction ajoute l'opération de fusion de patients Patient aux opérations prises en charge.

La fonction retournera un dictionnaire avec le nom de l'opération et l'adresse URL de l'opération. Sachez que le dictionnaire d'entrée peut être vide.

Le résultat attendu est le suivant:

{
  "resource": 
    {
      "Patient": 
        [
          {
            "name": "merge",
            "definition": "http://hl7.org/fhir/OperationDefinition/Patient-merge"
          }
        ]
    }
}

This json document will be added to the CapabilityStatement of the FHIR server.

Cliquez pour voir le code
def add_supported_operations(self,map:dict) -> dict:
    """
    @API Enumerate the name and url of each Operation supported by this class
    @Output map : A map of operation names to their corresponding URL.
    Example:
    return map.put("restart","http://hl7.org/fhir/OperationDefinition/System-restart")
    """

    # verify the map has attribute resource 
    if not 'resource' in map:
        map['resource'] = {}
    # verify the map has attribute patient in the resource
    if not 'Patient' in map['resource']:
        map['resource']['Patient'] = []
    # add the operation to the map
    map['resource']['Patient'].append({"name": "merge" , "definition": "http://hl7.org/fhir/OperationDefinition/Patient-merge"})

    return map

8.1.2. process_operation

Cette fonction traitera l'opération de fusion Patient.

La fonction renverra la différence entre les 2 patients.

Nous allons utiliser la bibliothèque deepdiff pour obtenir la différence entre les 2 patients.

Les paramètres d'entrée sont les suivants:

  • operation_name: Le nom de l'opération à traiter.
  • operation_scope: Le périmètre de l'opération à traiter.
  • body: Le corps de l'operation.
  • fhir_service: L'objet FHIR Service.
    • fhir_service.interactions.Read
      • Une méthode pour lire une ressource à partir du serveur FHIR.
      • Les paramètres d'entrée sont les suivants:
        • resource_type: Le type de la ressource à lire.
        • resource_id: L'identifiant de la ressource à lire.
      • Le résultat est un objet %DynamicObject
  • fhir_request: L'objet de requête FHIR Request..
    • fhir_request.Json
      • Propriété permettant d'obtenir le corps de la requête, c'est un objet %DynamicObject
  • fhir_response: L'objet de réponse FHIR Response.
    • fhir_response.Json
      • Propriété permettant de définir le corps de la réponse, c'est un objet %DynamicObject.

%DynamicObject est une classe permettant de manipuler des objets JSON.

C'est la même chose qu'un dictionnaire Python mais pour ObjectScript.

Téléchargement d'objet JSON:

json_str = fhir_request.Json._ToJSON()
json_obj = json.loads(json_str)

Définition d'objet JSON:

json_str = json.dumps(json_obj)
fhir_response.Json._FromJSON(json_str)

Assurez-vous que la fonction de traitement process_operation est appelée pour vérifier si operation_name est merge, operation_scope est Instance et RequestMethod est POST.

Cliquez pour voir le code
def process_operation(
    self,
    operation_name:str,
    operation_scope:str,
    body:dict,
    fhir_service:'iris.HS.FHIRServer.API.Service',
    fhir_request:'iris.HS.FHIRServer.API.Data.Request',
    fhir_response:'iris.HS.FHIRServer.API.Data.Response'
) -> 'iris.HS.FHIRServer.API.Data.Response':
    """
    @API Process an Operation request.
    @Input operation_name : The name of the Operation to process.
    @Input operation_scope : The scope of the Operation to process.
    @Input fhir_service : The FHIR Service object.
    @Input fhir_request : The FHIR Request object.
    @Input fhir_response : The FHIR Response object.
    @Output : The FHIR Response object.
    """
    if operation_name == "merge" and operation_scope == "Instance" and fhir_request.RequestMethod == "POST":
        # obtenir la ressource primaire
        primary_resource = json.loads(fhir_service.interactions.Read(fhir_request.Type, fhir_request.Id)._ToJSON())
        # obtenir la ressource secondaire
        secondary_resource = json.loads(fhir_request.Json._ToJSON())
        # retrouver la différence entre les deux ressources
        # utiliser deepdiff pour obtenir la différence entre les deux ressources
        diff = DeepDiff(primary_resource, secondary_resource, ignore_order=True).to_json()

        # créer un nouvel %DynamicObject pour stocker le résultat
        result = iris.cls('%DynamicObject')._FromJSON(diff)

        # mettre le résultat dans la réponse
        fhir_response.Json = result
    
    return fhir_response

à tester :

POST https://localhost:4443/fhir/r5/Patient/1/$merge
Authorization : Bearer <Token>
Accept: application/fhir+json

{
  "resourceType": "Patient",
  "id": "2",
  "meta": {
    "versionId": "2"
  }
}

Vous obtiendrez la différence entre les 2 patients.

{
    "values_changed": {
        "root['address'][0]['city']": {
            "new_value": "fdsfd",
            "old_value": "Lynnfield"
        },
        "root['meta']['lastUpdated']": {
            "new_value": "2024-02-24T09:11:00Z",
            "old_value": "2024-02-28T13:50:27Z"
        },
        "root['meta']['versionId']": {
            "new_value": "1",
            "old_value": "2"
        }
    }
}

Félicitations, vous avez créé l'opération personnalisée. 🥳

9. Trucs et Astuces

9.1. Journal de Csp

In %SYS

set ^%ISCLOG = 5
zw ^ISCLOG

9.2. Solution de BP

Cliquez pour voir le code
from grongier.pex import BusinessProcess
import iris
import jwt
import json
from fhir.resources import patient, bundle

class MyBusinessProcess(BusinessProcess):

    def on_init(self):
        if not hasattr(self, 'target'):
            self.target = 'HS.FHIRServer.Interop.HTTPOperation'
            return

    def on_fhir_request(self, request:'iris.HS.FHIRServer.Interop.Request'):
        # Faire quelque chose avec la requête
        self.log_info('Received a FHIR request')

        # La passer à la cible
        rsp = self.send_request_sync(self.target, request)

        # Essayez d'obtenir le jeton de la requête
        token = request.Request.AdditionalInfo.GetAt("USER:OAuthToken") or ""

        # Faire quelque chose avec la réponse
        if self.check_token(token):
            self.log_info('Filtering the response')
            # Filtrer la reponse
            payload_str = self.quick_stream_to_string(rsp.QuickStreamId)

            # si le payload est vide, renvoyer la réponse
            if payload_str == '':
                return rsp

            filtered_payload_string = self.filter_resources(payload_str)
            if filtered_payload_string == '':
                return rsp

            # écrire la chaîne json dans un flux rapide
            quick_stream = self.string_to_quick_stream(filtered_payload_string)

            # renvoyer la réponse
            rsp.QuickStreamId = quick_stream._Id()

        return rsp
    
    def check_token(self, token:str) -> bool:

        # décoder le jeton
        decoded_token= jwt.decode(token, options={"verify_signature": False})

        # vérifier si le jeton est valide
        if 'VIP' in decoded_token['scope']:
            return True
        else:
            return False

    def quick_stream_to_string(self, quick_stream_id) -> str:
        quick_stream = iris.cls('HS.SDA3.QuickStream')._OpenId(quick_stream_id)
        json_payload = ''
        while quick_stream.AtEnd == 0:
            json_payload += quick_stream.Read()

        return json_payload
    
    def string_to_quick_stream(self, json_string:str):
        quick_stream = iris.cls('HS.SDA3.QuickStream')._New()

        # écrire la chaîne json dans le payload
        n = 3000
        chunks = [json_string[i:i+n] for i in range(0, len(json_string), n)]
        for chunk in chunks:
            quick_stream.Write(chunk)

        return quick_stream

    def filter_patient_resource(self, patient_str:str) -> str:
        # filtrer le patient
        p = patient.Patient(**json.loads(patient_str))
        # supprimer le nom
        p.name = []
        # supprimer l'adresse
        p.address = []
        # supprimer le télécom
        p.telecom = []
        # supprimer la date de naissance
        p.birthDate = None

        return p.json()

    def filter_resources(self, resource_str:str) -> str:
        # analyser le payload
        payload_dict = json.loads(resource_str)

        # quel est le type de ressource?
        resource_type = payload_dict['resourceType'] if 'resourceType' in payload_dict else 'None'
        self.log_info('Resource type: ' + resource_type)

        # c'est un paquet?
        if resource_type == 'Bundle':
            obj = bundle.Bundle(**payload_dict)
            # filrer le paquet
            for entry in obj.entry:
                if entry.resource.resource_type == 'Patient':
                    self.log_info('Filtering a patient')
                    entry.resource = patient.Patient(**json.loads(self.filter_patient_resource(entry.resource.json())))

        elif resource_type == 'Patient':
            # filtrer le patient
            obj = patient.Patient(**json.loads(self.filter_patient_resource(resource_str)))
        else:
            return resource_str

        return obj.json()
0
0 50
Article Iryna Mykhailova · Juil 17, 2024 4m read

Parmi les points problématiques de la maintenance des interfaces HL7 figure la nécessité d'effectuer un test de régression fiable lors du déploiement dans de nouveaux environnements et après les mises à jour. La classe %UnitTest permet de créer des tests unitaires et de les intégrer au code de l'interface. Les données de test peuvent également être enregistrées au sein de la classe de test unitaire, ce qui permet de réaliser rapidement et facilement des tests de fumée et des tests de régression.

##Ressources:

##Scénario: Une classe de test unitaire sera créée pour chaque flux entrant en fonction des exigences en matière de profilage, de routage et de mappage des données.

  • Exigences relatives aux échantillons:*

Functional Requirements

Pour tester chaque scénario, nous devons lancer un échantillon pour chaque type d'événement et confirmer les règles de routage. Il nous faut également confirmer les exigences spécifiques en matière de mappage et trouver des exemples de données pour chaque scénario.

##Production HL7

L'objectif de ce UnitTest-RuleSet est de tester un pipeline HL7 : Service métierRègles de routageTransformation.

Dans cet exemple créé pour la production illustrée ci-dessous, le flux de processus ADT passe par plusieurs sauts supplémentaires. Une classe étendant UnitTest.RuleSet.HL7 a été modifiée pour permettre de traiter des flux de processus plus complexes.

Flux de processus: FromHSROUTER.TESTAdtFromTESTAdt.ReorgSegmentProcessRouteTESTAdtTEST.ADTTransformHS.Gateway.HL7.InboundProcess

HL7 Production

##Création d'une Classe de Test Unitaire

Créez une classe TestAdtUnitTest qui étend UnitTest.RuleSet.HL7. (UnitTest.RuleSet.Example dans le référentiel UnitTest-RuleSet contient un exemple d'une telle classe.

*Remarque: Dans cet exemple, tout a été déplacé sous HS.Local dans HSCUSTOM pour faciliter les tests. *

Signature:Class HS.Local.EG.UnitTest.TestAdtUnitTest Extends HS.Local.Util.UnitTest.RuleSet.HL7

##Aperçu de la structure des classes

La classe de test unitaire est organisée de la manière suivante:

Unit Test Class Layout

##Paramètres de configuration

Ces paramètres de classe sont utilisés pour configurer les tests.

// Espace de noms où la production est située
Parameter Namespace = "EGTEST";

// Répertoire de base pour les tests unitaires

Parameter TestDirectory = "/tmp/unittest";

// nom du sous-répertoire pour les tests unitaires

Parameter TestSuite = "TEST-HL7ADT";

/// Remplacement pour un schéma différent
Parameter HL7Schema = "2.5.1:ADT_A01";

/// Remplacement par le nom du service existant en production
Parameter SourceBusinessServiceName = "FromHSROUTER.TESTAdt";

/// Remplacer par le nom du moteur de routage de processus métier existant en production
Parameter TargetConfigName = "FromTESTAdt.ReorgSegmentProcess";

/// Nom du processus de routage primaire en production
Parameter PrimaryRoutingProcessName = "RouteTESTAdt";

/// Nom du processus de routage secondaire en production
Parameter SecondaryRoutingProcessName = "TEST.ADTTransform";

Remarque: Les processus de routage primaire et secondaire sont référencés dans les différentes méthodes de test afin de tester la sortie et les résultats de deux processus de routage enchaînés.

##Création d'exemples de messages d'entrée

Pour créer une classe de test unitaire réutilisable, il faut enregistrer des échantillons anonymes pour chaque type d'événement et tout message supplémentaire nécessaire à la réalisation des scénarios de test dans la classe de test unitaire, dans des blocs XDATA au bas du fichier.

  • Exemple du bloc XDATA:*

Le nom *SourceMessageA01 * est utilisé pour référencer le bloc XDATA spécifique.

XData SourceMessageA01 { <![CDATA[ MSH|^~\&|Epic|TEST||TEST|20230911060119|RUBBLE|ADT^A01|249509431|P|2.2 EVN|A01|20230911060119||ADT_EVENT|RUBBLE^MATTHEW^BARNEY^D^^^^^TEST^^^^^UH|20230911060000|PHL^PHL^ADTEDI ZVN||LS23450^LS-23450^^^^RTL PID|1|000163387^^^MRN^MRN|000163387^^^MRN^MRN||FLINTSTONE^ANNA^WILMA||19690812|F|MURRAY^ANNA~FLINTSTONE^ANNA^R~FLINTSTONE^ANNA|B|100 BEDROCK WAY^^NORTH CHARLESTON^SC^29420-8707^US^P^^CHARLESTON|CHAR|(555)609-0969^P^PH^^^555^6090969~^NET^Internet^ANNAC1@YAHOO.COM~(555)609-0969^P^CP^^^555^6090969||ENG|M|CHR|1197112023|260-61-5801|||1|||||Non Veteran|||N ZPD||MYCH||AC|||N||N PD1|||TEST HOLLINGS CANCER CENTER^^10003|1134107873^LINK^MICHAEL^J^^^^^EPIC^^^^PNPI ROL|1|UP|GENERAL|1134107873^LINK^MICHAEL^J^^^^^EPIC^^^^PNPI|20211115 NK1|1|GABLE^BETTY|PARENT||(555)763-5651^^PH^^^555^7635651||Emergency Contact 1 NK1|2|FLINTSTONE^FRED|Spouse|100 Bedrock way^^REMBERT^SC^29128^US|(888)222-2222^^PH^^^888^2222222|(888)222-3333^^PH^^^888^2223333|Emergency Contact 2 PV1|1|O|R1OR^RTOR^07^RT^R^^^^TEST RT OR|EL|||1386757342^HALSTEAD^LUCINDA^A.^^^^^EPIC^^^^PNPI|1386757342^HALSTEAD^LUCINDA^A.^^^^^EPIC^^^^PNPI||OTO||||PHYS|||1386757342^HALSTEAD^LUCINDA^A.^^^^^EPIC^^^^PNPI|SO||BCBS|||||||||||||||||||||ADMCONF|||20230911060000 PV2||PRV||||||20230911||||HOSP ENC|||||||||N|N||||||||||N ZPV||||||||||||20230911060000 OBX|1|NM|PRIMARYCSN|1|1197112023||||||F AL1|1|DA|900525^FISH CONTAINING PRODUCTS^DAM|3|Anaphylaxis|20210823 AL1|2|DA|568^PEANUT^HIC|3|Anaphylaxis|20221209 AL1|3|DA|12753^TREE NUT^HIC|3|Anaphylaxis|20221209 AL1|4|DA|1193^TREE NUTS^DAM|3|Anaphylaxis|20130524 AL1|5|DA|1554^HYDROCODONE^HIC||Other|20210728 AL1|6|DA|3102^POLLEN EXTRACTS^HIC||Other|20201204 AL1|7|DA|11754^SHELLFISH DERIVED^HIC||Other|20210728 DG1|1|I10|Q85.02^Neurofibromatosis, type 2^I10|Neurofibromatosis, type 2||ADMISSION DIAGNOSIS (CODED) DG1|2|I10|D33.3^Benign neoplasm of cranial nerves^I10|Benign neoplasm of cranial nerves||ADMISSION DIAGNOSIS (CODED) DG1|3|I10|J38.01^Paralysis of vocal cords and larynx, unilateral^I10|Paralysis of vocal cords and larynx, unilateral||ADMISSION DIAGNOSIS (CODED) DG1|4||^NF2 (neurofibromatosis 2) [Q85.02]|NF2 (neurofibromatosis 2) [Q85.02]||ADMISSION DIAGNOSIS (TEXT) DG1|5||^Acoustic neuroma [D33.3]|Acoustic neuroma [D33.3]||ADMISSION DIAGNOSIS (TEXT) DG1|6||^Unilateral complete paralysis of vocal cord [J38.01]|Unilateral complete paralysis of vocal cord [J38.01]||ADMISSION DIAGNOSIS (TEXT) GT1|1|780223|FLINTSTONE^ANNA^WILMA^^^^L||100 BEDROCK WAY^^NORTH CHARLESTON^SC^29420-8707^US^^^CHARLESTON|(555)609-0969^P^PH^^^555^6090969~(555)763-5651^P^CP^^^555^7635651||19690812|F|P/F|SL|248-61-5801|||||^^^^^US|||Full ZG1||||1 IN1|1|BL90^BCBS/STATE EMP^PLANID||BCBS STATE|ATTN CLAIMS PROCESSING^PO BOX 100605^COLUMBIA^SC^29260-0605||(800)444-4311^^^^^800^4444311|002038404||||20140101||NPR||FLINTSTONE^THOMAS^^V|Sp|19661227|3310 DUBIN RD^^NORTH CHARLESTON^SC^29420^US|||1|||||||||||||1087807|ZCS49984141|||||||M|^^^^^US|||BOTH IN3|1|||2||20230911|20230911|RUBBLE^MATTHEW^BARNEY^D|||NOT|||||(800)999-0000^^^^^800^9990000~(888)444-5555^^^^^888^4445555 ZIN|||||||FLINTSTONE^THOMAS^^V|||||16871492 ]]> }

Exemple de code permettant d'extraire des données d'un bloc XDATA pour les utiliser dans le cadre de tests :

set xdata=##class(%Dictionary.CompiledXData).%OpenId(..%ClassName(1)_"||"_XDataName,0)

Voici un exemple de code de ** GetMessage**, une méthode d'assistance utilisée pour lire et renvoyer les données d'un bloc XDATA en fonction du nom du bloc.

ClassMethod GetMessage(XDataName As %String) As EnsLib.HL7.Message { #dim SourceMessage as EnsLib.HL7.Message set xdata=##class(%Dictionary.CompiledXData).%OpenId(..%ClassName(1)_"||"XDataName,0) quit:'$IsObject(xdata) $$$NULLOREF set lines="" while 'xdata.Data.AtEnd { set line=$ZSTRIP(xdata.Data.ReadLine(),"<w") continue:line="" continue:$Extract(line,1)="<" // ignorer les balises XML ouvrantes ou fermantes et commencer la balise CData continue:$Extract(line,1)="]" // ignorer ]]> closing CDATA set lines=lines($S($L(lines)=0:"",1:$C(..#NewLine)))_line } set SourceMessage=##class(EnsLib.HL7.Message).ImportFromString(lines,.tSC) quit:$$$ISERR(tSC) $$$NULLOREF set SourceMessage.DocType=..#HL7Schema set tSC=SourceMessage.PokeDocType(..#HL7Schema) quit SourceMessage }

##Création de méthodes de test

La classe de test unitaire contient également une méthode de test qui configure chaque test de manière programmatique, injecte le message dans la production et vérifie que le message transformé qui en résulte correspond à ce qui est attendu.

L'exemple de test contient les méthodes de test suivantes :

  • TestMessageA01
  • TestMessageA02
  • TestMessageA03
  • TestMessageA04
  • TestMessageA05
  • TestMessageA06
  • TestMessageA08
  • TestMessageA28
  • TestMessageA31
  • TestCorrectAssigningAuthorityForA01
  • TestEncoutnerNumberPresent
  • TestPD1LocationMapped

Exemple de méthode: TestMessageA01 Méthode permettant de vérifier que les messages A01 sont traités sans erreur et routés vers la transformation correcte.

Method TestMessageA01() { Set ReturnA01 = ..#SecondaryRoutingProcessName_":HS.Local.EG.ProfSvcs.Router.Base.ADT.TransformA01" #dim message as EnsLib.HL7.Message

    // Télécharger un nouveau message HL7 par UnitTest
set ..HL7Message=..GetMessage("SourceMessageA01")
quit:'$IsObject(..HL7Message) $$$ERROR(5001,"Failed to correlate Xdata for Source Message")

set routingProcess = ..#PrimaryRoutingProcessName

set message=..HL7Message.%ConstructClone(1)
do message.PokeDocType(message.DocType)
do message.SetValueAt("SYSA","MSH:3.1")
set expectSuccess=1
set expectReturn="send:"_ReturnA01
set expectReason="rule#8"
do ..SendMessageToRouter(message,"TestMessageA01",routingProcess, expectSuccess, expectReturn, expectReason)

}

Remarque: SendMessageToRouter() est une méthode mise en œuvre dans le paquet UnitTest-RuleSet.

Exemple de méthode: TestEncounterNumberPresent

La méthode ci-dessous vérifie la présence de valeurs spécifiques dans le message après la transformation.

Method TestEncounterNumberPresent()
{
	#dim message as EnsLib.HL7.Message

    // Télécharger un nouveau message HL7 par UnitTest
set ..HL7Message=..GetMessage("SourceMessageA01")
quit:'$IsObject(..HL7Message) $$$ERROR(5001,"Failed to correlate Xdata for Source Message")

// source du processus de transformation
set routingProcess = ..#SecondaryRoutingProcessName
set message=..HL7Message.%ConstructClone(1)
do message.PokeDocType(message.DocType)
do message.SetValueAt("SYSA","MSH:3.1")
// Vérifier que la sortie PV1:19 n'est pas vide
set expectSuccess=1
set expectElement="PV1:19"
set expectReturnVal="1197112023"
do ..SendMessageReturnOutput(message,"TestMessageA01", routingProcess, expectSuccess, expectElement, expectReturnVal)
 }

Remarque: SendMessageReturnOutput() est une méthode modifiée pour renvoyer le message résultatif pour évaluation.

##Comment exécuter le UnitTest

Les mises en œuvre de la classe %UnitTest dépend de la globale ^UnitTestRoot pour l'emplacement des dossiers de travail des tests unitaires.

Il y a deux paramètres utilisés pour définir les dossiers:

 // Répertoire de base pour les tests unitaires
 Parameter TestDirectory = "/tmp/unittest";

 // nom du sous-répertoire pour les tests unitaires
 Parameter TestSuite = "TEST-HL7ADT";

Dans ce cas, la classe s'attend à ce que le dossier : /tmp/unittest/TEST-HL7ADT soit présent dans l'environnement où la classe de test unitaire est exécutée.

En outre, la mise en œuvre personnalisée définit la globale ^UnitTestRoot et passe à l'espace de noms spécifique dans le paramètre d'espace de noms Namespace.

Pour le lancement depuis le terminal:

HSCUSTOM> do ##class(HS.Local.EG.UnitTest.TestAdtUnitTest).Debug()

Les résultats du lancement seront envoyés à la console. Si l'un des tests échoue, tout le test est considéré comme ayant échoué. Outre le terminal, on peut également consulter les résultats à partir du portail de gestion. Pour ouvrir l'URL, utilisez le lien figurant dans le résultat.

##Extrait du résultat de la Console

TestMessageA31 passed TestPD1LocationMapped() begins ... 14:50:20.104:...t.TestAdtUnitTest: TestPD1Location Sent LogMessage:SessionId was 130 LogMessage:Source Config Name name is :TEST.ADTTransform LogMessage:Message Body Id was 94 LogMessage:Expect Success is 0 LogMessage:Testing for value PV1:39 LogMessage:Found value AssertNotEquals:Expect No Match:TestPD1Location:ReturnValue= (failed) <<==== FAILED TEST-HL7ADT:HS.Local.EG.UnitTest.TestAdtUnitTest:TestPD1LocationMapped LogMessage:Duration of execution: .033106 sec. TestPD1LocationMapped failed HS.Local.EG.UnitTest.TestAdtUnitTest failed Skipping deleting classes TEST-HL7ADT failed

Use the following URL to view the result: http://192.168.1.229:52773/csp/sys/%25UnitTest.Portal.Indices.cls?Index=3&$NAMESPACE=EGTEST Some tests FAILED in suites: TEST-HL7ADT

##Affichage des résultats dans le portail de gestion

Utilisez l'URL affichée sur le terminal et copiez-la dans un navigateur pour voir les résultats. En cliquant sur le nom du test, vous obtiendrez des détails supplémentaires.

Unit Test in Management Portal

En cliquant sur le lien de chaque test, vous obtiendrez plus d'informations sur le test :

UnitTest Results

##Conclusion La création de classes de tests unitaires pour chaque interface HL7 et leur intégration dans le code de l'interface permettent de documenter le processus de test et les échantillons de données, ainsi que de tester rapidement la régression de toute mise à jour ou modification des données ou de leur mise en œuvre.

Lors du déploiement, la classe de test unitaire sert de test de fumée autonome pour confirmer que l'interface est complète et fonctionnelle.

##Considérations supplémentaires

  • Le cadre UnitTest_RuleSet peut être adapté aux tests unitaires du CCDA. Les tests de routage sont relativement semblables à l'exemple HL7. Pour répondre aux exigences de mappage, il faut mettre en œuvre la classe de test unitaire pour gérer XSLT et XPaths.

  • Les responsables de l'assurance qualité peuvent recueillir des exigences et des échantillons de données pour configurer la classe de test unitaire avant le début de la mise en œuvre.

  • Les tests unitaires pour toutes les interfaces peuvent être regroupés dans le gestionnaire de tests unitaires (Unit Test Manager), de sorte que l'ensemble des tests peut être exécuté en une seule fois pour valider la configuration et le code existants.

0
0 50
Article Pierre LaFay · Juin 26, 2024 1m read

Ajouter un identifiant pour se connecter à l'interface FHIR REST - dans ce cas, ne considérer qu'une authentification de base

 

Ajouter un registre de service - dans ce cas, ne considérer qu'une authentification de base

- configurer un service HTTP

- saisir le chemin d'accès au serveur FHIR

- saisir l'URL du service FHIR

- utiliser l'identifiant profilé


 

 

Ajouter un "HS.FHIRServer.Interop.HTTPOperation"

Choisissez le nom du service

Tester le client FHIR

Tracer le résultat du test

0
0 66
Article Guillaume Rongier · Juin 24, 2024 10m read

InterSystems IRIS dispose d'une série de dispositifs facilitant la capture, la persistance, l'interopérabilité et la génération d'informations analytiques à partir de données au format XML. Cet article vous montrera comment procéder:

  1. Capture du XML (via un fichier dans notre exemple);
  2. Traitement des données capturées en interopérabilité;
  3. Persistance du XML dans les entités/tables persistantes;
  4. Création des vues analytiques pour les données XML capturées.

Capture des données XML

L'InterSystems IRIS dispose de nombreux adaptateurs intégrés pour capturer des données, notamment les suivants:

  1. Adaptateur de fichiers : utilisé pour obtenir des fichiers à partir de dossiers de réseau.
  2. Adaptateur FTP : utilisé pour obtenir des fichiers à partir de serveurs FTP/SFTP. 
  3. Adaptateur SOAP/Services Web : utilisé pour recevoir des données XML à partir d'opérations de services Web.
  4. Adaptateurs HTTP: utilisés pour acquérir des données et des fichiers XML à partir de points de terminaison HTTP.
  5. D'autres adaptateurs peu courants pour obtenir des données XML, par exemple des adaptateurs de messagerie. Vous pouvez les trouver à l'adresse suivante http://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=PAGE_interop_protocols.

Pour capturer des données à l'aide de productions d'interopérabilité, il faut configurer une production et utiliser un service métier Business Service associé à un adaptateur approprié. Les services métier les plus courants sont énumérés ci-dessous:

  1. EnsLib.XML.Object.Service.FileService. C'est l'option que je préfère car elle utilise un adaptateur de fichier pour obtenir un fichier XML à partir du réseau et le charger sur des objets mappés en schéma XML. C'est l'approche que nous emploierons dans cet article.
  2. EnsLib.XML.Object.Service.FTPService. Il utilise un adaptateur FTP pour acquérir un fichier XML à partir d'un serveur FTP et le charger sur des objets mappés en schéma XML.
  3. EnsLib.XML.FileService. Il utilise un adaptateur de fichier pour obtenir un fichier XML à partir du réseau et le charger sur un flux de fichiers File Stream.
  4. EnsLib.XML.FTPService. Il utilise un adaptateur FTP pour obtenir un fichier XML à partir du serveur FTP et le charger sur un flux de fichiers File Stream.
  5. EnsLib.HTTP.GenericService et EnsLib.HTTP.Service. Ils utilisent un adaptateur HTTP pour consommer un point de terminaison HTTP et acquérir un contenu du fichier XML.
  6. EnsLib.SOAP.GenericService et EnsLib.SOAP.Service. Ils utilisent un adaptateur SOAP pour consommer un point de terminaison SOAP et recevoir un contenu du fichier XML.

Persistance et/ou interopérabilité du XML capturé

Pour rendre persistantes ou envoyer (interopérer) les données XML, vous pouvez utiliser tous les adaptateurs mentionnés ci-dessus, mais vous devez également inclure l'adaptateur SQL. Il est utilisé pour conserver les données dans les bases de données SGBDR, par exemple la base de données IRIS. Vous trouverez ci-dessous la liste des adaptateurs couramment utilisés pour l'interopérabilité:

  1. Adaptateur SQL : pour interopérer les données vers les bases de données cibles.
  2. Adaptateur Kafka: pour interopérer les données de manière asynchrone dans des rubriques Kafka.
  3. Adaptateur REST: pour interagir avec les API REST.
  4. Adaptateurs PEX: pour interagir avec les composants natifs Java, dotNet ou Python.  

Pour interopérer ou conserver des données à l'aide de productions d'interopérabilité, il faut configurer une production et utiliser une opération métier associée à un adaptateur approprié. Les opérations métier les plus couramment utilisées sont les suivantes:

  1. EnsLib.SQL.Operation.GenericOperation: utilisée pour conserver les données capturées dans les bases de données SQL et IRIS.
  2. EnsLib.Kafka.Operation: utilisée pour publier les données capturées/traitées dans les rubriques Kafka. 
  3. EnsLib.REPOS.GenericOperation: utilisée pour envoyer des données capturées/traitées aux méthodes des API REST, permettant des intégrations via des API REST.
  4. EnsLib.SAVON.GenericOperation: utilisée pour envoyer des données capturées/traitées aux méthodes de service Web SOAP, permettant des intégrations via des services Web SOAP.
  5. EnsLib.PEX.BusinessOperation: utilisée pour envoyer des données capturées/traitées aux composants Java, dotNet et Python natifs.
  6. EnsLib.XML.Objet.Opération.Ftoperation et EnsLib.XML.Objet.Opération.FileOperation: utilisées pour enregistrer des données XML sous forme de fichier à partir de données d'objet dans des serveurs FTP et des emplacements de système de fichiers Filesystem.

Entre les données capturées à l'aide des services métier et les données envoyées par les opérations métier, il est possible d'utiliser un processus métier pour mettre en œuvre des règles/logiques métier ou pour mapper et traduire le format et la structure des données du service métier à l'opération métier. Les types de processus métier les plus courants sont les suivants:

  1. Ens.BusinessProcessBPL. Il implémente la logique métier à l'aide du langage visuel BPL.
  2. EnsLib.MsgRouter.RoutingEngine. Il est utilisé pour mettre en œuvre la logique de mappage et de traduction afin de convertir les données capturées dans le protocole/la structure utilisé(e) par les opérations métier.
  3. EnsLib.PEX.BusinessProcess. Il est utilisé pour mettre en œuvre la logique métier via Java, DotNet ou Python.

En reprenant le système d'interopérabilité InterSystems IRIS, nous avons ce qui suit:


Pour illustrer et matérialiser l'interopérabilité des données XML, nous allons utiliser un exemple d'application Open Exchange.

Interopérabilité XML: un échantillon

Installer l'échantillon

1. Clone/git extrait le référentiel dans n'importe quel répertoire local.

$ git clone https://github.com/yurimarx/iris-xml-sample.git

2. Ouvrez le terminal dans ce répertoire et lancez:

$ docker-compose build

3. Lancez le conteneur IRIS avec votre projet:

$ docker-compose up -d

 

Lancement de la production d'échantillons

1. Ouvrez le lien http://localhost:52796/csp/user/EnsPortal.ProductionConfig.zen?$NAMESPACE=USER&$NAMESPACE=USER& 
2. Cliquez sur le bouton Start et voyez tous les rubriques en vert:


CConfiguration du VSCode pour ce projet

1. Ouvrez le code source dans VSCode:


2. Dans le pied de page, recherchez le bouton ObjectScript (uniquement s'il n'est pas encore connecté):

3. Cliquez dessus et sélectionnez "Toggle Connection" en haut de la page:

4. Vous avez maintenant le VSCode et le serveur IRIS connectés à l'espace de noms de l'utilisateur USER:

Traitement d'un échantillon XML

1. Accédez à l'onglet Explorateur:

2. Sélectionnez le fichier books.xml et copiez-le dans le dossier xml_input:

3. Une ou deux secondes plus tard, le fichier books.xml sera traité et supprimé du dossier (VSCode affiche le fichier comme étant effacé et le supprime).
4. Vous pouvez maintenant voir les résultats dans l'éditeur de production: http://localhost:52796/csp/user/EnsPortal.ProductionConfig.zen?$NAMESPACE=USER&$NAMESPACE=USER&
5. Accédez à l'onglet Messages et cliquez sur la première session de la liste:

6. Consultez l'onglet Contenu:

7. Accédez maintenant à l'éditeur SQL: http://localhost:52796/csp/sys/exp/%25CSP.UI.Portal.SQL.Home.zen?$NAMESPACE=USER&$NAMESPACE=USER 

8. Exécutez le SQL suivant et regardez les résultats:

SELECTID, author, description, genre, price, publish, title, totalDays
FROM dc_XmlDemo.Catalog


À ce stade, nous allons découvrir le code source de cet échantillon.

Derrière les coulisses : le code source

Création d'un mappage de classe pour le schéma XML

1. Ouvrez le fichier books.xml et copiez son contenu:

2. Nous devons créer un schéma XML pour ce fichier XML au cas où il n'existerait pas encore. J'ai utilisé ce site : https://www.liquid-technologies.com/online-xml-to-xsd-converter. Cependant, il existe de nombreuses autres possibilités en ligne. Il faut donc insérer le contenu XML et cliquer sur Générer un schéma.

3. Copiez le schéma XML généré et créez le fichier books.xsd avec son contenu.:

4. Accédez au terminal IRIS. Pour ce faire, cliquez sur le bouton docker:iris:52796[USER] dans le pied de page et sélectionnez l'option Ouvrir le terminal dans Docker:


5. Écrivez les commandes comme indiqué ci-dessous:

USER>set reader = ##class(%XML.Utils.SchemaReader).%New()              
USER>do reader.Process("/home/irisowner/dev/xml_input/books.xsd","dc.XmlDemo.Schemas")


6. Cette méthode de classe IRIS crée pour vous des classes qui correspondent à la structure XML, ce qui vous permet d'accéder au XML par le biais de classes, de propriétés et de méthodes:


Création de la classe persistante pour stocker les livres ingérés à partir de données XML

1. Créez le fichier Catalog.cls dans le dossier src/dc/XmlDemo avec le contenu suivant:

Class dc.XmlDemo.Catalog Extends%Persistent
{

Property author As%String(MAXLEN = 200);Property title As%String;Property genre As%String;Property price As%Double;Property publish As%Date;Property totalDays As%Integer;Property description As%String(MAXLEN = ""); }


2. Je ne comprends pas bien cette phrase. Peut-être que l'auteur voulait dire : "Cette classe élargit la classe %Persistent, ce qui nous permet de stocker des données persistantes dans la base de données".
3. Ces propriétés reflètent les données XML. Cependant, l'une d'entre elles, totalDays, n'est pas présente dans les données XML. Elle sera calculée en fonction du nombre de jours écoulés entre la publication et le jour actuel. Vous devez enregistrer cette classe pour la créer sur le serveur IRIS.

Création des informations d'identification pour accéder à la base de données IRIS à partir de la production

1. Accéder à Interopérabilité > Configuration > Informations d'identification et créer une référence IrisCreds:

  • Identifiant: IrisCreds
  • Nom de l'utilisateur: _SYSTEM
  • Mot de passe: SYS

2. Cliquez sur Enregistrer (Save).


Création de la Production d'Interopérabilité

1. Accéder à Interopérabilité &gt ; Liste &gt ; Productions:


2. Créez une nouvelle production en cliquant sur le bouton Nouveau (New).
3. Saisissez les valeurs conformément à l'image ci-dessous et cliquez sur le bouton OK:

4. Cliquez sur le bouton + à côté des Services:


5. Définissez les options comme indiqué ci-dessous:

6. Remplissez les chemins d'accès au fichier XML avec les données suivantes:

  • Chemin d'accès au fichier: /home/irisowner/dev/xml_input/
  • Spécification du fichier: *.xml
  • Chemin d'accès à l'Archive: /home/irisowner/dev/xml_output/

7. Saisissez le nom de la classe et le nom du composant pour obtenir les données relatives aux éléments du livre au moment de l'exécution:

8. Cliquez sur le bouton Appliquer (Apply).
9. À ce stade, il est préférable d'utiliser Java Gateway car nous allons établir une connexion JDBC avec la base de données du serveur IRIS pour envoyer des commandes d'insertion SQL et sauvegarder les données. Cette approche est valable pour tous les fournisseurs de bases de données, y compris Oracle, SQL Server, DB2, MySQL et PostgreSQL, lorsque vous devez rendre persistantes des données XML dans une table SQL.
10. Cliquez à nouveau sur le bouton + à côté des Services. Saisissez les champs comme illustré ci-dessous et cliquez sur le bouton OK:


11. Choisissez la passerelle JavaGateway et saisissez les données suivantes dans le champ de chemin d'acces à la classe:

  • Chemin d'acces à la classe: /usr/irissys/dev/java/lib/1.8/*.jar


12. Ce chemin contient le pilote JDBC de la base de données IRIS.
13. Cliquez sur le bouton Appliquer (Apply).
14. Cliquez sur le bouton + à côté des Opérations.
15. Saisissez les valeurs et cliquez sur le bouton OK:


16. Choisissez SqlOperation et saisissez le DSN avec le nom de l'utilisateur (espace de noms dans lequel la table SQL du livre est disponible).
17. Sélectionnez IrisCreds dans le champ des Informations d'identification.
18. Écrivez la commande SQL suivante dans le champ de requête:

insertinto dc_XmlDemo.Catalog(author, description, genre, price, publish, title,totalDays) values (?,?,?,?,DATE(?),?,DATEDIFF('d',?,CURRENT_DATE))


19. Saisissez la valeur dc.XmlDemo.Schemas.book dans RequestClass:

20. Cliquez sur le bouton + à côté de Ajouter (Add) et cliquez sur le bouton Liste à côté du bouton X pour choisir le champ du premier paramètre ‘?’:

21. Sélectionnez *author et cliquez sur le bouton OK:

22. Incluez plus de paramètres pour obtenir les résultats affichés ci-dessous:

23. Il est essentiel de vérifier si vos valeurs ont * avant le champ.
24. Cliquez sur le bouton Appliquer (Apply).
25. Maintenant, choisissez à nouveau XmlFileService et définissez le champ des noms de configuration cible (Target Config Names) sur SqlOperation. Cela permettra au service de recevoir les données XML et d'envoyer les valeurs à l'opération SqlOperation enregistrée dans la base de données.

26. Arrêtez la production créée dans l'exemple avant de lancer celle que vous avez développée:

27. Cliquez sur Ouvrir (Open) et l'arrêter (Stop):

28. Sélectionnez la production dont vous avez besoin: 
29. Sélectionnez votre nouvelle production, ouvrez-la et démarrez-la.
30. Dans VSCode, copiez le fichier books.xml dans le dossier xml_input pour tester votre production.
31. Observez les résultats comme indiqué dans la section d'échantillon XML de processus (Process XML Sample) et profitez-en!

0
1 100
Article Sylvain Guilbaud · Avr 30, 2024 3m read

Gitter

Configuration de Production

Cette démo comporte une production d'interopérabilité contenant 16 composants. 

Configuration de Production HL7 + Kafka Producer

La première partie de cette démonstration consiste à envoyer un fichier HL7 SIU qui sera transmis aux 2 autres flux HL7 (HTTP et TCP), et transformé et transmis au serveur Kafka. Les flux HTTP et TCP transformeront les messages HL7 de la même manière avant de les envoyer également à Kafka.

0
0 189