#Interoperabilidad

0 Seguidores · 127 Publicaciones

En los servicios médicos, la compatibilidad  operativa es la capacidad que tienen los diferentes sistemas en tecnología de la información y aplicaciones de software para comunicarse, intercambiar datos y utilizar la información que se intercambió.

Artículo Alberto Fuentes · mayo 26, 2022 2m read

¡Hola desarrolladores! ¿habéis tenido que desarrollar alguna integración DICOM alguna vez? Es posible que hayáis buscado ejemplo, o incluso un simulador con el que poder simular ciertas comandos. Aquí os paso un ejemplo que puede seros útil.

DICOM es un protocolo de comunicaciones muy extendido en sanidad en el ámbito de la imagen diagnóstica. Tanto con IRIS For Health como con Health Connect podéis desarrollar integraciones que empleen el protocolo DICOM, aquí tenéis disponible la documentación.

En muchas ocasiones, cuando estamos desarrollando la integración DICOM es muy útil que podamos contar con un simulador que haga las veces de un sistema externo (e.g. un PACS) y podamos probar por completo el circuito a implementar antes de conectarlo con un sistema real.

Aquí os paso un ejemplo que implementa dos ejemplos de integraciones DICOM utilizando IRIS For Health y también el simulador dcm4che.

Los dos circuitos de ejemplo que encontraréis son:

Recepción de un DICOM por TCP que contiene un informe PDF embebido

image

Búsqueda y recepción (Query / retrieve) de imágenes en un PACS

Circuito de búsqueda

image

Circuito de recepción

image

Cualquier aporte será bienvenido! :)

6
0 772
Artículo Luis Angel Pérez Ramos · oct 28, 2022 8m read

Acceso a Producción Programática

Para editar producciones programáticamente (interfaces) puedes usar una combinación de APIs de Interoperabilidad y consultas SQL.

Namespace actual

Es importante conocer el namespace y la producción en la que estás trabajando.

// Object script 
// El namespace activo se guarda en esta variable
$$$NAMESPACE 
// Imprimir el namespace
Write $$$NAMESPACE
# Python
import iris
# Este método retorna el namespace activo
iris.utils._OriginalNamespace()
# Imprimir el namespace
print(iris.utils._OriginalNamespace())
>>> DEMONSTRACIÓN

Producción activa

También, es importante conocer el nombre de tu producción. Puedes recuperar la producción activa en un namespace usando las siguientes APIs

// ObjectScript
USER>ZN "DEMONSTRATION"
// Obtener la última producción en ejecución
DEMONSTRATION>W ##class(Ens.Director).GetActiveProductionName()
>>> Hospital.HospitalProduction
#  Python
import os
os.environ['IRISNAMESPACE'] = 'DEMONSTRATION'
import iris
active_production = iris.cls('Ens.Director').GetActiveProductionName()
print(active_production)
>>> Hospital.HospitalProduction

Cómo encontrar elementos en una producción

Puedes usar Objectscript o Python para encontrar elementos activos en la producción

1. Consulta SQL para obtener elementos en producción

SELECT Name FROM Ens_Config.Item Where Production = 'Hospital.HospitalProduction'
-- 
['From_Athena_Multi']
['From_Athena_Multi_Router']
['From_Cerner_ADT']
['From_Cerner_ADT_Router']
['From_Cerner_Orders']
['From_Cerner_Orders_Router']
['From_Dictaphone_Results']
['From_Dictaphone_Results_Router']
['From_Lab_Results']
['From_Lab_Results_Router']
['From_Radiology_Results']
['From_Radiology_Results_Router']
['HS.IHE.XDSb.DocumentSource.Operations']
['HS.IHE.XDSb.Repository.Operations']
['To_Cerner_Results']
['To_Dictaphone']
['To_Intellilab']
['To_Lab']
['To_Radiology']
-- 

2. Consulta SQL para obtener elementos activos en producción

SELECT Name, ClassName 
FROM Ens_Config.Item 
WHERE Production = 'Hospital.HospitalProduction' 
  AND Enabled = 1

-- 
Name	                                ClassName
To_Radiology	                        EnsLib.HL7.Operation.FileOperation
To_Lab	                                EnsLib.HL7.Operation.FileOperation
To_Dictaphone	                        EnsLib.HL7.Operation.FileOperation
From_Cerner_ADT	                        EnsLib.HL7.Service.FileService
From_Cerner_ADT_Router	                EnsLib.HL7.MsgRouter.RoutingEngine
From_Radiology_Results_Router	        EnsLib.HL7.MsgRouter.RoutingEngine
From_Lab_Results_Router	                EnsLib.HL7.MsgRouter.RoutingEngine
From_Dictaphone_Results_Router	        EnsLib.HL7.MsgRouter.RoutingEngine
To_Intellilab	                        EnsLib.HL7.Operation.FileOperation
To_Cerner_Results	                    EnsLib.HL7.Operation.FileOperation
From_Cerner_Orders_Router	            EnsLib.HL7.MsgRouter.RoutingEngine
From_Athena_Multi_Router	            EnsLib.HL7.MsgRouter.RoutingEngine
HS.IHE.XDSb.DocumentSource.Operations	HS.IHE.XDSb.DocumentSource.Operations
-- 

3. Acceso por ObjectScript a elementos de la Producción

// ObjectScript 
// Acceso para obtener todos los elementos de una producción activa
// Devuelve la lista de elementos
ClassMethod ListItemsInProduction()
{
    Set productionName =  ##class(Ens.Director).GetActiveProductionName()
    Set items = []
    &sql(Declare curr cursor FOR Select Name into :newId from Ens_Config.Item Where Production = :productionName)
    &sql(OPEN curr)
    For {
        &sql(FETCH curr)
        Quit:SQLCODE
        Do items.%Push(newId)
    }
    &sql(CLOSE curr)
    quit items
}

>>> zw ##class(ISC.SE.ProductionTools).ListItemsInProduction()

["From_Athena_Multi","From_Athena_Multi_Router","From_Cerner_ADT","From_Cerner_ADT_Router","From_Cerner_Orders","From_Cerner_Orders_Router","From_Dictaphone_Results","From_Dictaphone_Results_Router"
,"From_Lab_Results","From_Lab_Results_Router","From_Radiology_Results","From_Radiology_Results_Router","HS.IHE.XDSb.DocumentSource.Operations","HS.IHE.XDSb.Repository.Operations","To_Cerner_Results"
,"To_Dictaphone","To_Intellilab","To_Lab","To_Radiology"]  ; <DYNAMIC ARRAY>
# Python
# Obtención del entorno de datos de los elementos activos de la producción

import os
# Definición de variables de entorno
os.environ['IRISNAMESPACE'] = 'DEMONSTRATION'
import iris

def getActiveProductionItems():
    productionName = iris.cls('Ens.Director').GetActiveProductionName()
    df = iris.sql.exec("SELECT Name FROM Ens_Config.Item Where Production = '{}'".format(productionName))
    return df

production_items_df = getActiveProductionItems().dataframe()

#                                      name
# 0                       From_Athena_Multi
# 1                From_Athena_Multi_Router
# 2                         From_Cerner_ADT
# 3                  From_Cerner_ADT_Router
# 4                      From_Cerner_Orders
# 5               From_Cerner_Orders_Router
# 6                 From_Dictaphone_Results
# 7          From_Dictaphone_Results_Router
# 8                        From_Lab_Results
# 9                 From_Lab_Results_Router
# 10                 From_Radiology_Results
# 11          From_Radiology_Results_Router
# 12  HS.IHE.XDSb.DocumentSource.Operations
# 13      HS.IHE.XDSb.Repository.Operations
# 14                      To_Cerner_Results
# 15                          To_Dictaphone
# 16                          To_Intellilab
# 17                                 To_Lab
# 18                           To_Radiology

Cómo manipular producciones vía API

1. Añadir componentes

// ObjectScript
set productionName = ##class(Ens.Director).GetActiveProductionName()
//crear un nuevo servicio de archivos xml
set classname="EnsLib.XML.FileService"	//clase de este elemento
set name="NewService"			//nombre de la configuración
set item=##class(Ens.Config.Item).%New(classname)

set item.Name=name
set item.Comment = "Test Service"
set item.PoolSize = "1"
set item.Enabled = 1
do item.%Save()
//	
// Abrir la clase de la producción
// set prod="Test.configtest"	//el nombre de la producción se define manualmente
// O
set prod = productionName
set prodObj=##class(Ens.Config.Production).%OpenId(prod)
//se graba el nuevo elemento
set tSC=prodObj.Items.Insert(item)
set tSC=prodObj.SaveToClass(item)
set tSC=prodObj.%Save()

// ELIMINACIÓN del elemento anterior
set tSC = prodObj.RemoveItem(item)
set tSC = prodObj.SaveToClass()
set tSC=prodObj.%Save()
# Python
import os
os.environ['IRISNAMESPACE'] = 'DEMONSTRATION'
import iris
active_production = iris.cls('Ens.Director').GetActiveProductionName()
print("Current Production {}".format(active_production))

# Metadata sobre el componente
classname="EnsLib.XML.FileService"	 # clase de esta elemento
name="NewService"			         # nombre de la configuración
item=iris.cls('Ens.Config.Item')._New(classname) # Creación del nuevo componente
item.Name=name
item.Comment = "Test Service"
item.PoolSize = "1"
item.Enabled = 1
item._Save()

# Se carga la clase de la producción
# prod="Test.configtest"	# el nombre de la producción se define manualmente
# O se usa la producción activa anterior
prod = active_production

prodObj=iris.cls('Ens.Config.Production')._OpenId(prod)
# grabamos la producción después de insertar el elemento en ella
tSC=prodObj.Items.Insert(item)
tSC=prodObj.SaveToClass(item)
tSC=prodObj._Save()

# ELIMINAMOS el elemento anterior
tSC = prodObj.RemoveItem(item)
tSC = prodObj.SaveToClass()
tSC=prodObj._Save()

2. Deshabilitar / Habilitar Componentes

// ObjectScript
set productionName = ##class(Ens.Director).GetActiveProductionName()
set itemName = "My.Inbound.HL7"
// Obligatorio para habilitar el elemento
Set componentName = productionName _ "||" _ itemName _ "|"
// Habilitar or deshabilitar
Set enable = 1 // or 0
Do ##class(Ens.Director).EnableConfigItem(componentName, enable, 1)

/// Habilitar o deshabilitar un ConfigItem en una producción. La producción puede estar activa o no.
/// El argumento pConfigItemName proporciona el nombre del elemento de configuración para habilitar o deshabilitar
/// En el caso de múltiples coincidencias de elementos con el mismo nombre de configuración, si alguno ya está habilitado entonces
///  la opción pEnable=1 no hará nada y la opción pEnable=0 deshabilitará el elemento de la producción activa o, si no está activa, 
/// el primer elemento coincidente que esté habilitado que encuentre.
///   
/// Ver el método Ens.Director.ParseConfigName() para ver la sintáxis del string de especificación del nombre del ConfigItem.
ClassMethod EnableConfigItem(pConfigItemName As %String, pEnable As %Boolean = 1, pDoUpdate As %Boolean = 1)
# Python
import os
os.environ['IRISNAMESPACE'] = 'DEMONSTRATION'
import iris

active_production = iris.cls('Ens.Director').GetActiveProductionName()
item_name = "My.Inbound.HL7"
componentName = active_production + "||" + item_name + "|"

enable = 1 # or 0
iris.cls('Ens.Director').EnableConfigItem(componentName, enable, 1)

Estado de la producción a través de API

// ObjectScript
/// Este método devuelve el estado de la producción por los parámetros de salida.
/// pProductionName: Devuelve el nombre de la producción cuando el estado es en ejecución, suspendida o con problemas.
/// pState: Salidas del estado de la producción. Los valores válidos son:
///          $$$eProductionStateRunning == 1
///          $$$eProductionStateStopped == 2
///          $$$eProductionStateSuspended == 3
///          $$$eProductionStateTroubled == 4
Set sc = ##class(Ens.Director).GetProductionStatus(.productionName, .productionState) 
Write productionName, " -- ", productionState
import os
# Configurar el namespace a las malas
os.environ['IRISNAMESPACE'] = 'DEMONSTRATION'

import iris

# TEST 2 con variables de salida
productionName, productionState = iris.ref('productionName'), iris.ref('productionState')
status = iris.cls('Ens.Director').GetProductionStatus(productionName, productionState) 

print("Status: {}".format(status))
# ver .value
print("Production: {}".format(productionName.value))
# ver .value
print("Production State: {}".format(productionState.value))
0
1 169
Artículo Ricardo Paiva · ene 29, 2021 8m read

¡Hola Desarroladores!

IRIS External Table es un proyecto de código abierto de la comunidad de InterSystems, que permite utilizar archivos almacenados en el sistema de archivos local y almacenar objetos en la nube como AWS S3 y tablas SQL. IRIS External Table

Se puede encontrar en GitHub https://github.com/intersystems-community/IRIS-ExternalTable Open Exchange https://openexchange.intersystems.com/package/IRIS-External-Table y está incluido en el administrador de paquetes InterSystems Package Manager (ZPM).

Para instalar External Table desde GitHub, utilice:

git clone https://github.com/antonum/IRIS-ExternalTable.git
iris session iris
USER>set sc = ##class(%SYSTEM.OBJ).LoadDir("<path-to>/IRIS-ExternalTable/src", "ck",,1)

Para instalarlo con el ZPM Package Manager, utilice:

USER>zpm "install external-table"

Cómo trabajar con archivos locales

Crearemos un archivo simple que tiene este aspecto:

a1,b1
a2,b2

Abra su editor favorito y cree el archivo o utilice solo una línea de comandos en Linux/Mac:

echo $'a1,b1\na2,b2' > /tmp/test.txt

Cree una tabla SQL en IRIS para representar este archivo:

create table test (col1 char(10),col2 char(10))

Convierta la tabla para utilizar el almacenamiento externo:

CALL EXT.ConvertToExternal(
    'test',
    '{
        "adapter":"EXT.LocalFile",
        "location":"/tmp/test.txt",
        "delimiter": ","
    }')

