Hola Kurro,

Me parece que en las reglas del enrutador no se puede.

Una posible alternativa sería:

  • Desde el enrutador, enviar el mensaje a un Business Process que se encargue de enviar dinámicamente lo que necesites
  • Creas el Business Process anterior, y extraes el valor que necesites del HL7 (e.g. usando .GetValueAt()) y después desde el Business Process sí que puedes hacer envío dinámico utilizando justo esa sintaxis que has puesto (@destino) en la llamada.

Hola Luis,

Parece que estás en una versión muy antigua (2012) y utilizando una tecnología (ZEN) también antigua. ZEN se soporta aún por compatibilidad, pero échale un vistazo al InterSystems IRIS Migration Guide en el WRC > Software Distribution > Docs.

Sobre tu cuestión, el error probablemente viene dado de que intentas establecer el value de algo nulo. No consigues referencia el parámetro. Prueba con el ejemplo que te ha pasado Mario, o incluso mejor añade un id al parámetro para que puedas referenciarlo directamente a través del identificador.

<tablePane id="table"
           queryClass="MyApp.Employee"
           queryName="ListEmployees">
    <parameter value="Sales" id="param1"/>
    <parameter value="NEW YORK"/>
</tablePane>

Mira por ejemplo en Query Parameters

Hola Yone,

En los adaptadores de interoperabilidad no hay directamente un adaptador STOW-RS pero puedes intentar implementar la parte de servicios REST en la plataforma y luego enviarlo utilizando los adaptadores DICOM TCP convencionales.

Los servicios y operaciones incluidos que utilizan adaptadores DICOM TCP emplean siempre como mensaje EnsLib.DICOM.Document. Y sí, puedes instanciar un documento DICOM desde un fichero (stream) con CreateFromDicomFileStream.

Comprueba siempre el resultado de CreateFromDicomFileStream por si devuelve algún error. Si todo va bien, debería ser 1 o lo que es lo mismo un $$$OK.

USER>set fileStream = ##class(%Stream.FileBinary).%New()

USER>set fileStream.Filename="/shared/dicom/d1I00001.dcm"                                     

USER>write fileStream.Size
262878
USER>set sc = ##class(EnsLib.DICOM.Document).CreateFromDicomFileStream(fileStream, .dicom)

USER>write sc
1
USER>zwrite dicom
dicom=13@EnsLib.DICOM.Document  ; <OREF>
+----------------- general information ---------------
|      oref value: 13
|      class name: EnsLib.DICOM.Document
| reference count: 2
+----------------- attribute values ------------------
|       %Concurrency = 1  <Set>
|     DestinationAET = ""
|           Modified = 1
|  OriginalSourceAET = ""
|          SourceAET = ""
|    SourceIPAddress = ""
+----------------- swizzled references ---------------
|       i%CommandSet = ""  <Set>
|       r%CommandSet = "7@EnsLib.DICOM.CommandSet"  <Set>
|     i%FixedDataSet = ""
|     r%FixedDataSet = "5@EnsLib.DICOM.FixedDataSet"
|   i%MutableDataSet = ""  <Set>
|   r%MutableDataSet = "4@EnsLib.DICOM.MutableDataSet"  <Set>
+--------------- calculated references ---------------
|        (i%DataSet)   <Get>
|        (r%DataSet)   <Get>
|            HasData   <Get>
+-----------------------------------------------------

USER>

Una vez tengas tu instancia de EnsLib.DICOM.Document ya puedes enviarlo por DICOM TCP convencional. En tu ejemplo, parece que lo has incluido en otro mensaje.

Quizá se haya construido con errores el EnsLib.DICOM.Document, o simplemente sea un tema de representación en el visor de mensajes. Siempre puedes instanciar el mensaje en concreto que quieras en el terminal y examinar su contenido para quedarte seguro.

Hola Yone,

Los Streams se utilizan para almacenar cadenas de datos sin límite de tamaño. Si en una clase persistente, incluyes propiedades de tipo Stream serán persistentes.

%Stream.GlobalCharacter, %Stream.GlobalBinary: persisten los datos en globals (en la base de datos).
%Stream.FileCharacter, %Stream.FileBinary: persisten los datos en ficheros (.stream).

Lo que te recomienda la documentación es que utilices estas clases en lugar de sus versiones antiguas, por ejemplo:

  • Utiliza %Stream.GlobalCharacter en lugar de la antigua %GlobalCharacterStream.
  • Utiliza %Stream.FileCharacter en lugar de la antigua %FileCharacterStream.

La gestión de los mensajes huérfanos es como siempre. Si tienes un árbol de clases persistente que cuelga de un mensaje de interoperabilidad (incluya o no Streams), recuerda siempre implementar el método %OnDelete para borrar su contenido adecuadamente.