Y finalmente, consulte la tabla:

select * from test

Si todo funciona según lo previsto, debería ver el resultado de la siguiente forma:

col1    col2
a1  b1
a2  b2

Ahora regrese al editor, modifique el contenido del archivo y ejecute nuevamente la consulta SQL. ¡¡¡Tarán!!! Está leyendo nuevos valores de su archivo local en SQL.

col1    col2
a1  b1
a2  b99

Cómo leer los datos desde S3

En https://covid19-lake.s3.amazonaws.com/index.html puede acceder a los datos de la COVID que se actualizan constantemente, estos se almacenan por AWS en el lago de datos públicos.

Intentaremos acceder a una de las fuentes de datos en este lago de datos: s3://covid19-lake/rearc-covid-19-nyt-data-in-usa/csv/us-states

Si tiene instalada la herramienta de línea de comandos para AWS, puede repetir los siguientes pasos. Si no es así, vaya directamente a la parte de SQL. No es necesario que tenga ningún componente específico de AWS instalado en su equipo para continuar con la parte de SQL.

$ aws s3 ls s3://covid19-lake/rearc-covid-19-nyt-data-in-usa/csv/us-states/
2020-12-04 17:19:10     510572 us-states.csv

$ aws s3 cp s3://covid19-lake/rearc-covid-19-nyt-data-in-usa/csv/us-states/us-states.csv .
download: s3://covid19-lake/rearc-covid-19-nyt-data-in-usa/csv/us-states/us-states.csv to ./us-states.csv

$ head us-states.csv 
date,state,fips,cases,deaths
2020-01-21,Washington,53,1,0
2020-01-22,Washington,53,1,0
2020-01-23,Washington,53,1,0
2020-01-24,Illinois,17,1,0
2020-01-24,Washington,53,1,0
2020-01-25,California,06,1,0
2020-01-25,Illinois,17,1,0
2020-01-25,Washington,53,1,0
2020-01-26,Arizona,04,1,0

Por lo tanto, tenemos un archivo con una estructura bastante simple y cinco campos delimitados.

Para mostrar esta carpeta S3 como en External Table, primero necesitamos crear una tabla “regular” con la estructura deseada:

-- create external table
create table covid_by_state (
    "date" DATE, 
    "state" VARCHAR(20),
    fips INT,
    cases INT,
    deaths INT
)

Tenga en cuenta que algunos campos de datos como “Date” son palabras reservadas en el SQL de IRIS y deben escribirse entre comillas dobles. Entonces, necesitamos convertir esta tabla “regular” en la tabla “externa”, basada en el bucket AWS S3 y con el tipo CSV.

 -- convert table to external storage
call EXT.ConvertToExternal(
    'covid_by_state',
    '{
    "adapter":"EXT.AWSS3",
    "location":"s3://covid19-lake/rearc-covid-19-nyt-data-in-usa/csv/us-states/",
    "type": "csv",
    "delimiter": ",",
    "skipHeaders": 1
    }' 
)

Si observa detenidamente, en EXT.ExternalTable los argumentos de los procedimientos son el nombre de la tabla y luego la cadena JSON, además contiene varios parámetros como la ubicación para buscar archivos, el adaptador para utilizarlos, un delimitador, etc. Además, External Table de AWS S3 es compatible con el almacenamiento de Azure BLOB, Google Cloud Buckets y el sistema de archivos local. El repositorio de GitHub contiene referencias para la sintaxis y opciones que son compatibles con todos los formatos.

Y finalmente, consulte la tabla:

-- query the table
select top 10 * from covid_by_state order by "date" desc

[SQL]USER>>select top 10 * from covid_by_state order by "date" desc
2.  select top 10 * from covid_by_state order by "date" desc

date    state   fips    cases   deaths
2020-12-06  Alabama 01  269877  3889
2020-12-06  Alaska  02  36847   136
2020-12-06  Arizona 04  364276  6950
2020-12-06  Arkansas    05  170924  2660
2020-12-06  California  06  1371940 19937
2020-12-06  Colorado    08  262460  3437
2020-12-06  Connecticut 09  127715  5146
2020-12-06  Delaware    10  39912   793
2020-12-06  District of Columbia    11  23136   697
2020-12-06  Florida 12  1058066 19176

Es comprensible que se necesite más tiempo para consultar los datos de la tabla remota, que para consultar la tabla “nativa de IRIS” o la tabla basada en el global, pero esta se almacena y actualiza completamente en la nube, y en segundo plano se extrae a IRIS.

Exploremos un par de funciones adicionales de External Table.

%PATH y las tablas basadas en varios archivos

La carpeta de nuestro ejemplo, que se encuentra en el bucket, contiene solo un archivo. Lo más común es que tenga varios archivos de la misma estructura, donde el nombre del archivo identifique tanto al registro de la hora como al identificador de algún otro atributo que queramos utilizar en nuestras consultas.

El campo %PATH se agrega automáticamente a cada tabla externa y contiene la ruta completa hacia el archivo de donde se recuperó la fila.

select top 5 %PATH,* from covid_by_state

%PATH   date    state   fips    cases   deaths
s3://covid19-lake/rearc-covid-19-nyt-data-in-usa/csv/us-states/us-states.csv    2020-01-21  Washington  53  1   0
s3://covid19-lake/rearc-covid-19-nyt-data-in-usa/csv/us-states/us-states.csv    2020-01-22  Washington  53  1   0
s3://covid19-lake/rearc-covid-19-nyt-data-in-usa/csv/us-states/us-states.csv    2020-01-23  Washington  53  1   0
s3://covid19-lake/rearc-covid-19-nyt-data-in-usa/csv/us-states/us-states.csv    2020-01-24  Illinois    17  1   0
s3://covid19-lake/rearc-covid-19-nyt-data-in-usa/csv/us-states/us-states.csv    2020-01-24  Washington  53  1   0

Puede utilizar el campo %PATH en sus consultas SQL como cualquier otro campo.

De datos ETL a “tablas regulares”

Si su tarea es cargar datos de S3 en una tabla IRIS, puede utilizar External Table como una herramienta ETL. Simplemente haga lo siguiente:

INSERT INTO internal_table SELECT * FROM external_table

En nuestro caso, si queremos copiar los datos COVID de S3 a la tabla local:

--create local table
create table covid_by_state_local (
    "date" DATE, 
    "state" VARCHAR(100),
    fips INT,
    cases INT,
    deaths INT
)
--ETL from External to Local table
INSERT INTO covid_by_state_local SELECT TO_DATE("date",'YYYY-MM-DD'),state,fips,cases,deaths FROM covid_by_state

UNIÓN entre IRIS, tablas nativas y externas. Consultas federadas

External Table es una tabla SQL. Se puede unir con otras tablas, utilizarse en subconsultas y sistemas de archivos tipo UNION. Incluso puede combinar la tabla “Regular” de IRIS y dos o más tablas externas que provengan de diferentes fuentes en la misma consulta SQL.

Intente crear una tabla regular, por ejemplo, haga coincidir los nombres de los estados con sus códigos como en el caso de Washington y WA. Y únalos con nuestra tabla basada en S3.

create table state_codes (name varchar(100), code char(2))
insert into state_codes values ('Washington','WA')
insert into state_codes values ('Illinois','IL')

select top 10 "date", state, code, cases from covid_by_state join state_codes on state=name

Cambie “join” por “left join” para incluir aquellas filas donde el código del estado no esté definido. Como puede ver, el resultado es una combinación de datos provenientes de S3 y su tabla nativa de IRIS.

Acceso seguro a la información

El lago de datos Covid en AWS es público. Cualquier persona puede leer los datos que provengan de esta fuente sin la necesidad de tener alguna autenticación o autorización. En la vida real seguramente quiere acceder a sus datos de una forma segura, donde se evite que extraños echen un vistazo a sus archivos. Los detalles completos sobre AWS Identity y Access Management (IAM) están fuera del alcance de este artículo. Pero lo mínimo que debe saber es que necesita por lo menos la clave de acceso a la cuenta y la información confidencial de AWS para acceder a los datos privados de su cuenta. https:

AWS utiliza la autenticación de claves/información confidencial de la cuenta para firmar las solicitudes. https://docs.aws.amazon.com/general/latest/gr/aws-sec-cred-types.html#access-keys-and-secret-access-keys

Si está ejecutando IRIS External Table en una instancia de EC2, la forma recomendada de lidiar con la autenticación es utilizando las funciones que se encuentran en la instancia de EC2 https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html. De este modo, IRIS External Table podría utilizar los permisos de esa función. No se requiere ninguna configuración adicional.

En una instancia local o que no sea de EC2 es necesario especificar AWS_ACCESS_KEY_ID y AWS_SECRET_ACCESS_KEY, ya sea con la ayuda de variables de entorno o mediante la instalación y configuración del cliente CLI de AWS.

export AWS_ACCESS_KEY_ID=AKIAEXAMPLEKEY
export AWS_SECRET_ACCESS_KEY=111222333abcdefghigklmnopqrst

Asegúrese de que la variable de entorno sea visible dentro del proceso de IRIS. Puede verificarlo al ejecutar:

USER>write $system.Util.GetEnviron("AWS_ACCESS_KEY_ID")

Esto debería emitir el valor de la clave.

O instale el CLI de AWS, mediante instrucciones que se encuentran aquí: https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2-linux.html y ejecutar:

aws configure

Entonces External Table podrá leer las credenciales desde los archivos de configuración para el CLI de AWS. Posiblemente su shell interactivo y el proceso de IRIS estén ejecutándose en cuentas diferentes, asegúrese de ejecutar aws configure con la misma cuenta que su proceso de IRIS.

1
0 147
Artículo Ricardo Paiva · sep 29, 2022 2m read

¡Hola Comunidad!

A lo largo de los años siempre he pensado en crear cosas nuevas, modificar las existentes, experimentar, probar, romper (siempre pasa), construir de nuevo, y empezar otra vez.

Los concursos promovidos por InterSystems son una excelente fuente de motivación. Obviamente los premios llaman la atención y eso no se puede negar. Pero no se trata solo de los premios/regalos - los concursos son un reto creativo, una oportunidad de crear, reimaginar, probar, experimentar... Y lo mejor de todo es que eres libre de hacer todo lo que quieras!

Así que ví estos concursos como una oportunidad de crear mi propio Y si...? (la serie en la que Marvel permite a los autores re-imaginar sus historias como quieran) y he sido muy afortunado de encontrar otra persona que recibe estas ideas con los brazos abiertos laugh ¡Muchas gracias, @José Pereira!

En el último concurso de Interoperabilidad, creé el visualizador de mensajes Message Viewer y en este concurso de Interoperabilidad traigo de nuevo el Message Viewer, pero esta vez con Visual Trace!

0
0 152
Artículo Eduard Lebedyuk · sep 26, 2022 2m read

A veces necesitamos depurar una Business Operation (BO). El registro y seguimiento (trazas) funcionan, pero a veces quieres trabajar con una BO en tu sesión en el terminal local.

Así es como puedes hacerlo en cualquier sistema operativo.

Windows tiene una estupenda herramienta para depurar Business Operations - en modo Foreground. En ese modo, Windows ejecuta un terminal local con un job para la operación.

0
0 131
Artículo Heloisa Paiva · sep 6, 2022 4m read


Recientemente empecé a estudiar interoperabilidad y la documentación oficial fue muy útil para comprender la operación de los business hosts, pero aún me costó lograr hacerlo con mis manos. Mis compañeros de trabajo me ayudaron hasta que logré crear una Demo de un sistema y aprender practicando. Por eso, quise escribir acá para pasar adelante la ayuda que tuve.

0
0 159
Artículo Alberto Fuentes · sep 1, 2022 2m read

¡Hola desarrolladores!

Quizá os hayáis encontrado con escenarios donde no tenéis que implementar un repositorio FHIR, sino por ejemplo reenviar peticiones FHIR, gestionar las respuestas y tal vez realizar modificaciones o extraer algunos valores por el camino. Aquí encontraréis algunos ejemplos que pueden implementarse con InterSystems IRIS For Health o HealthShare Health Connect.

En estos ejemplos he utilizado producciones de interoperabilidad con el FHIR Interoperability Adapter y los mensajes tipo HS.FHIRServer.Interop.Request.

Si por el contrario estáis interesados en implementar un repositorio FHIR, no dejéis de ver el Webinar que hicimos en su día.

Un primer escenario podría ser tener que construir una petición FHIR de cero quizá a partir de un fichero o tal vez una consulta SQL y a continuación reenviarlo a un servicio FHIR externo: image

Otro escenario podría ser hacer de pasarela de peticiones / respuestas FHIR contra un repositorio externo, gestionando el paso de tokens OAuth. image

Y finalmente podríamos pensar quizá en recibir peticiones FHIR para reenviarlas a un servicio FHIR externo, pero pudiendo extraer cierta información o manipulando algunos campos el camino. image

Los detalles de la implementación los encontraréis en la aplicación Open Exchange :)

¡Espero que os sirva!

0
0 259
Artículo Ricardo Paiva · jul 7, 2022 15m read

Si tuvieras la oportunidad de cambiar algo en el Visualizador de Mensajes de Interoperabilidad en IRIS, ¿qué harías?

Después de publicar el artículo Panel de Control "IRIS History Monitor", recibí algunos comentarios muy interesantes y varias peticiones. Una de ellas fue un Visualizador de Mensajes mejorado.
 
Si aún no lo has hecho, echa un vistazo al proyecto: merece la pena que le dediques un rato, y además ganó el 3er premio (Bronce) a Los mejores desarrolladores y aplicaciones de InterSystems Open Exchange en 2019.
 
Empecé a pensar algunas ideas sobre lo que me gustaría incluir en el "nuevo" Visualizador de Mensajes pero ¿cómo podría mostrar estos recursos de la forma más rápida y sencilla?
0
0 174
InterSystems Official Jose-Tomas Salvador · abr 13, 2022

Hola!! Hemos abierto una plaza de Sales Engineer en InterSystems para nuestra oficina de Madrid.

No se requieren conocimientos de nuestra tecnología aunque, por supuesto, tenerlos puede ser un gran plus. Lo más importante es que te apasione la tecnología, te guste compartir conocimiento, aprender de otros y enseñar,... y no te asusten los retos, para encontrar soluciones innovadoras junto con nuestros partners a las necesidades que se les plantean, en areas como rendimiento de BBDDs, interoperabilidad, desarrollo de aplicaciones críticas, IA,....

0
0 192
Artículo Ricardo Paiva · mar 24, 2022 9m read

Este artículo es una continuación de esta publicación.

En ese artículo, analizamos el desarrollo de business processes, que forman parte de los componentes necesarios para la integración del sistema y sirven como coordinadores de la producción.

En este artículo mostraremos la creación de un business service, que es la ventana de entrada de información para la producción.

Y, finalmente, llegamos al último artículo de "¡Utilicemos la interoperabilidad!"

El business service proporciona una ventana de entrada para la información enviada desde fuera de IRIS, con o sin utilizar el adaptador para I/F externo.

Hay tres tipos de business services en la muestra (los enlaces entre paréntesis son enlaces al código de la muestra):

  1. Business services para archivos que utilizan adaptadores de entradaStart.FileBS
  2. Business services para servicios web que utilizan el adaptador de entrada SOAPStart.WS.WebServiceBS
  3. Business services llamados por procedimientos almacenados o REST sin utilizar adaptadoresStart.NonAdapterBS

Los diferentes métodos de conexión que se utilizan para introducir la información solo aumentarán el número de business services; sin embargo, el procesamiento realizado dentro de un business service es

Crear un mensaje de solicitud que se enviará
usando información introducida externamente y
simplemente llamar al business component

Sin ningún esfuerzo.

Ahora, describiremos cómo crear componentes que utilizan adaptadores de entrada de archivos.

Los business services se escriben en scripts, que pueden crearse en VSCode o Studio.

1. Business services para archivos que utilizan adaptadores de entrada(Start.FileBS

Si creas una clase en VSCode, deberías crear una clase que hereda de Ens.BusinessService. Para los adaptadores, puedes utilizar el parámetro ADAPTER como nombre de la clase ADAPTER (por ejemplo, especificar una clase de adaptador de entrada de archivos).
Si no utilizas el adaptador, no será necesaria ninguna configuración.

Class Start.FileBS Extends Ens.BusinessService
{
Parameter ADAPTER = "EnsLib.File.InboundAdapter";

En el adaptador de entrada de archivos, puedes especificar el directorio que se supervisará en Settings→File Path para el business service de la producción.

imagen

Si el archivo localizado en "File Path" coincide con la información especificada en "File Spec", este abre el archivo como un objeto de flujo. Lo define como la primera variable cuando se llama al business service ProcessInput().

Cuando se inicia ProcessInput(), se llama automáticamente a OnProcessInput(). OnProcessInput() se transmite directamente a OnProcessInput() con los parámetros transmitidos a ProcessInput().

imagen

En OnProcessInput() la sentencia inicial recibe la información del objeto file stream, que se transmite como primer parámetro, después crea un mensaje que se dará al siguiente componente, escribe el proceso de llamada al siguiente componente y completa la lógica básica.


【Memo】
En el caso de Studio, inicia el Asistente (Wizard) de Business Services en el menú de New Creation, selecciona el adaptador y haz clic en el botón Finalizar.


La definición del método OnProcessInput() es la siguiente:

Method OnProcessInput(pInput As %Stream.Object, Output pOutput As %RegisteredObject) As %Status

pInput es proporcionado con una instancia de la clase %Stream.FileCharacter para archivos de texto o de la clase %Stream.FileBinary para archivos binarios.

En el ejemplo, se introducirá un archivo en formato texto, y lo hemos escrito para aceptar solicitudes de varias líneas y una solicitud por línea.

La propiedad AtEnd se establece en 1 cuando se detecta EndOfFile. Puedes utilizar esta propiedad para detener el bucle.

En un bucle, leemos las líneas utilizando el método ReadLine(), que nos permite obtener información sobre los contenidos del archivo una línea cada vez ( consulta la documentación para más información sobre el adaptador de archivos).

Escribe el mensaje, recuperando información línea a línea. Después, ejecutamos el método ..SendRequestAsync(), que llama al resto de los componentes.

Cuando se ejecute el método, el primer parámetro debería ser el nombre del componente al que quieres llamar en forma de string, y el segundo parámetro debería ser el mensaje de solicitud que hayas creado.

Ten en cuenta que ..SendRequestAsync() es una llamada asincrónica y no espera recibir una respuesta.

Nota: También existe SendRequestSync() para las llamadas sincronizadas.。

El código de ejemplo es el siguiente:

imagen

Referencia: explicación del uso de la función $piece() en el texto de ejemplo anterior

$piece(“string”, ”delimiter mark”, ”position number”)

La función para establecer/obtener una string con un delimitador, en el ejemplo, para obtener el primer y segundo valor de datos separados por comas, se escribe con la siguiente sintaxis:

set request.Product=$piece(record,",",1)
set request.Area=$piece(record,",",2)

Ahora, revisemos la función de Start.FileBS tal y como aparecía en la descripción anterior.

En la producción del ejemplo, el "File Path" se estableció en /irisdev/src, y el "File Spec" se estableció en check.txt. Prepara el mismo directorio o cámbialo a otro y registra los datos de la muestra en el archivo check.txt con el siguiente formato: nombre del producto adquirido, nombre de la ciudad.

※Si estás utilizando el contenedor de muestra, cambia el nombre de [Test-check.txt] en el directorio src en el directorio que se creó con el clon de git.

imagen

imagen

2. Business services para servicios web que utilizan el adaptador de entrada SOAP (Start.WS.WebServiceBS

Posteriormente, describiremos la creación de business services para los servicios web.

La clase de Business Service para servicios web actúa como proveedor de servicios web = servidor de servicios web.

En el ejemplo, tenemos dos parámetros en el método del servicio web para esta producción de ejemplo, para tener información que se envía desde el cliente del servicio web. El método web utiliza los datos introducidos en los parámetros para crear una clase de mensaje y llamar a otros componentes.

imagen

Cuando se define una clase de servicio web, se crea una pantalla de prueba. Sin embargo, no se muestra de forma predeterminada.

Inicia sesión en IRIS (o inicia un terminal), ve al namespace donde se encuentra la producción y haz lo siguiente:

Para tu referencia:Acceso al catálogo y a las páginas de prueba

Esta es una configuración de código de ejemplo en el ajuste, donde el contenedor se inició con docker-compose up -d (ejecutar en el namespace %SYS)

set $namespace="%SYS"
set ^SYS("Security","CSP","AllowClass","/csp/user/","%SOAP.WebServiceInfo")=1
set ^SYS("Security","CSP","AllowClass","/csp/user/","%SOAP.WebServiceInvoke")=1


【Atención】Ten en cuenta que la frase distingue entre mayúsculas y minúsculas y debe escribirse con cuidado. Además, según el namespace en el que se utilice el producto, cambia el script especificado. La oración del ejemplo fue escrita considerando que el ejemplo se importa en el namespace USER.
Si importas el código del ejemplo en el namespace ABC, el cuarto subíndice debería ser "/csp/abc/".

Cuando se haya completado la configuración, ve a la siguiente URL:

http://localhost:52773/csp/user/Start.WS.WebServiceBS.cls

imagen

Si quieres ofrecer el WSDL a tu cliente de servicios web, especifica WSDL=1 al final de la siguiente URL

http://localhost:52773/csp/user/Start.WS.WebServiceBS.cls?WSDL

3. Business services llamados por procedimientos almacenados o REST sin utilizar adaptadores(Start.NonAdapterBS

A continuación, introduciremos el Business Service sin adaptadores (Start.NonAdapterBS).

imagen

Para los business services que utilizan adaptadores, el adaptador llama al método ProcessInput() del business service para detectar la información.

Si no utilizas adaptadores, puedes seguir llamando al método ProcessInput(), pero este método no es público. Por lo tanto, si implementas un business service que no utiliza adaptadores, tendrás que considerar ProcessInput().

La muestra utiliza los dos métodos siguientes:

Este es un ejemplo del procedimiento almacenado.

imagen

Después de añadir un business service (Start.NonAdapterBS) que no utiliza adaptadores a la producción (estado incorporado en la muestra), ejecuta el siguiente procedimiento almacenado

call Start.Utils_CallProduction('piroshki','Russia')

imagen

Un rastreo de los resultados de la ejecución es el siguiente:

imagen

A continuación, se muestra un ejemplo de creación de una clase dispatch para REST:

imagen

El XML descrito en el mapa de la URL de XData define qué métodos se llaman como respuesta a la URL en el momento que se realiza la llamada de REST.
En el ejemplo se describe una definición que llama al método WeatherCheck() cuando se proporcionan las URL's del /weather/first parameter (purchased product name)/ second parameter (name of the city) en la solicitud GET.

<Route Url="/weather/:product/:arecode" Method="GET" Call="WeatherCheck"/>

A continuación, define la URL base para la URL anterior en la pantalla de Configuración de la ruta de acceso a la aplicación web del Portal de administración, y estará completo.

Consulta este artículo para más detalles sobre la configuración.

Cuando esté listo, intenta ejecutar la información usando un business service que te permita enviar la información REST.

Ejemplo)http://localhost:52773/start/weather/Takoyaki/Osaka

imagen

imagen

Si no utilizas un adaptador, como ProcessInput() no se puede llamar directamente desde fuera, hemos creado un objeto para el business service en la lógica que se ejecuta por medio de REST o procedimientos almacenados (utilizando el método CreateBusinessService() de la clase Ens.Director) y llamado a ProcessInput()

Si utilizas un adaptador, este detecta la entrada y almacena la información en un objeto único y la transmite al business service. En cambio, si no utilizas un adaptador, el resto es prácticamente igual, la diferencia solo se encuentra en la parte del proceso mencionada anteriormente.

El business service está diseñado simplemente para utilizar la información que se introduce fuera de IRIS para crear mensajes de solicitud y llamar a los business components.

Durante la producción de la muestra, pudimos ver lo siguiente:

Los distintos componentes desempeñan diferentes funciones en la ejecución de una producción (business services, business processes, business operations).

Para transmitir información entre componentes, utiliza el mensaje.

Los mensajes se almacenan en la base de datos a menos que se borren y, por ello, se pueden rastrear en cualquier momento.

Algunos adaptadores facilitan el proceso que rodea a la conexión.

Estas son las operaciones básicas sobre cómo utilizar la interoperabilidad en IRIS.

También hay mapas de registros y herramientas de conversión de datos que son útiles para la entrada y salida de archivos CSV y otros archivos con formato específico.

Además, IRIS for Health también es compatible con las transmisiones FHIR y HL7 (incluyendo SS-MIX2).

Estaré encantado de explicarlo en otra publicación. Si tienes algo interesante que compartir, ¡deja un comentario!

Por último, también hay cursos de formación para aprender a utilizar la Interoperabilidad.

0
0 224
Artículo Ricardo Paiva · mar 11, 2022 8m read

Este artículo es una continuación de esta publicación.

En ese artículo, analizamos la creación de business operations a partir de los componentes necesarios para la integración del sistema.

En este artículo, mostraré cómo crear un business process que llama a las dos business operations definidas en el orden de la secuencia.

El business process actúa como coordinador (centro de mando) del proceso.

Los ajustes en el proceso que se pueden implementar en la muestra son los siguientes:

Paso 1: Proporcionar el nombre de la ciudad a una API web externa y solicitar información meteorológica.
Paso 2: Registrar el resultado de la consulta (información meteorológica) del paso 1 y el nombre del producto comprado que se recibió al inicio de la producción.

En el *business process* de muestra, esperaremos la respuesta al paso 1 y ajustaremos el paso 2 para que funcione.

En el proceso de espera de una respuesta (es decir, de sincronización), por ejemplo, ¿qué ocurre si el paso 1) no responde durante unos días?

Si se entregan nuevos mensajes al business process mientras se espera una respuesta durante unos días, los mensajes no serán descartados ya que se almacenan en una cola. Sin embargo, el business process no procesará nuevos mensajes y habrá un retraso en la operación.

Nota: Los business processes y las business operations tienen colas.

Por lo tanto, en producción, cuando hay una llamada sincronizada, hay dos maneras de que el business process pueda moverse: A) Hacer una sincronización perfecta, y B) Guardar el estado del propio business process en la base de datos y transferir el entorno de ejecución para que otros procesos puedan ejecutarse mientras esperan una respuesta.

A) Cómo hacer una sincronización perfecta:

Mientras se realiza una llamada sincronizada, el procesamiento del business process está en marcha, y esperando a que se procese el siguiente mensaje hasta que se complete todo el procesamiento.
➡Esta función se utiliza cuando se necesita garantizar el orden del procesamiento en el método "primero en entrar, primero en salir".

B) El método para guardar el estado del propio *business process* en la base de datos y transferir el entorno de ejecución para que otros procesos puedan ejecutarse mientras esperan una respuesta es

Cuando se realiza una llamada sincronizada, el proceso guarda su estado en la base de datos. Cuando se recibe un mensaje de respuesta, y es el momento de procesar el mensaje, se abre la base de datos y se ejecuta el siguiente proceso.
(IRIS gestionará el almacenamiento y la reapertura de los business processes en la base de datos).
➡ Se utiliza cuando es aceptable cambiar el orden para procesar los mensajes (es decir, cuando se permiten procesar más y más mensajes diferentes recibidos mientras se espera una respuesta).

En la muestra, se utiliza B).

Hay dos tipos de editores para crear business processes: un Editor de Business Processes que permite colocar cuadros de procesamiento (actividades) e implementarlos mientras se define su ejecución, y un método para crearlos mediante ObjectScript en Studio o VSCode.

Si utilizas el Editor de Business Processes, utilizarás la actividad de llamada para invocar al componente, pero esta actividad está implementada de la forma B). Por supuesto, también puedes implementar el métodoA) en el Editor de Business Processes, excepto que en ese caso no utilizará la actividad de llamada (utilizará la actividad del código).