Hola Yone,

Si el %Status (tSC) que te devuelve ##class(ITB.HL7.Util.Convert).ER7ToXML es 1 como muestras, entonces el error no lo tienes en la parte de la conversión de ER7 a XML en Healthcare-HL7-XML (ITB).

Tendrás que ir examinando el resto de partes que tengas en tu servicio web:

  • No sé si tienes más código antes o después de esa llamada, comprueba que no haya errores.
  • Comprobar logs del servidor web y del CSP Webgateway. Incluso puedes activar ISCLOG Documentación

Hola Yone,

Entiendo que estás comparando dos cosas diferentes:

Hay más factores que pueden intervenir: servidor web externo, configuración Web Gateway, configuración seguridad aplicación web.

Yo te recomendaría que lo primero de todo pongas algunas trazas en el código de tu WebService para comprobar si la llamada está llegando a donde crees.

Por ejemplo puedes utilizar una global:

set ^zdebug($i(^zdebug))="["_$zdt($zts,3,,2)_"] "_"before" 
set ackXML = ##class(ITB.HL7.Util.Convert).ER7ToXML(ackER7,.tSC,"2.5")
set ^zdebug($i(^zdebug))="["_$zdt($zts,3,,2)_"] "_"after. tSC="_tSC 

Y luego échale un vistazo:

USER>zw ^zdebug
^zdebug=3
^zdebug(2)="[2022-06-03 08:35:47.75] before"
^zdebug(3)="[2022-06-03 08:35:57.39] after. tSC=1"

Así de entrada estás seguro que está llegando hasta la llamada.
Si llega hasta la llamada, luego puedes investigar en particular la conversión para ese mensaje.

Hola Yone,

Los procesos de negocio para DICOM tienen que controlar y gestionar lo que sucede con las operaciones DICOM que usan debido a la propia naturaleza dúplex del protocolo.

https://docs.intersystems.com/irisforhealthlatest/csp/docbook/DocBook.UI...

Por ejemplo, en DICOM.BP.QueryProcess tiene que gestionar llamadas para establecer y liberar las asociaciones en la conexión.

Quizá te resulte más sencillo de implementar utilizar varios BP y BO en la producción, según los diferentes sistemas que tengas que integrar.

Hola Yone,

Disculpa, ¡no había visto que esta pregunta estaba sin responder!

No puedes exportar un documento DICOM a XML y después tratar de escribirlo directamente en la traza. Los documentos DICOM son complejos y la forma de acceder a sus propiedades es a través de los métodos de la clase EnsLib.DICOM.Document.

Por ejemplo:

pInput.GetValueAt("DataSet.PatientID",,.tSC)

Hola Yone,

Imagino que habrá diferencias entre el C-FIND que se envía en el primer caso y el segundo.

En el primer caso, el que retorna más resultados, entiendo que es el caso del ejemplo. Revisa cómo se está generando exactamente ese C-FIND:

https://github.com/intersystems-ib/iris-dicom-sample/blob/7bc3c00dfa1bbb...

En principio, se está haciendo un PatientRootQuery (tAffectedSOPClassUID).

No sé si puede servirte para algo, pero en el herramienta findscu creo que hay una opción para especificar el Information Model a utilizar:

https://github.com/dcm4che/dcm4che/blob/master/dcm4che-tool/dcm4che-tool...

-M <name>                                specifies Information Model.
                                          Supported names: PatientRoot,
                                          StudyRoot, PatientStudyOnly,
                                          MWL, UPSPull, UPSWatch,
                                          UPSQuery, HangingProtocol or
                                          ColorPalette. If no Information
                                          Model is specified, StudyRoot
                                          will be used.

Hola Yone,

Imagino que te refieres al ejemplo https://github.com/intersystems-ib/iris-dicom-sample

Los comandos C-FIND son mensajes DICOM que deben tener el formato correcto y transmitirse usando el protocolo DICOM. Por eso, o usas un simulador, o generas ese mensaje desde Ensemble / Health Connect.

En el ejemplo, el comando do ##class(DICOM.BS.QueryService).TestFind() provoca la generación de un mensaje C-FIND dentro de la producción para un paciente concreto.

El simulador dcm4che tiene la utilidad findscu que permite simular la generación de mensajes C-FIND.

Hola Yone,

En tu caso, parece que el host al que intentas conectar (supongo que es un simulador), está rechazando la conexión.

Quizá porque el documento DICOM que intentas enviar tiene un TransferSyntax que no está configurado. Lo mejor sería que intentaras obtener información / logs en el host que lo está rechazando. Por ejemplo si usas el simulador dcm4che te mostrará información que te puede ayudar a investigar qué ha sucedido.