En esta sección, explicaré cómo crearla.

Si se utiliza el Editor de Business Processes, deben escribirse en el Portal de Administración.

También puedes abrir el business process desde la página de configuración de la producción. La siguiente imagen muestra el procedimiento.

imagen

Iconos como en este editor se llaman actividades, y las que están marcadas como son actividades que pueden invocar otros componentes.

Este símbolo indica que se devolverá un mensaje de respuesta (es decir, se realizará una llamada sincronizada). La actividad se ajusta de forma predeterminada a la configuración de la llamada no sincronizada, que puede cambiarse según sea necesario.

Ahora observemos los business processes, que son componentes que se invocan al recibir un mensaje de solicitud, así como las business operations.

En la muestra, el mensaje de solicitud: Se pone en marcha cuando recibe un Start.Request y no devuelve un mensaje de respuesta.

imagen

En el business process, los mensajes aparecen en varias situaciones.

Mensajes de solicitud que se envían a los business processes.

Mensaje de solicitud (más un mensaje de respuesta) que se envía cuando se llama a otro componente usando la actividad.

En el Editor de Business Processes, los nombres de los objetos que almacenan mensajes están claramente separados para poder ver qué mensaje se envió desde qué destino.

imagen

  • solicitud(requisitos básicos)

El mensaje que activó el inicio del business process, en nuestro ejemplo, es Start.Request (el mensaje que se debe especificar en la configuración de la Solicitud en la pestaña Contexto dentro del Editor de Business Processes)

  • respuesta(respuesta básica)

Mensaje de respuesta para devolver a la persona que llama al business process (no se utiliza en el ejemplo) (mensaje que se debe especificar en la configuración de la respuesta que aparece en la pestaña Contexto en el Editor de Business Processes)

  • callrequest(mensaje de solicitud)

Mensaje de solicitud que se envía al llamar al componente determinado por la actividad.

  • callresponse(mensaje de respuesta)

Mensaje de respuesta devuelto desde el componente especificado por la actividad.

callrequest y callresponse son objetos que se eliminarán cuando se complete el procesamiento de llamada de la actividad. Todos los demás objetos no desaparecerán hasta que finalice el business process.

Ahora se presenta el problema cuando desaparece callresponse.

Esto es porque, como se puede ver en este ejemplo, Cuando se llama a un componente, si se quiere utilizar el resultado de la respuesta de un componente llamado previamente, se perderá el mensaje de respuesta, y se borrará la información que se iba a utilizar en el siguiente componente.

Es un problema 😓

¿Qué deberíamos hacer?・・・・・

En este caso, se puede utilizar el objeto de contexto.

El objeto de contexto, al igual que la solicitud/respuesta, es un objeto que sobrevive hasta el final del business process.

Además, como el contexto es un objeto genérico, se puede definir en el editor de proceso.

Además del contexto, también se puede utilizar el objeto de respuesta si tiene una propiedad que coincida con lo que guarda la información heredada.

Ahora, vamos a repasar los pasos de nuevo.

imagen

El mensaje de respuesta en el globo azul claro: Start.Response es un objeto que se eliminará cuando termine el proceso.

Como queremos utilizar el mensaje de respuesta (Start.Response) que contiene la información meteorológica como el mensaje que se enviará a la siguiente [Business Operation para la actualización de la base de datos], tenemos que implementar el objeto de contexto de tal forma que todos los valores de la propiedad del mensaje de respuesta (Start.Response) se puedan asignar a él.

Entonces, ¿cuál es la configuración para la propiedad de contexto?

Las propiedades se definen en "Context Properties" en la pestaña Context del Editor de business processes.

En este caso, nos gustaría guardar todas las propiedades del mensaje de respuesta (Start.Response) en el objeto de contexto. Por lo tanto, la especificación del tipo de propiedad se establece en Start.Response.

imagen

A continuación, consulta la configuración en la actividad.

imagen

Los mensajes de solicitud y de respuesta tienen un botón llamado ○○ Builder.

Al hacer clic en este botón se iniciará un editor de líneas que permite especificar lo que se quiere registrar en las propiedades de cada mensaje.

imagen

Después de esto, la business operation para solicitar una actualización de la base de datos (Start.SQLInsertOperation o Start.InsertOperation) se llama de la misma manera con la actividad, y todo estará listo.

(Para más información, consulta Configuring para Business Processes).

Cuando se haya completado la verificación, se podrá probar. El método de prueba es el mismo que se utiliza para probar las business operations (consulta este artículo).

El seguimiento después de la prueba es el siguiente:

imagen

Como el business process es el coordinador, pudimos ver que invocaba de forma secuencial los componentes definidos, lo que mantiene la ejecución sincronizada.

Nota 1: Este ejemplo solo se refiere a la actividad sobre las llamadas, pero hay otras actividades, como la transformación de datos.

Nota 2: Los business processes creados únicamente por ObjectScript, distintos al Editor de Business Processes, se heredan de la clase Ens.BusinessProcess. Si se crea en el Editor de Business Processes, se hereda de la clase Ens.BusinessProcessBPL.

El business process es el coordinador del proceso de integración del sistema.
El Editor de Business Processes ofrece los siguientes tipos de variables para los mensajes (request/response/callrequest/callreponse/context).
Un business process creado con el Editor de Business Processes puede funcionar de forma que no retrase otros mensajes, incluso si hay sincronización en la llamada del componente.

En el próximo artículo, mostraré finalmente cómo desarrollar el último componente: los business services.

0
0 286
Artículo Ricardo Paiva · feb 18, 2022 4m read

Este artículo es una continuación de esta publicación.

En ese artículo revisamos los contenidos de la producción. Ejecutamos el código de muestra y revisamos el contenido de los mensajes que fluyen en la producción en la página de Visual Trace.

En este artículo revisaremos el concepto y la definición de los mensajes que se utilizan para enviar y recibir datos entre componentes desde el contenido de desarrollo necesario para la integración del sistema.

Antes de crear un mensaje, vamos a revisar el caso de estudio.

Una empresa gestiona una tienda online y está cambiando el orden en que se muestra la información de los productos, para que coincida con las estaciones del año.
Sin embargo, algunos artículos se venden bien independientemente de la estación del año, mientras otros se venden en momentos inesperados, lo que no coincide con la regla actual de cambiar el orden.
Por lo tanto, estudiamos la posibilidad de cambiar el orden para que coincida con la temperatura del día en lugar de con la estación del año. Era necesario saber la temperatura de los productos adquiridos en ese momento.
Como se dispone de una API web externa para consultar la información meteorológica, planeamos recopilar la información meteorológica en el momento de la compra y registrarla en la base de datos.

En este caso, puedes observar lo siguiente:

La información que se recibe del exterior es el "nombre del producto comprado y el nombre de la ciudad".
La información que se envía desde IRIS a un sistema externo para solicitar el procesamiento es el "nombre de la ciudad". El resultado de este proceso será la "información meteorológica" para la ciudad que se utilizará como entrada.

imagen

A partir de este caso de estudio, implementaremos los componentes necesarios para la integración del sistema. Pero antes, para ejecutar los componentes, es necesario enviar y recibir mensajes, que son datos transmidos; y para utilizar los mensajes, es necesario definir la clase de mensajes.

Una clase de mensajes se diseña para considerar qué información (es decir, mensajes) debe enviarse y recibirse para que el componente se ejecute.

En este proceso, necesitamos estos dos tipos de información:

A) El nombre de la ciudad para enviar a una API web externa y así obtener la información meteorológica.

B) La información meteorológica y el nombre del producto adquirido para su registro en la base de datos.

El nombre de la ciudad en A) y el nombre del producto comprado en B) pueden incluirse en la información de entrada en IRIS.

La información meteorológica en B) puede recuperarse de la información de respuesta de una API web externa.

A continuación se muestra un diagrama que considera qué información sería necesaria para enviar y recibir cada componente a partir de los datos disponibles.

La primera línea en los globos amarillos describe el nombre de la clase de mensajes, y a partir de la segunda línea se indica lo que se debe establecer en las propiedades.

imagen

En el código de ejemplo, hay tres tipos de mensajes:

Start.Request(Mensaje de solicitud)
Se utiliza para enviar el nombre del producto comprado y la ciudad para adquirir la información meteorológica.

Start.Response(Mensaje de respuesta)
Se utiliza para devolver los resultados de las operaciones (información meteorológica) para obtener información meteorológica.

Start.InsertRequest(Mensaje de solicitud)
Se utiliza para enviar la información meteorológica y el nombre de los productos comprados para el registro en la base de datos.

Los mensajes se especifican en una superclase, Request message, y los Response messages derivan de Ens.Request y Ens.Response, respectivamente.

El siguiente es un ejemplo de la definición del mensaje de solicitud Start.Request.

Este es un ejemplo para la definición del mensaje de respuesta.

El mensaje de solicitud, Start.InsertRequest que se enviará con la solicitud de registro en la base de datos es el siguiente:

(Planeamos establecer la propiedad WeatherInfo con la información de Start.Response, que se devolverá después de obtener la información meteorológica).

Si quieres crearlo en Studio, también puedes utilizar el Asistente para Crear Mensajes.

Referencia) Pasos para crear una clase de respuesta en Studio.

La clave hasta ahora es

Una clase de mensajes se diseña con la idea de "qué información (es decir, mensajes) debe enviarse y recibirse" para que el componente FUNCIONE.

Cuando la clase de mensajes (que es la información que dirige cada componente) se implementa, el siguiente paso es crear una clase para el componente.

0
0 341
Artículo Ricardo Paiva · feb 8, 2022 7m read

Este artículo es una continuación de esta publicación.

En ese artículo, expliqué cómo funciona el menú de Interoperabilidad para su integración en el sistema.

En este artículo, me gustaría explicar cómo desarrollar una integración de sistemas utilizando el menú de interoperabilidad.

En primer lugar, ¿qué tipo de proceso quieres crear? Mientras piensas en ello, prepara el siguiente contenido.

  • Producción
  • Mensaje
  • Componentes
    • Business Services
    • Business Processes
    • Business Operations

Producción es una definición que se utiliza para especificar los componentes necesarios para la integración de sistemas y para almacenar la configuración de los componentes, que se configuran mediante el Portal de Administración (almacenado de forma interna como una definición de clase para la Producción).

Por ejemplo, supón que quieres crear un businessservice que procese los archivos colocados en un directorio específico a intervalos regulares. En ese caso, es necesario configurar exactamente qué directorios monitorizar y qué archivos procesar. Hay una Producción disponible para almacenar dicha configuración.

La configuración depende del adaptador usado por el componente que envía y recibe los datos.

Los adaptadores son clases para simplificar la conexión a los sistemas externos. Algunos son específicos de protocolos, como Mail/File/SOAP/FTP/HTTP/SQL/TCP, y otros son de específicos de estándares, como HL7.

Consulta la documentación (adaptadores específicos de protocolos y adaptadores relacionados con la documentación EDI) para más información sobre los adaptadores.

Como definiremos los componentes necesarios para la Producción, "Start Production" iniciará la integración del sistema, y "Stop Production" detendrá la integración del sistema.

El desarrollo necesario para completar la Producción es la creación de los componentes necesarios para la integración del sistema, concretamente los siguientes contenidos:

  • Mensaje
  • Componentes (Business Services, Business Processes, Business Operations)
  • Conversión de datos, etc.

El contenido anterior se explicará con más detalle en próximos artículos.

Primero vamos a iniciar la Producción utilizando la muestra Producción y comprobaremos el proceso de los mensajes al procesar los datos mientras se verifica la configuración.

La muestra puede descargarse en https://github.com/Intersystems-jp/selflearning-interoperability.

Para utilizar un contenedor, descarga el código de muestra por medio del clon en Git, ve al directorio del clon y ejecuta docker-compose up -d ¡Es así de fácil!

Consulta aquí el procedimiento (lleva un poco de tiempo crear un contenedor).

Si no utilizas contenedores, crea un nuevo namespace después de descargar la muestra, e importa todos los archivos de definición de clases (extensión .cls) a la carpeta src en el namespace creado.

Para más información sobre el proceso para crear un namespace, consulta el video desde el minuto 07:03 que aparece en este artículo.

Consulta el archivo README para más información sobre el código de muestra.

Cuando estés listo, ve al Portal de Administración (cambia el número de puerto del servidor web para que coincida con tu entorno).

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

Ve a Management Portal > Interoperability > Configuration > Production.

Si utilizas un método distinto al de los contenedores, conéctate al namespace donde importaste el código fuente, accede a [Configuration] > [Production], haz clic en el botón [Open], selecciona [Start] > [Production], y después haz clic en el botón [Start].

※ Si utilizas algo que no sea un contenedor, tendrás que hacer unos ajustes iniciales. Configura los contenidos descritos más abajo antes de probar los siguientes contenidos.

imagen

La página de producción se mostrará como [Component Name] para cada uno de los componentes "Service", "Process" y "Operation".

Haz clic sobre el nombre del componente para cambiar el contenido de la pestaña "Settings" en la parte derecha de la pantalla.

Por ejemplo, cuando haces clic sobre Start.GetKionOperation (un solo clic), se mostrará lo siguiente.

imagen

Este componente tiene la configuración de [HTTP Server] y de la [URL] para conectarse a la API Web. Hay un campo [appid] en la parte inferior de la configuración, donde se puede introducir la clave de la API que recibes. Hay un campo [lang] cerca de [appid] y se configura "ja" ("ja" = japonés). [lang] establece el idioma de la respuesta de OpenWeather. En el caso del inglés, selecciona "en". Cuando termines de definir esta configuración, haz clic en el botón "Apply".

imagen

Si utilizas un contenedor, la configuración está completa. Para más información, haz clic aquí.


Si estás probando con algo distinto a los contenedores

Realiza estos dos ajustes por adelantado:

  1. Configurar el cliente SSL.

Debido a que la API Web a la que se conectará estará comunicada mediante HTTPS, configura previamente el cliente SSL en el lado de IRIS.

Para que coincida con la configuración de la producción de muestra, utilizaremos el nombre [openweather]. La configuración de la Producción es la siguiente:

imagen

Haz clic en Management Portal > [System Administration] > [Security] > [SSL/TLS Configuration] > [Create New Configuration], escribe "openweather" en el campo "Configuration Name", y haz clic en el botón "Save" para terminar.

imagen

  1. Crear una URL base para REST

En la producción de muestra, lo configuramos para que la información se pueda introducir mediante REST, y la URL base para REST debe configurarse en el lado de IRIS.

En la muestra, definimos /start como la URL base. Dado que la clase Start.REST se encuentra en el namespace donde se importó la muestra, especificaremos esta clase como clase dispatch y añadiremos %All como el rol de aplicación para omitir la autenticación en el momento del acceso.

Management Portal > System Administration > Security > Applications > Web Application Path > Haz clic en el botón "Create new web application".

En el campo Name, especifica /start; en el campo Namespace, especifica el namespace desde el que se importó la muestra; en el campo Dispatch Class, especifica Start.REST; en el campo Allowed Authentication Method, selecciona "Unauthenticated", y guarda el archivo.

Después de guardar, añade %All al rol de aplicación en la pestaña "Application Roles".

imagen

imagen


Tratar de enviar datos

En cuanto tengas todo configurado, intenta utilizar un business service para enviar información a través de REST y hazlo funcionar.

http://localhost:52773/start/weather/Takoyaki/Osaka

El ejemplo anterior es una URL donde se supone que alguien compró "Takoyaki" en la ciudad de Osaka.

Después de la ejecución, en la pantalla aparece esto:

imagen

Comprueba los mensajes que se han enviado a la Producción.

En Management Portal > Interoperability > Configuration > Production, haz clic en el servicio que aparece a continuación:

Seleccione la pestaña "Messages " que aparece en la parte derecha de la pantalla y haz clic en cualquier número que se encuentre debajo de la columna "Header". Si no lo encuentras, vuelve a cargar tu navegador.

imagen

A través de la página de Visual Trace, se puede ver la información de messages enviados y recibidos entre los componentes. Puedes ver que la información meteorológica se recupera de la API web y se envía de nuevo en el marco azul claro.

De esta manera, se puede utilizar el seguimiento para ver qué datos se enviaron y recibieron en ese momento y en qué orden.

En este artículo, confirmamos que en la Producción se definieron los componentes necesarios y sus configuraciones para la integración del sistema, basándose en las configuraciones del código de muestra.

Además, confirmamos que podemos consultar los mensajes que circulan dentro de la Producción en orden cronológico, utilizando la página Visual Trace.

En los siguientes artículos, analizaremos el concepto que hay detrás de la creación del "mensaje" que se muestra en este recorrido y cómo se define realmente.

0
1 422
Artículo Nigel Salm · feb 4, 2022 3m read

Me permito adjuntar un documento que describe un producto que he desarrollado llamado NiPaRobotica Pharmacy. Se trata de una interfaz que desarrollé, que acepta solicitudes para dispensar a farmacias y convierte las líneas de pedido en diálogos de dispensación que se envían a los robots de las farmacias. Implementé la interfaz en 3 farmacias de hospitales, dos de las cuales tenían 6 robots que se organizaron de tal manera que las rampas de dispensación canalizaban los medicamentos hasta los mostradores de los farmacéuticos que atendían en las ventanillas a 1 200 pacientes al día. Los robots disminuyeron el tiempo promedio de espera de 2 a 1 hora.

Después, implementé la interfaz en 6 sitios construidos específicamente en lugares cercanos a las viviendas de los pacientes con enfermedades crónicas como tuberculosis, VIH, diabetes, epilepsia, hipertensión y asma. El propósito de este proyecto fue "Llevar los medicamentos al paciente". Estos sitios cuentan con 6 Unidades de Dispensación Farmacéutica (PDU) similares a los cajeros automáticos, que disponen de una interfaz que permite al paciente comunicarse con un centro de asistencia telefónica farmacéutica. En el interior de cada PDU hay un gran robot que contiene varios miles de medicamentos. Mi aplicación envía una instrucción de dispensación al robot, que dispensa el artículo en una banda transportadora que lleva el medicamento hasta situarlo debajo de una impresora. A la impresora llega el contenido de una etiqueta farmacéutica con el nombre del paciente, las instrucciones de administración y otras notas. La impresora coloca y pega la etiqueta al envase del medicamento. El artículo se desplaza un poco más y una esponja presiona la etiqueta para fijarla con mayor firmeza al envase. La banda transportadora pasa el artículo a un contenedor de la PDU y, una vez que se suministran todos los artículos, el paciente puede abrir una ventanilla de la PDU y recoger los artículos. Lo más importante de este proyecto es que eliminó la necesidad de que los pacientes tengan que faltar al trabajo, recorrer largas distancias hasta la clínica donde se hace el seguimiento de su estado de salud, recoger sus medicamentos y volver a casa. Ubicar estos sitios en los vecindarios donde viven los pacientes permite que puedan acudir a cualquiera de estos sitios y recoger sus medicamentos en el camino hacia o de vuelta del trabajo. 

Desde el final de la época victoriana se han producido muy pocos cambios en el mundo de las farmacias. Los ingredientes ahora son más especializados y, en muchos casos, permiten salvar vidas. La penicilina, las vacunas, los analgésicos, las terapias contra el cáncer y las inmunoterapias han modificado nuestra capacidad de tratar enfermedades que históricamente habrían sido letales para los pacientes. Sin embargo, el proceso de dispensación de esos medicamentos ha permanecido estancado en las profundidades de las farmacias de los hospitales o de las farmacias de barrio que venden más cachivaches que medicamentos. La aplicación puede hacer mucho más que transferir las solicitudes de dispensación desde la aplicación farmacéutica a los robots, y estas funciones se detallan en el documento. La aplicación ha sido modificada para admitir los mensajes FHIR relacionados con el inventario, las solicitudes y respuestas sobre medicamentos y los certificados de los mismos. El documento viene en formato PDF.

0
0 154
Artículo Ariel Arias · nov 23, 2021 6m read

Bajo el escenario que ya tenemos una API REST, funcionando, y queremos incorporarla a una producción para contar con trazabilidad y todas las ventajas que ofrece IRIS para interoperar, dejo este artículo para cambiar una API existente que responde un JSON, para responder el mismo JSON pero dejando sus trazas en una producción de la misma instancia.

Lo primero, ya contamos con una aplicación creada, llamada /restapi y que tiene como DispatchClass: Testing.REST.ApiDisp (o la clase que tenemos en nuestra instancia).

Este ejemplo, responderá un JSON a la petición: /restapi/test

La clase:

Class Testing.REST.ApiDisp Extends %CSP.REST
{

Parameter HandleCorsRequest = 1;

XData UrlMap [ XMLNamespace = "http://www.widgetsdirect.com/urlmap" ]
{
<Routes>
   <Route Url="/test" Method="GET" Call="TestAPI" Cors="false" />
</Routes>
}

ClassMethod TestAPI() As %Status
{
   Set %response.ContentType="application/json"
	
   SET retObj = {}
   SET retMessage = "API TEST"
	
   SET retEjemplo = "Puede incluir mensajes predeterminados"
   SET retObj.Message = retMessage
   SET retObj.Ejemplo = retEjemplo
   Set retObj.remoteip = %request.CgiEnvs("REMOTE_ADDR")
   Set retObj.cluster1 = %request.CgiEnvs("GATEWAY_INTERFACE")
   Set retObj.PeerAddr = $SYSTEM.TCPDevice.PeerAddr()
   Set retObj.LocalAddr = $SYSTEM.TCPDevice.LocalAddr()

   Set person = ##class(Testing.REST.Model.Persons).%OpenId(1)

   Set persona = {}
   Set persona.nombre = person.Name
   Set persona.titulo = person.Title

   Set retObj.datos = persona

	
   WRITE retObj.%ToJSON()
   QUIT $$$OK
}
}

Es una prueba sencilla en la que además de un mensaje, retrna un objeto persona (usamos el ID 1 sólo como ejemplo).

A la petición GET http://localhost:10012/restapi/test veremos un JSON así en espuesta: ` { "Message": "API TEST", "Ejemplo": "Puede incluir mensajes predeterminados", "remoteip": "172.26.0.1", "cluster1": "CGI/1.1", "cgienvsize": "", "servername": "localhost", "PeerAddr": "127.0.0.1", "LocalAddr": "127.0.0.1", "datos": { "nombre": "Campos,Ashley D.", "titulo": "Assistant Sales Rep." } }

`

Vamos a modificar la clase para extender además de %CSP.REST la clase Ens.BusinessService.

Al extender esta clase, podemos agregar en una producción nuestra clase REST (Testing.REST.ApiDisp). Al agregarla, podemos mantener el nombre de la misma clase para instanciar el BS o cambiarle el nombre para hacelo más fácil de identificar. En este caso vamos a usar el nombre REST.BS:

image

Luego, podemos agregar una línea para crear un BS. La línea que necesitamos:

`Set tSC = ##class(Ens.Director).CreateBusinessService("REST.BS", .Service)`

Vamos a crear un nuevo métod para no perder el que teníamos previamente como referencia solamente. Creamos un método llamado TestAPIBS:

`
ClassMethod TestAPIBS(idperson As %Integer) As %Status
{
    Set retObj = {}
    Set retMessage = "API TEST"
    Set retObj.Message = retMessage

    #Dim testreq As Testing.REST.Messages.TestReq
    #Dim testresp As Testing.REST.Messages.TestResp

    Set testresp = ##class(Testing.REST.Messages.TestResp).%New()
    Set testreq = ##class(Testing.REST.Messages.TestReq).%New()
    
    Set tSC = ##class(Ens.Director).CreateBusinessService("REST.BS", .Service)

    Set testreq.Codigo = idperson

    Set tSC = Service.ProcessInput(testreq,.testresp)
	Quit:$SYSTEM.Status.IsError(tSC) 
	Set %response.ContentType="application/json"

    If (testresp.Status = "OK") {
        Set persona = {}
        Set persona.nombre = testresp.Nombre
        Set persona.titulo = testresp.Titulo
        Set persona.provincia = testresp.Estado
        Set persona.compania = testresp.Company

        Set retObj.datos = persona
    }Else{
        Set retObj.estado = testresp.Status
        Set retObj.error = testresp.ErrorDesc
    }
    
	
	Write retObj.%ToJSON()
	Quit $$$OK
}
`

Para usar una producción, normalmente se requiere un BP y BO. Para este ejemplo, agregamos una clase tipo Ens.Request y otra tipo Ens.Response para utilizarlas dentro de la producción:

Request:

`
Class Testing.REST.Messages.TestReq Extends Ens.Request
{

Property Codigo As %Integer [ InitialExpression = 1 ];

}`

Response:

`Class Testing.REST.Messages.TestResp Extends Ens.Response
{

Property Codigo As %String(MAXLEN = "");

Property Nombre As %String(MAXLEN = "");

Property Titulo As %String(MAXLEN = "");

Property Estado As %String(MAXLEN = "");

Property Company As %String(MAXLEN = "");

Property Status As %String;

Property ErrorDesc As %String;

}`

A modo de ejemplo, usamos una clase Persona:

`Class Testing.REST.Model.Persons Extends (%Persistent, %Populate, %JSON.Adaptor)
{

Property Name As %String(MAXLEN = "");

Property Company As %String(MAXLEN = "");

Property Title As %String(MAXLEN = "");

Property State As %String(MAXLEN = "");
}`

Trasladamos la lógica de abrir un objeto "Persona" basado en un ID a un BO:

`Class Testing.REST.BO.GetPersonData Extends Ens.BusinessOperation
{

Parameter ADAPTER = "EnsLib.SQL.OutboundAdapter";

Property Adapter As EnsLib.SQL.OutboundAdapter;

Parameter INVOCATION = "Queue";

Method TestConnection(pRequest As Testing.REST.Messages.TestReq, Output pResponse As Testing.REST.Messages.TestResp) As %Status
{
	set tSC = $System.Status.OK()
	try
	{
		set pResponse=##class(Testing.REST.Messages.TestResp).%New()

        Set person = ##class(Testing.REST.Model.Persons).%OpenId(pRequest.Codigo)

        If $ISOBJECT(person) {
            Set pResponse.Status = "OK"
            Set pResponse.Codigo = person.%Id()
            Set pResponse.Nombre = person.Name
            Set pResponse.Titulo = person.Title
            Set pResponse.Company = person.Company
            Set pResponse.Estado = person.State
        }
        else {
            Set pResponse.Status = "NOK"
            Set pResponse.ErrorDesc = "No se encuentra persona " _ pRequest.Codigo
        }        

	}
	catch (tException)
	{
		set tSC = tException.AsStatus()	
	 	set pResponse.ErrorDesc = $System.Status.GetErrorText(tSC)
	}
	quit tSC
}

XData MessageMap
{
<MapItems>
	<MapItem MessageType="Testing.REST.Messages.TestReq"> 
		<Method>TestConnection</Method>
	</MapItem>

</MapItems>
}

}
`

Un BP que conectará nuestro BS con el BO:

image

Ahora modificamos la clase Dispatch para manejar las llamadas al GET que use el método creado (TestAPIBS):

`<Route Url="/testbs/:id" Method="GET" Call="TestAPIBS" Cors="false" />`

Agregamos el parámetro "id" sólo para hacer interactivo el GET y poder obtener la información de la persona basados precisamente en este Id.

Para el GET http://localhost:10012/restapi/testbs/10

Podemos ver una respuesta como esta:

image

Espero esto ayude a quienes inician con creación de APIs con IRIS, y puedan agregar funcionalides.

0
0 465
Artículo Pablo Frigolett · nov 23, 2021 2m read