Yo te recomendaría:

1-Intenta ejecutar el ejemplo que te pasé, utilizando contenedores, y comprueba que todo te funciona bien y comprendes cómo funciona la integración con DICOM.

2-Intenta replicar el comportamiento que te interese en tu propia producción con tu propio simulador. Ten presente la información que te devuelva el simulador. Te ayudará a comprender el proceso de negociación de la conexión y la transferencia.

Hola Yone,

No sé si te he entendido muy bien. ¿Quieres hacer la comprobación por código y si es así obtener el campo?

Por ejemplo:

if (request.GetValueAt("PID:3.4.1")="CAC")&&(request.GetValueAt("PID:3.5")="JHN") {
     write !,request.GetValueAt("PID:3.1")
}

Si lo que necesitas es hacerlo en el buscador de mensajes, lo más rápido sería que utilizarás tablas de búsqueda para indexar esas búsquedas y que vayan más rápido.

Hola Yone, me alegro de que al final hayas encontrado el mecanismo de Attachment para enviarlo :)

Respecto a la autenticación, deberías revisar las especificaciones del servicio web al que te quieres conectar.

Creo que estás intentando conectar a un servicio web del Ministerio para enviar comunicaciones, por experiencias pasadas creo recordar que suelen pedir al menos:
* Cabeceras WSA (parece que ya tienes algunas puestas).
* Firma del mensaje con token y un timestamp. La firma debería incluir el timestamp, el cuerpo SOAP, el token y las cabeceras WSA.

Pero repito, confírmalo por favor con la documentación de las especificaciones del servicio web al que te quieras conectar.

Puedes echar un vistazo a la documentación aquí:
https://docs.intersystems.com/irisforhealthlatest/csp/docbook/DocBook.UI...

En cualquier caso lo dicho, si necesitas algún ejemplo específico o comentar alguna cosa concreta puedes escribirme por email y buscamos un rato para echarlo un ojo.

Hola Yone,

En principio el ..SetHttpHeader() debería ser suficiente.

Puedes probar con:

do ..SetHttpHeader("Content-Disposition", "attachment; name=""application.zip""")

¿El Servicio Web sigue devolviendo un error respecto al Name?

Supongo que estás utilizando ^ISCSOAP para examinar lo que se envía al WebService. Dependiendo de tu versión de Ensemble o Health Connect podrás utilizar las opciones de ISCSOAP para que te muestre las cabeceras HTTP:

set ^ISCSOAP("Log")="ioshH"
set ^ISCSOAP("LogFile")="/tmp/soap.log"

Aquí en InterSystems IRIS SOAP Log te explica las diferentes opciones. Comprueba en la documentación de tu versión específica si están las opciones para las cabeceras HTTP y así asegurarte de que se muestran.

He hecho una prueba rápida en una 2020.1 y en el log de ISCSOAP debería tener una pinta así:

10/15/2021 13:39:51 *********************
Output from Web client with SOAP action = 
<?xml version="1.0" encoding="UTF-8" ?>
<!-- mensaje SOAP que se haya enviado -->


**** Output HTTP headers for Web Client
User-Agent: Mozilla/4.0 (compatible; InterSystems IRIS;)
Host: xyz.es
Accept-Encoding: gzip
Content-Disposition: attachment; name="application.zip"
SOAPAction: 

Si en tu versión no se pueden mostrar las cabeceras en el log quizá puedes utilizar herramientas externas como WireShark, etc.

Échale un vistazo a esto, y si no logras avanzar escríbeme por correo y quedamos y lo revisamos.

Hola de nuevo Yone,

Por lo que comentas, quizá te falte añadir la cabecera Content-Disposition en la petición y ahí especificar el nombre del archivo.

Creo que en el ejemplo que habías hecho originalmente con SoapUI, esa cabecera tenía este valor:

Content-Disposition: attachment; name="application.zip"

En Fine Tuning a WebClient te habla de cómo puedes especificar cabeceras en tu cliente web utilizando el método SetHttpHeader() que hereda de %SOAP.WebClient.

Así que puedes probar a especificar con SetHttpHeader() la cabecera Content-Disposition y añadir el nombre del fichero que quieras que aparezca.

Quizá puedas comparar la petición te funciona en SoapUI Vs. la que da error en IRIS y comprobar si tienen alguna mínima diferencia en cabeceras HTTP o SOAP.

Podrías utilizar SetHttpHeader() para modificar las cabeceras HTTP de tu %SOAP.WebClient
https://docs.intersystems.com/irisforhealthlatest/csp/docbook/DocBook.UI...

O directamente cabeceras SOAP si te hicieran falta:
https://docs.intersystems.com/irisforhealthlatest/csp/docbook/DocBook.UI...