En esta minera - Operación de Candelaria para Lundin Mining - como en muchas otras, los sistemas de registro de eventos de la operación están separados de forma física y lógica. Buscando encontrar trazar la ubicación de material en el yacimiento y los diámetros de material relevante una vez molido lo extraído, sus ejecutivos usan herramientas no especializadas, planillas de cálculo en este caso, para bucear en los datos. El escenario se complica cuando en los datos no hay información de cruce del vehículo que transporta el material desde su ubicación en el yacimiento con la información del

0
0 118
Artículo Ricardo Paiva · nov 12, 2021 21m read

Este curso de formación está dirigido a todas las personas interesadas en conocer el framework de Interoperabilidad de IRIS. Utilizaremos Docker y VSCode.

GitHub: https://github.com/grongierisc/formation-template

1. Formación en Ensemble/Interoperabilidad

El objetivo de esta formación es aprender el framework de interoperabilidad de InterSystems, y en particular el uso de:

  • Producciones
  • Mensajes
  • Business Operations
  • Adaptadores
  • Business Processes
  • Business Services
  • Operaciones y servicios REST

ÍNDICE:

2. Framework

Este es el framework de IRIS.

FrameworkFull

Los componentes que están en el interior de IRIS representan una producción. Los adaptadores de entrada y de salida nos permiten utilizar diferentes tipos de formato como entrada y salida para nuestra base de datos. Las aplicaciones compuestas nos darán acceso a la producción a través de aplicaciones externas como los servicios REST.

Las flechas que están entre todos estos componentes son mensajes. Estos pueden ser solicitudes o respuestas.

3. Adaptación del framework

En nuestro caso, leeremos las líneas desde un archivo CSV y las guardaremos en la base de datos IRIS.

Entonces, añadiremos una operación que nos permitirá guardar los objetos en una base de datos externa, utilizando JDBC. Esta base de datos se ubicará en un contenedor de Docker, utilizando postgre.

Por último, veremos cómo utilizar aplicaciones compuestas para insertar nuevos objetos en nuestra base de datos, o para consultar esta base de datos (en nuestro caso, a través de un servicio REST).

El framework adaptado a nuestro propósito nos ofrece:

FrameworkAdapted

4. Requisitos previos

Para esta formación, necesitarás:

5. Configuración

5.1. Contenedores de Docker

Para tener acceso a las imágenes de InterSystems, hay que ir a esta URL: http://container.intersystems.com. Después de iniciar sesión con nuestras credenciales de InterSystems, obtendremos nuestra contraseña para conectarnos al registro. En el addon de Docker para VSCode, que se encuentra en la pestaña de imágenes, hacemos clic en Conectar Registro, introducimos la misma URL que antes (http://container.intersystems.com) como registro genérico y se nos pedirá que demos nuestras credenciales. El inicio de sesión es el habitual pero la contraseña es la que obtuvimos del sitio web.

A partir de ahí, deberíamos ser capaces de crear y componer nuestros contenedores (con los archivos docker-compose.yml y Dockerfile que se nos dieron).

5.2. Portal de Administración

Abriremos un Portal de Administración. Esto nos dará acceso a una página web desde la que podremos crear nuestra producción. El portal debe estar ubicado en la URL: http://localhost:52775/csp/sys/UtilHome.csp?$NAMESPACE=IRISAPP. Necesitarás las siguientes credenciales:

LOGIN: SuperUser

PASSWORD: SYS

5.3. Guardar el progreso

Una parte de las cosas que haremos se guardarán localmente, pero todos los procesos y producciones se guardan en el contenedor de Docker. Con el fin de conservar todo nuestro progreso, necesitamos exportar todas las clases que se crean desde el Portal de Administración con ayuda del addonObjectScript de InterSystems:

ExportProgress

Tendremos que guardar de esta forma nuestra producción, mapa de registros, business processes y transformaciones de datos. Después de hacerlo, cuando cerremos nuestro contenedor Docker y hagamos la compilación nuevamente, aún tendremos todo nuestro progreso guardado de forma local (por supuesto, hay que hacer esto después de cada cambio que hagamos a través del portal). Para que sea accesible a IRIS de nuevo, tenemos que compilar los archivos exportados (cuando los guardemos, los addons de InterSystems se encargarán del resto).

6. Producciones

Ahora podemos crear nuestra primera producción. Para hacerlo, nos moveremos por los menús [Interoperability] y [Configure]:

ProductionMenu

Ahora hacemos clic en [New], seleccionamos el paquete [Formation] y elegimos un nombre para nuestra producción:

ProductionCreation

Inmediatamente después de crear nuestra producción, hay que hacer clic en la opción [Production Settings], situada encima de la sección [Operations]. En el menú de la barra lateral derecha, tendremos que activar la opción [Testing Enabled] en la sección [Development and Debugging] de la pestaña [Settings] (no te olvides de hacer clic en [Apply]).

ProductionTesting

En esta primera producción añadiremos ahora las business operations.

7. Operaciones

Una business operation (BO) es un tipo de operación específica que nos permitirá enviar solicitudes desde IRIS hacia una aplicación/sistema externo. También se puede utilizar para guardar lo que queramos directamente en IRIS.

Crearemos esas operaciones de forma local, es decir, en el archivo Formation/BO/. Cuando guardemos los archivos los compilaremos en IRIS.

En nuestra primera operación, guardaremos el contenido de un mensaje en la base de datos local.

Para hacerlo, primero necesitamos tener una forma de almacenar este mensaje.

7.1. Creación de nuestra clase de almacenamiento

En IRIS, las clases de almacenamiento extienden el tipo %Persistent. Se guardarán en la base de datos interna.

En nuestro archivo Formation/Table/Formation.cls tenemos lo siguiente:

Class Formation.Table.Formation Extends %Persistent
{

Property Name As %String;

Property Salle As %String;

}

Ten en cuenta que al guardar, de forma automática se añaden líneas adicionales al archivo. Son obligatorias y las añaden los addons de InterSystems.

7.2. Creación de nuestra clase para mensajes

Este mensaje contendrá un objeto Formation, situado en el archivo Formation/Obj/Formation.cls:

Class Formation.Obj.Formation Extends (%SerialObject, %XML.Adaptor)
{

Property Nom As %String;

Property Salle As %String;

}

La clase Message utilizará el objeto Formation, src/Formation/Msg/FormationInsertRequest.cls:

Class Formation.Msg.FormationInsertRequest Extends Ens.Request
{

Property Formation As Formation.Obj.Formation;

}

7.3. Creación de nuestra operación

Ahora que ya tenemos todos los elementos que necesitamos, podemos crear nuestra operación, en el archivo Formation/BO/LocalBDD.cls:

Class Formation.BO.LocalBDD Extends Ens.BusinessOperation
{

Parameter INVOCATION = "Queue";

Method InsertLocalBDD(pRequest As Formation.Msg.FormationInsertRequest, Output pResponse As Ens.StringResponse) As %Status
{
    set tStatus = $$$OK

    try{
        set pResponse = ##class(Ens.Response).%New()
        set tFormation = ##class(Formation.Table.Formation).%New()
        set tFormation.Name = pRequest.Formation.Nom
        set tFormation.Salle = pRequest.Formation.Salle
        $$$ThrowOnError(tFormation.%Save())
    }
    catch exp
    {
        Set tStatus = exp.AsStatus()
    }

    Quit tStatus
}

XData MessageMap
{
<MapItems>
    <MapItem MessageType="Formation.Msg.FormationInsertRequest"> 
        <Method>InsertLocalBDD</Method>
    </MapItem>
</MapItems>
}

}

El MessageMap nos proporciona el método que debemos lanzar, dependiendo del tipo de solicitud (el mensaje que se envió a la operación).

Como podemos ver, si la operación recibió un mensaje del tipo Formation.Msg.FormationInsertRequest, se llamará al método InsertLocalBDD. Este método guardará el mensaje en la base de datos local de IRIS.

7.4. Cómo añadir la operación a la producción

Ahora necesitamos añadir esta operación a la producción. Para hacerlo, utilizaremos el Portal de Administración. Al hacer clic en el signo [+] junto a [Operations], tendremos acceso al [Business Operation Wizard]. Allí, elegiremos la clase de la operación que acabamos de crear en el menú desplegable.

OperationCreation

7.5. Pruebas

Si hacemos doble clic en la operación podremos activarla. Después de hacerlo, al seleccionar la operación e ir a las pestañas [Actions] que están en el menú de la barra lateral derecha, deberíamos poder probar la operación (si no ves la sección para crear la producción, puede que tengas que iniciar la producción si se encuentra detenida).

De este modo, enviaremos a la operación un mensaje del tipo que declaramos anteriormente. Si todo sale bien, los resultados deberían ser similares a los que se muestran a continuación:

OperationTest

Mostrar el registro visual nos permitirá ver lo que ocurrió entre los procesos, servicios y operaciones. Aquí, podemos ver el mensaje que se envía a la operación por parte del proceso, y a la operación cuando envía de vuelta una respuesta (que en este caso solo es una cadena vacía).

8. Business Processes

Los business processes (BP) son la lógica empresarial de nuestra producción. Se utilizan para procesar las solicitudes o retransmitirlas a otros componentes de la producción.

Los business processes se crean dentro del Portal de Administración:

BPMenu

8.1. Business processes simples

8.1.1. Creación del proceso

Ahora estamos en el Diseñador de Business Process. Vamos a crear un business process simple que llamará nuestra operación:

BPAddingCall

8.1.2. Modificación del contexto de un business process

Todos los business processes tiene un contexto. Se compone de una clase para la solicitud, la clase de la entrada, una clase para la respuesta y la clase de la salida. Los business processes solo tienen una entrada y una salida. También es posible agregar propiedades.

Como nuestro business process solo se utilizará para llamar a nuestra business operation, podemos poner la clase del mensaje que hemos creado como clase para la solicitud (no necesitamos una salida ya que solo queremos insertarlo en la base de datos).

BPContext

Ahora, elegiremos el objetivo de la función Call: nuestra business operation. Esa operación, al ser llamada tiene una propiedad callrequest. Necesitamos vincular esa propiedad callrequest con la solicitud del business process (ambos pertenecen a la clase Formation.Msg.FormationInsertRequest) y para ello, hacemos clic en la función Call y utilizaremos el creador de peticiones:

BPBindRequests

Ahora podemos guardar este business process (en el paquete 'Formation.BP' y, por ejemplo, con el nombre 'InsertLocalBDD' o 'Main'). Al igual que las operaciones, pueden crearse instancias de los procesos y se pueden probar mediante la Configuración de la producción, aunque para esto necesitan compilarse previamente (en la pantalla del Business Process Designer).

Por ahora, nuestro proceso solo pasa el mensaje a nuestra operación. Vamos a aumentar la complejidad para que el business process tome como entrada una línea de un archivo CSV.

8.2. Cómo hacer que el business process lea líneas CSV

8.2.1. Creación de un mapa de registro

Para leer un archivo y poner su contenido en otro archivo, necesitamos un Mapa de Registros (RM). En el menú [Interoperability > Build] del Portal de Administración hay un servicio para mapear los registros, especializado en archivos CSV:

RMMenu

Crearemos el servicio para elaborar mapas de esta manera:

RMCreation

Ahora deberías tener el siguiente Mapa de Registros:

RMDetails

Ahora que el mapa está creado, debemos generarlo (con el botón Generate). También debemos efectuar una Transformación de datos desde el formato del Mapa de registros y un mensaje de inserción.

8.2.2. Creación de una transformación de datos

Encontraremos el Generador para la Transformación de datos (DT) en el menú [Interoperability > Builder]. A continuación, crearemos nuestra DT de esta forma (si no encuentras la clase Formation.RM.Csv.Record, tal vez no se generó el Mapa de Registros):

DTCreation

Ahora, podemos mapear los diferentes campos juntos:

DTMap

8.2.3. Añadir la transformación de datos al business process

Lo primero que debemos modificar es la clase de la solicitud del business process, ya que necesitamos tener una entrada en el Mapa de Registros que creamos.

BP2ChangeContext

Entonces, podemos añadir nuestra transformación (el nombre del proceso no cambia nada, a partir de aquí elegimos llamarlo Main):

BP2AddingTransform

La actividad de transformación tomará la solicitud del business process (un registro del archivo CSV, gracias a nuestro servicio para mapear los registros) y la transformará en un mensaje FormationInsertRequest. Si deseamos almacenar ese mensaje para enviarlo al business operation, necesitamos añadir una propiedad al contexto del business process.

BP2MsgContext

Ahora podemos configurar nuestra función de transformación para que tome su entrada como entrada del business process y guarde su salida en la propiedad recién creada. El origen y el objetivo de la transformación RmToMsg son request y context.Msg, respectivamente:

BP2RmToMsg

Tenemos que hacer lo mismo para Call BO. Su entrada, o callrequest, es el valor almacenado en context.msg:

BP2CallBO

Al final, el flujo en el business process puede representarse de esta manera:

BP2Diagram

8.2.4. Configuración de la producción

Con el signo [+], podemos añadir nuestro nuevo proceso a la producción (si aún no lo hemos hecho). También necesitamos un servicio genérico para utilizar el Mapa de Registros, para ello utilizamos EnsLib.RecordMap.Service.FileService (lo añadimos con el botón [+] que está junto a los servicios). A continuación, parametrizamos este servicio:

ServiceParam

Ahora deberíamos poder probar nuestro business process.

8.2.5. Pruebas

Probamos toda la producción de esta manera:

TestProductionCSV

En el menú System Explorer > SQL, puedes ejecutar el comando

SELECT 
ID, Name, Salle
FROM Formation_Table.Formation

para ver los objetos que acabamos de guardar.

9. Obtener acceso a una base de datos externa usando JDBC

En esta sección, crearemos una operación para guardar nuestros objetos en una base de datos externa. Utilizaremos la API de JDBC, así como el otro contenedor Docker que configuramos, con postgre en él.

9.1. Creación de nuestra nueva operación

Nuestra nueva operación, en el archivo Formation/BO/RemoteBDD.cls es así:

Include EnsSQLTypes

Class Formation.BO.RemoteBDD Extends Ens.BusinessOperation
{

Parameter ADAPTER = "EnsLib.SQL.OutboundAdapter";

Property Adapter As EnsLib.SQL.OutboundAdapter;

Parameter INVOCATION = "Queue";

Method InsertRemoteBDD(pRequest As Formation.Msg.FormationInsertRequest, Output pResponse As Ens.StringResponse) As %Status
{
    set tStatus = $$$OK

    try{
        set pResponse = ##class(Ens.Response).%New()
        set ^inc = $I(^inc)
        set tInsertSql = "INSERT INTO public.formation (id, nom, salle) VALUES(?, ?, ?)"
        $$$ThrowOnError(..Adapter.ExecuteUpdate(.nrows,tInsertSql,^inc,pRequest.Formation.Nom, pRequest.Formation.Salle ))
    }
    catch exp
    {
        Set tStatus = exp.AsStatus()
    }

    Quit tStatus
}

XData MessageMap
{
<MapItems>
    <MapItem MessageType="Formation.Msg.FormationInsertRequest"> 
        <Method>InsertRemoteBDD</Method>
    </MapItem>
</MapItems>
}

}

Esta operación es similar a la primera que creamos. Cuando reciba un mensaje del tipo Formation.Msg.FormationInsertRequest, utilizará un adaptador para ejecutar solicitudes SQL. Esas solicitudes se enviarán a nuestra base de datos de postgre.

9.2. Configuración de la producción

Ahora, desde el Portal de Administración, crearemos una instancia de esa operación (añadiéndola con el signo [+] en la producción).

También necesitaremos añadir el JavaGateway para el controlador JDBC en los servicios. El nombre completo de este servicio es EnsLib.JavaGateway.Service.

JDBCProduction

Ahora necesitamos configurar nuestra operación. Como hemos configurado un contenedor postgre, y conectado su puerto 5432, los valores que necesitamos en los siguientes parámetros son:

DSN: jdbc:postgresql://db:5432/DemoData

Controlador de JDBC: org.postgresql.Driver

JDBC Classpath: /tmp/iris/postgresql-42.2.14.jar

JDBCParam

Finalmente, necesitamos configurar las credenciales para tener acceso a la base de datos remota. Para ello, necesitamos abrir el Visualizador de credenciales:

JDBCCredentialMenu

Tanto el nombre de usuario como la contraseña son DemoData, como lo configuramos en el archivo docker-compose.yml.

JDBCCredentialCreation

De vuelta a la producción, podemos añadir "Postgre" en el campo [Credential] en la configuración de nuestra operación (debería estar en el menú desplegable). Antes de que podamos probarlo, debemos añadir el JGService a la operación. En la pestaña [Settings], en [Additional Settings]:

JDBCService

9.3. Pruebas

Cuando se están haciendo pruebas el registro visual debe mostrar que tuvimos éxito:

JDBCTest

Conectamos correctamente una base de datos externa.

9.4. Ejercicio

Como ejercicio, podría ser interesante modificar BO.LocalBDD para que devuelva un booleano, que le dirá al business process que llame a BO.RemoteBDD dependiendo del valor de ese booleano.

Sugerencia: Esto se puede hacer cambiando el tipo de respuesta que devuelve LocalBDD, añadiendo una nueva propiedad al contexto y utilizando la actividad if en nuestro business process.

9.5. Solución

Primero, necesitamos tener una respuesta de nuestra operación LocalBDD. Vamos a crear un nuevo mensaje, en Formation/Msg/FormationInsertResponse.cls:

Class Formation.Msg.FormationInsertResponse Extends Ens.Response
{

Property Double As %Boolean;

}

Después, cambiamos la respuesta de LocalBDD por esa respuesta y establecemos el valor de su booleano de forma aleatoria (o no):

Method InsertLocalBDD(pRequest As Formation.Msg.FormationInsertRequest, Output pResponse As Formation.Msg.FormationInsertResponse) As %Status
{
    set tStatus = $$$OK

    try{
        set pResponse = ##class(Formation.Msg.FormationInsertResponse).%New()
        if $RANDOM(10) < 5 {
            set pResponse.Double = 1
        } 
        else {
            set pResponse.Double = 0
        }
...

Ahora crearemos un nuevo proceso (copiado del que hicimos), donde añadiremos una nueva propiedad de contexto, de tipo %Boolean:

ExerciseContext

Esta propiedad se completará con el valor del callresponse.Double de nuestra llamada de operación (necesitaremos establecer [Response Message Class] en nuestra nueva clase de mensaje):

ExerciseBinding

A continuación, añadimos una actividad if, con la propiedad context.Double como condición:

ExerciseIf

MUY IMPORTANTE: necesitamos desmarcar Asynchronous en la configuración de nuestra LocallBDD Call, o la actividad if se activará antes de que reciba la respuesta booleana.

Finalmente configuramos nuestra actividad de llamada como un objetivo RemoteBDD BO:

ExerciseRemoteCall

Para completar la actividad if, necesitamos arrastrar otro conector desde la salida del if al triángulo join que se encuentra debajo. Como no haremos nada si el valor booleano es falso, dejaremos este conector vacío.

Después de compilar y crear instancias, deberíamos poder probar nuestro nuevo proceso. Para ello, necesitamos cambiar Target Config Name de nuestro servicio de archivos.

En el seguimiento, deberíamos tener aproximadamente la mitad de los objetos leídos en el csv guardados también en la base de datos remota.

10. Servicio REST

En esta parte, crearemos y utilizaremos un Servicio REST.

10.1. Creación del servicio

Para crear un servicio REST, necesitamos una clase que extienda %CSP.REST, en Formation/REST/Dispatch.cls tenemos:

Class Formation.REST.Dispatch Extends %CSP.REST
{

/// Ignore any writes done directly by the REST method.
Parameter IgnoreWrites = 0;

/// By default convert the input stream to Unicode
Parameter CONVERTINPUTSTREAM = 1;

/// The default response charset is utf-8
Parameter CHARSET = "utf-8";

Parameter HandleCorsRequest = 1;

XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ]
{
<Routes>
  <!-- Get this spec -->
  <Route Url="/import" Method="post" Call="import" />
</Routes>
}

/// Get this spec
ClassMethod import() As %Status
{
  set tSc = $$$OK

  Try {

      set tBsName = "Formation.BS.RestInput"
      set tMsg = ##class(Formation.Msg.FormationInsertRequest).%New()

      set body = $zcvt(%request.Content.Read(),"I","UTF8")
      set dyna = {}.%FromJSON(body)

      set tFormation = ##class(Formation.Obj.Formation).%New()
      set tFormation.Nom = dyna.nom
      set tFormation.Salle = dyna.salle

      set tMsg.Formation = tFormation

      $$$ThrowOnError(##class(Ens.Director).CreateBusinessService(tBsName,.tService))

      $$$ThrowOnError(tService.ProcessInput(tMsg,.output))

  } Catch ex {
      set tSc = ex.AsStatus()
  }

  Quit tSc
}

}

Esta clase contiene una ruta para importar un objeto, vinculado al verbo POST:

<Routes>
  <!-- Get this spec -->
  <Route Url="/import" Method="post" Call="import" />
</Routes>

El método de importación creará un mensaje que se enviará a un business service.

10.2. Añadir nuestro Business Service (BS)

Vamos a crear una clase genérica que dirigirá todas sus solicitudes hacia TargetConfigNames. Este objetivo se configurará cuando creemos una instancia de este servicio. En el archivo Formation/BS/RestInput.cls tenemos:

Class Formation.BS.RestInput Extends Ens.BusinessService
{

Property TargetConfigNames As %String(MAXLEN = 1000) [ InitialExpression = "BuisnessProcess" ];

Parameter SETTINGS = "TargetConfigNames:Basic:selector?multiSelect=1&context={Ens.ContextSearch/ProductionItems?targets=1&productionName=@productionId}";

Method OnProcessInput(pDocIn As %RegisteredObject, Output pDocOut As %RegisteredObject) As %Status
{
    set status = $$$OK

    try {

        for iTarget=1:1:$L(..TargetConfigNames, ",") {
            set tOneTarget=$ZStrip($P(..TargetConfigNames,",",iTarget),"<>W")  Continue:""=tOneTarget
            $$$ThrowOnError(..SendRequestSync(tOneTarget,pDocIn,.pDocOut))
        }
    } catch ex {
        set status = ex.AsStatus()
    }

    Quit status
}

}

Volviendo a la configuración de la producción, añadimos el servicio de la manera habitual. En [Target Config Names], ponemos nuestro BO LocalBDD:

RESTServiceSetup

Para utilizar este servicio, necesitamos publicarlo. Para ello, usamos el menú [Edit Web Application]:

RESTServicePublish

10.3. Pruebas

Por último, podemos probar nuestro servicio con cualquier tipo de cliente REST:

RESTTest

Conclusión

A través de esta formación, hemos creado una producción que es capaz de leer líneas desde un archivo csv y guardar los datos leídos tanto en la base de datos de IRIS como en una base de datos externa, utilizando JDBC. También añadimos un servicio REST para utilizar el verbo POST para guardar nuevos objetos.

Hemos descubierto los principales elementos del framework de interoperabilidad de InterSystems.

Lo hemos hecho utilizando Docker, VSCode y el Portal de Administración de InterSystems IRIS.

0
0 319
Anuncio Esther Sanchez · oct 19, 2021

¡Hola desarrolladores!

Os traemos un nuevo vídeo, ya disponible en el Canal de YouTube de la Comunidad de Desarrolladores en inglés.

Es la grabación de una de las ponencias realizadas en la Convención Anual de InterSystems del año pasado, así que el idioma del vídeo es el inglés. Pero recordad que podéis activar los subtítulos en inglés, por si os resulta más fácil entender el vídeo leyendo el texto.

En el vídeo, @Patrick Jamieson nos enseña cómo buscar recursos FHIR con una variedad de opciones de consulta:

⏯ Búsqueda de recursos FHIR (Virtual Summit 2020)

0
0 143
Anuncio Esther Sanchez · oct 8, 2021

¡Hola desarrolladores!

Os traemos el cuarto tutorial grabado por @David Reche, y disponible en el canal de YouTube de la Comunidad de Desarrolladores en español: Cómo habilitar la interoperabilidad en InterSystems IRIS.

En este tutorial de tres minutos, David nos mostrará cómo habilitar la interoperabilidad en InterSystems IRIS Community Edition.

Tutorial 4: Cómo habilitar la interoperabiliad en InterSystems IRIS

0
0 117
Artículo Muhammad Waseem · oct 5, 2021 2m read

Oí hablar del Banco de Mensajes (Message Bank) cuando comenzamos a rediseñar una producción de Health Connect para que se ejecutara en contenedores en la nube. Como habría varios contenedores de IRIS, se nos indicó que utilizáramos el Banco de Mensajes como un sitio único para ver los mensajes y registros de todos los contenedores.

¿Cómo funciona Message Bank?

Añadí la operación del Banco de Mensajes a nuestra Producción de Interoperabilidad. Envía automáticamente mensajes y registros de eventos al Banco de Mensajes.

0
0 118
Artículo Ricardo Paiva · sep 9, 2021 4m read

Este artículo es una continuación de esta publicación.

El objetivo de este artículo es explicar cómo funciona el menú de interoperabilidad para la integración del sistema.

imagen

La parte izquierda de la figura representa la ventana para aceptar información enviada desde sistemas externos.

Hay varias maneras de recibir información, como monitorizar el directorio especificado a intervalos regulares para leer archivos, consultar periódicamente la base de datos, esperar a que se introduzcan datos, o llamar directamente y que se pasen desde aplicaciones en otros sistemas.

En el mecanismo de integración del sistema creado en el menú Interoperabilidad de IRIS, la información recibida se almacena en un objeto llamado mensaje. El mensaje se envía al componente responsable de su procesamiento posterior.

Se puede crear un mensaje utilizando toda la información recibida o solo una parte de ella.

Supón que deseas enviar la información contenida en el mensaje a un sistema externo. En ese caso, es necesario que envíes el mensaje al componente responsable de solicitar a la red externa que lo procese (la parte derecha de la figura). El componente que recibe el mensaje solicitará al sistema externo que lo procese.

Además, supón que un mensaje requiere que una persona lo revise, conversión de datos o adjuntar datos. En ese caso, el mensaje se envía al componente situado en el centro del diagrama (BPM), que es el encargado de coordinar el flujo del proceso.

Los mensajes se utilizan para enviar y recibir datos entre cada componente. Cuando se envía o se recibe un mensaje, este se almacena automáticamente en la base de datos.

Como los mensajes se almacenan en la base de datos, se puede revisar la diferencia entre antes y después de la conversión de datos. Revisa el mensaje que fue la fuente de un problema durante una operación o vuelva a empezar (reenvío) desde la mitad del proceso. Verifica el estado utilizando mensajes en cada etapa de desarrollo, prueba y operación.

Una imagen sencilla de la integración del sistema se dividiría en tres componentes (business services, business processes y business operations), como se muestra en la siguiente figura.

También hay una definición llamada "producción" que almacena información sobre los componentes que se van a utilizar (por ejemplo, la información de la conexión).

imagen

La función de cada componente es la siguiente:

Business services
Responsables de recibir información de fuentes externas, crear mensajes y enviar mensajes a otros componentes.

Business processes
Esta función se activa cuando se recibe un mensaje. Es responsable de coordinar el proceso (llamando a los componentes en el orden definido, esperando respuestas, esperando los resultados de la revisión humana, etc.).

Business operations Esta función se activa cuando se recibe un mensaje. Tiene la función de solicitar al sistema externo que procese el mensaje.

Los mensajes se utilizan para enviar y recibir datos entre componentes.

Los componentes que son distintos de los business services inician el procesamiento cuando reciben un mensaje.

La pregunta es: ¿cuál es el propósito de crear y utilizar este mensaje?

Los mensajes se crean mediante la recuperación de la información que quieres transmitir al sistema externo a partir de los datos introducidos en el business service.

Dado que no todos los sistemas externos conectados a IRIS utilizan el mismo tipo de formato de datos para transmitir, y el contenido a transmitir varía, la producción puede definir libremente las clases de mensaje de acuerdo con la información.

Hay dos tipos de mensajes: solicitudes (= mensaje de solicitud) y respuesta (= mensaje de respuesta). El mensaje que desencadena la activación del componente se denomina solicitud (= mensaje de solicitud), y el mensaje al que responde el componente después de su procesamiento se denomina respuesta (= mensaje de respuesta).

Estos mensajes se diseñarán mientras se considera el proceso de transmisión.

En los siguientes artículos, utilizaremos un caso de estudio para describir la creación de producciones, mensajes y componentes.

0
0 485
Anuncio Esther Sanchez · ago 31, 2021

¡Hola Comunidad!

Os traemos un nuevo vídeo, ya disponible en el Canal de YouTube de la Comunidad de Desarrolladores en inglés.

Es la grabación de una de las ponencias realizadas en la Convención Anual de InterSystems del año pasado, así que el idioma del vídeo es el inglés. Pero recordad que podéis activar los subtítulos en inglés, por si os resulta más fácil entender el vídeo leyendo el texto.

Gestión de APIs de FHIR (Virtual Summit 2020)

0
0 91
Artículo Ricardo Paiva · jul 22, 2021 3m read

Posiblemente te hayas encontrado con esto y no supiste cómo evitarlo; o tal vez ni siquiera te diste cuenta...

Pero cuando se tienen componentes empresariales de la Producción de Interoperabilidad TCP (por ejemplo, un business service HL7), probablemente tienes (dependiendo de tu configuración de StayConnected) muchas entradas en el Registro de Eventos (Event log) de tipo Info. Cada entrada registraría una conexión o desconexión.

Por ejemplo:

0
0 156
Artículo Ricardo Paiva · jul 1, 2021 3m read

¡Hola a todos!

InterSystems IRIS tiene un menú llamado Interoperabilidad.

Ofrece mecanismos que permiten crear fácilmente integraciones de sistemas (adaptadores, mapas de registros, BPMs, conversiones de datos, etc.), para que diferentes sistemas puedan conectarse fácilmente.

En el proceso de transmisión de datos se pueden incluir diversas operaciones, por ejemplo: para conectar sistemas que normalmente no están conectados, se pueden recibir (o enviar) datos según las especificaciones del sistema de destino. Además, se puede adquirir y añadir información desde otro sistema antes de enviar los datos. La información también se puede adquirir y actualizar a partir de una base de datos (IRIS u otra).

En esta serie de artículos, comentaremos los siguientes temas, mientras vemos ejemplos de códigos para ayudarte a comprender cómo funciona y qué tipo de desarrollo se requiere cuando se integran sistemas con Interoperabilidad.

En primer lugar, os presento el caso de estudio que utilizaremos en esta serie de artículos:

Una empresa gestiona una tienda online y está cambiando el orden en que se muestra la información de los productos para que coincida con las estaciones del año.
Sin embargo, algunos artículos se venden bien independientemente de la estación del año, mientras otros se venden en momentos inesperados, lo que no coincide con la regla actual de cambiar el orden.
Por lo tanto, estudiamos la posibilidad de cambiar el orden para que coincida con la temperatura del día en lugar de con la estación del año. Fue necesario saber la temperatura de los productos comprados en ese momento.
Como se dispone de una API web externa para comprobar la información meteorológica, planeamos recopilar la información meteorológica en el momento de la compra y registrarla en la base de datos.

Es muy sencillo, pero es necesario utilizar una “API web externa” para recoger la información, y se debe combinar la información obtenida y la de compra para registrarla en la base de datos.

Las instrucciones específicas se comentarán en un artículo relacionado (no incluye la creación de un sitio web). ¡Échale un vistazo!

En cuanto a la "API web externa" que estamos utilizando en esta ocasión, estamos usando los Datos meteorológicos actuales de OpenWeather.

(Si quieres probarlo, debes registrar una cuenta y obtener un ID de API ).

Lo siguiente es el resultado de una solicitud GET de un cliente REST (lo ejecutaremos en el mecanismo que implementaremos en Interoperabilidad).

El JSON de la respuesta HTTP es el siguiente:

{
    "coord": {
        "lon": 135.5022,
        "lat": 34.6937
    },
    "weather": [
        {
            "id": 803,
            "main": "Clouds",
            "description": "broken clouds",
            "icon": "04d"
        }
    ],
    "base": "stations",
    "main": {
        "temp": 17.05,
        "feels_like": 13.33,
        "temp_min": 16,
        "temp_max": 18,
        "pressure": 1017,
        "humidity": 55
    },
    "visibility": 10000,
    "wind": {
        "speed": 4.63,
        "deg": 70
    },
    "clouds": {
        "all": 75
    },
    "dt": 1611635756,
    "sys": {
        "type": 1,
        "id": 8032,
        "country": "JP",
        "sunrise": 1611612020,
        "sunset": 1611649221
    },
    "timezone": 32400,
    "id": 1853909,
    "name": "Osaka",
    "cod": 200
}

En el siguiente artículo, comentaremos cómo funciona el menú de Interoperabilidad para la integración del sistema.

0
0 233
Anuncio Esther Sanchez · jun 24, 2021

¡Hola Comunidad!

Hemos grabado el webinar que hicimos ayer y lo hemos subido al canal de YouTube de la Comunidad de Desarrolladores en español. Si os perdisteis el webinar o lo queréis volver a ver con más detalle, ya está disponible la grabación!

Ricardo Paiva es un experto en interoperabilidad o, lo que es lo mismo, en la integración inteligente de procesos de negocio. Así que, si queréis saber cómo puede FHIR convivir e integrarse con otros protocolos... ¡no os perdáis el vídeo!

Interoperabilidad en FHIR

0
0 121
Artículo Eduardo Anglada · jun 23, 2021 6m read

Según la consultora IDC, más del 80% de la información es de tipo NoSQL, especialmente texto en documentos. Cuando los servicios o aplicaciones digitales no procesan toda esta información, la empresa pierde. Para resolver este desafío, es posible utilizar la tecnología OCR. El Reconocimiento Óptico de Caracteres (OCR) utiliza la tecnología de machine learning y/o el reconocimiento de patrones en imágenes para transformar los pixeles de las imágenes en texto. Esto es importante porque muchos documentos se escanean como imágenes, o muchos documentos contienen imágenes con texto en su interior. Por eso la tecnología OCR es un paso importante para obtener toda la información posible de un documento.

Para hacer OCR de un documento, la solución de código abierto más utilizada es Tesseract de Google, es la más popular entre la comunidad que utiliza Python y Java. Tesseract es compatible con más de 100 idiomas y puede aprender a reconocer nuevos modelos, como matrículas de automóviles, captchas y muchas cosas más. Tesseract fue creada en C++, de modo que Java lo utiliza con la ayuda de un intermediario llamado Tess4J. Este código sirve de muestra:

private String extractTextFromImage(File tempFilethrows TesseractException {
 
        ITesseract tesseract = new Tesseract();
        tesseract.setDatapath("/usr/share/tessdata/"); //directory to trained models
        tesseract.setLanguage("eng+por"); // choose your language/trained model
 
        return tesseract.doOCR(tempFile); //call tesseract function doOCR() 
                                          //passing the file to be processed with OCR technique
 
    }

Para permitir que IRIS utilice esta clase de Java y obtenga los resultados desde Java, necesitamos utilizar las soluciones PEX y Java Gateway.

En primer lugar, es necesario configurar el proxy de Java en la producción y, en segundo lugar, configurar una Business Operation o Service en PEX para comunicar IRIS y Java en una producción.

Class dc.ocr.OcrProduction Extends Ens.Production
{
 
XData ProductionDefinition
{
<Production Name="dc.ocr.OcrProduction" LogGeneralTraceEvents="false">
  <Description></Description>
  <ActorPoolSize>2</ActorPoolSize>
  <Item Name="OcrService" Category="" ClassName="dc.ocr.OcrService" PoolSize="1" Enabled="true" 
Foreground="false" Comment="" LogTraceEvents="false" Schedule=""> 
  </Item>
  <Item Name="JavaGateway" Category="" ClassName="EnsLib.JavaGateway.Service" PoolSize="1" 
Enabled="true" Foreground="false" Comment="" LogTraceEvents="false" Schedule="">
    <Setting Target="Host" Name="ClassPath">.:/usr/irissys/dev/java/lib/JDK18/*:/opt/irisapp/*
:/usr/irissys/dev/java/lib/gson/*
:/usr/irissys/dev/java/lib/jackson/*:/jgw/ocr-pex-1.0.0.jar
</Setting> 
    <Setting Target="Host" Name="JavaHome">/usr/lib/jvm/java-8-openjdk-amd64/</Setting> 
  </Item> 
  <Item Name="OcrOperation" Category="" ClassName="EnsLib.PEX.BusinessOperation" PoolSize="1" 
Enabled="true" Foreground="false" Comment="" LogTraceEvents="false" Schedule=""> 
    <Setting Target="Host" Name="%gatewayPort">55555</Setting> 
    <Setting Target="Host" Name="%remoteClassname">community.intersystems.pex.ocr.OcrOperation</Setting> 
    <Setting Target="Host" Name="%gatewayExtraClasspaths">.:/usr/irissys/dev/java/lib/JDK18/*
:/opt/irisapp/*:/usr/irissys/dev/java/lib/gson/*
:/usr/irissys/dev/java/lib/jackson/*
:/jgw/ocr-pex-1.0.0.jar
</Setting> 
  </Item> 
</Production>
}
 
}

¡Ahora cualquier producción de IRIS puede comunicarse con Java y Tesseract! Para comprobarlo, mira:

//call ocr method to get text from image, if you want to use pex
        Set pRequest = ##class(dc.ocr.OcrRequest).%New()
        Set pRequest.FileName = file.Filename
        
        // call java pex operation to do ocr, passing file into pRequest and receive ocr text with pResponse
        Set tSC = ..SendRequestSync("OcrOperation"pRequest, .pResponse1200)
        
        //save the results into database to use text analytics - nlp
        Set ocrTable = ##class(dc.ocr.OcrTable).%New()
        Set ocrTable.FileName = file.Filename
        Set ocrTable.OcrText = pResponse.StringValue
 
<div style="color: #d4d4d4;background-color: #1e1e1e;'Courier New', monospace;font-weight: normal;font-size: 14px;line-height: 19px;;">
  <div>
    <span style="color: #ffffff;">Set</span><span style="color: #d4d4d4;"> </span><span style="color: #ade2ff;">tSC</span><span style="color: #d4d4d4;"> = </span><span style="color: #ade2ff;">ocrTable</span><span style="color: #d4d4d4;">.</span><span style="color: #dcdcaa;">%Save</span><span style="color: #d4d4d4;">()</span>
  </div>
</div>

Toda la información sobre el código, con los respectivos comentarios, puede encontrarse en mi repositorio del servicio OCR (https://openexchange.intersystems.com/package/OCR-Service).

Ahora, con el texto extraído, necesitamos utilizar el motor PNL de IRIS para analizar los datos del texto y obtener información que nos permita tomar decisiones. Para ello, cuando se extrae un texto, se guarda en una tabla, y dicha tabla es utilizada por el motor de PNL como una fuente de texto. Mira la tabla %Save() anterior y analiza el siguiente código con PNL, que hace referencia a la OCRTable (que incluye los textos extraídos):

Class dc.ocr.OcrNLP Extends %iKnow.DomainDefinition [ ProcedureBlock ]
{
 
XData Domain [ XMLNamespace = "http://www.intersystems.com/iknow" ]
{
<domain name="OcrNLP" disabled="false" allowCustomUpdates="true">
<parameter name="DefaultConfig" value="OcrNLP.Configuration" isList="false" />
<data dropBeforeBuild="true">
<table listname="OcrNLPTable" batchMode="true" disabled="false" 
listerClass="%iKnow.Source.SQL.Lister" tableName="dc_ocr.OcrTable" idField="ID" 
groupField="ID" dataFields="OcrText" metadataColumns="FileName" metadataFields="filename" />
</data>
<matching disabled="false" dropBeforeBuild="true" autoExecute="true" ignoreDictionaryErrors="true" />
<metadata>
<field name="filename" operators="=" dataType="STRING" storage="0" caseSensitive="false" disabled="false" />
</metadata>
<configuration name="OcrNLP.Configuration" detectLanguage="true" languages="en,pt" 
userDictionary="OcrNLP.Dictionary#1" summarize="true" maxConceptLength="0" />
<userDictionary name="OcrNLP.Dictionary#1" />
</domain>
}
 
}

Consulta toda la información y la configuración en mi repositorio de GitHub sobre el servicio OCR.

Ahora podemos cargar algunos archivos e ir al Explorador para ver los conceptos y el CRC generados.

Este gif incluye todos los pasos comentados en este artículo:

0
0 153
Anuncio Esther Sanchez · jun 17, 2021

¡Hola Comunidad!

Os invitamos a un nuevo webinar en español: "Interoperabilidad en FHIR", el miércoles 23 de junio, a las 4:00 PM (CEST).

  

¿Cómo puede FHIR convivir e integrarse con otros protocolos?

En este webinar partiremos de un servidor FHIR ya existente y veremos cómo integrarlo con diferentes productores y consumidores de datos. También veremos las herramientas que permite InterSystems IRIS for Health para navegar entre distintos protocolos y presentar distintas fachadas de un repositorio. ¡Y algunas cosas más!

¡Os esperamos!

➡️ Podéis registraros aquí >>

1
0 164
Anuncio Esther Sanchez · abr 12, 2021

¡Hola desarrolladores!

Os invitamos a un nuevo webinar en español: "Perfiles FHIR: Introducción y uso con InterSystems IRIS for Health", el martes 20 de abril, a las 4:00 PM (CET).
 

Los Perfiles en FHIR permiten adaptar las especificaciones ‘core’ de FHIR al caso de uso o contexto de implantación. Durante el webinar, hablaremos de Perfiles desde la perspectiva del estándar y enseñaremos el uso de Perfiles en InterSystems IRIS for Health.

¡Nos vemos el próximo martes!

➡️ Podéis registraros aquí >> 
 

2
0 278