scieee AI-readable full text Open interactive document viewer

Pasarela de la plataforma FIWARE al estándar médico FHIR basada en Spring

González Ruiz, Jaime

Abstract

FIWARE es una plataforma para IoT que, aunque ha sido utilizada en dominios como las ciudades inteligentes, la industria o la gestión de la energía, aún se ha utilizado poco en el contexto de la sanidad. Un problema recurrente en el ámbito de las tecnologías enfocadas a la gestión de la salud es la interoperabilidad entre ellas. En los últimos años, se ha observado una tendencia al alza en la inversión en las TICS para crear una arquitectura común, que permita entre otras cosas el intercambio de mensajes entre las aplicaciones sanitarias, la interoperabilidad del Historial Médico Electrónico y los identificadores de los pacientes. El estándar FHIR, impulsado por HL7, es un proyecto cuyo objetivo es proporcionar una arquitectura moderna, interoperable y común para las aplicaciones del ámbito médico, solucionando el enorme problema de la comunicación entre sistemas. Este Trabajo de Fin de Grado consiste en la creación de una aplicación web que actúa como pasarela entre dispositivos médicos de la plataforma FIWARE y el estándar FHIR. Para alcanzar este objetivo, se ha establecido una correspondencia entre los recursos de ambos y se han desarrollado una serie de funciones tras una interfaz REST para manejar arquitecturas que usen ambos estándares.

Full text

1 Equation Chapter 1 Section 1 Trabajo Fin de Grado Grado en Ingeniería de las Tecnologías de Telecomunicación Pasarela de la plataforma FIWARE al estándar médico FHIR basada en Spring Autor: Jaime González Ruiz Tutores: Isabel Román Martínez y Juan Antonio Ternero Muñiz Departamento de Ingeniería Telemática Escuela Técnica Superior de Ingeniería Universidad de Sevilla Sevilla, 2019 2 3 Trabajo Fin de Grado Grado en Ingeniería de las Tecnologías de Telecomunicación Pasarela de la plataforma FIWARE al estándar médico FHIR basada en Spring Autor: Jaime González Ruiz Tutores: Isabel Román Martínez y Juan Antonio Ternero Muñiz Departamento de Ingeniería Telemática Escuela Técnica Superior de Ingeniería Universidad de Sevilla Sevilla, 2019 4 5 Trabajo Fin de Grado: Pasarela de la plataforma FIWARE al estándar médico FHIR basada en Spring Autor: Jaime González Ruiz Tutores: Isabel Román Martínez y Juan Antonio Ternero Muñiz El tribunal nombrado para juzgar el Proyecto arriba indicado, compuesto por los siguientes miembros: Presidente: Vocales: Secretario: Acuerdan otorgarle la calificación de: Sevilla, 2019 El Secretario del Tribunal 6 7 A mi familia A mis amigos 8 9 Agradecimientos En primer lugar, me gustaría agradecer a mis padres su apoyo incondicional, tanto emocional como económico, a lo largo de estos intensos cuatro años. Agradecer también a mis amigos y a mis compañeros por hacer estos años más llevaderos. Gracias por las risas y los momentos vividos que quedarán ahí para siempre. Pero sobre todo agradecer a mis tutores Isabel y Juan Antonio, que me han orientado cuando lo he necesitado y me han ayudado en la revisión de este documento. Jaime González Ruiz Sevilla, 2019 16 3.8.12 Actualización de plantilla del recurso DeviceMetric ................................................. 148 3.8.13 Actualización de plantilla del recurso Observation ................................................... 150 3.8.14 Eliminación de una familia de dispositivos ................................................................ 152 3.8.15 Eliminación de un recurso Device concreto .............................................................. 154 3.8.16 Actualización del valor medido por un dispositivo ................................................... 155 3.8.17 Actualización del estado de un dispositivo ................................................................ 157 3.8.18 Actualización de la posición de un dispositivo .......................................................... 159 3.8.19 Actualización de la fecha de calibración de un dispositivo ....................................... 160 3.8.20 Actualización de la dirección IP de un dispositivo ..................................................... 162 4 MONTAJE Y PRUEBAS DEL ENTORNO ................................................................................. 165 4.1 Servidor FHIR ......................................................................................................................... 165 4.1.1 Prerrequisitos ................................................................................................................... 165 4.1.2 Ejecutando el servidor ..................................................................................................... 167 4.1.3 Ejecutando el servidor dentro de Apache Tomcat ........................................................ 167 4.1.4 Ejecutando el servidor dentro de un contenedor Docker (Opcional) .......................... 171 4.2 Orion Context Broker de FIWARE y MongoDB. .................................................................. 173 4.2.1 Primera Opción: Usando comandos de Docker ............................................................. 176 4.2.2 Segunda Opción: Usando la herramienta Docker Compose ........................................ 177 4.3 Jar de la aplicación y opciones de ejecución ....................................................................... 178 4.3.1 Parámetros configurables el ejecutar el jar ................................................................... 180 4.4 Pruebas .................................................................................................................................. 182 4.4.1 Creación de la plantilla DeviceDefinition ....................................................................... 183 4.4.2 Creación de la plantilla Device ........................................................................................ 185 4.4.3 Creación de la plantilla DeviceMetric ............................................................................. 189 4.4.4 Creación de la plantilla Observation ............................................................................... 191 4.4.5 Creación de recursos Device adicionales ....................................................................... 194 4.4.6 Actualización del valor medido por un dispositivo ........................................................ 197 4.4.7 Actualización de la localización de un dispositivo ......................................................... 198 4.4.8 Actualización del estado de un dispositivo .................................................................... 199 4.4.9 Actualización de la fecha de calibración de un dispositivo ........................................... 200 4.4.10 Actualización de la dirección IP de un dispositivo ..................................................... 201 4.4.11 Recuperación de un recurso Device previamente creado ....................................... 202 4.4.12 Recuperación de un recurso DeviceDefinition previamente creado ....................... 203 4.4.13 Recuperación de un recurso DeviceMetric previamente creado ............................ 204 4.4.14 Recuperación de recurso Observation previamente creado ................................... 205 4.4.15 Actualización de un recurso DeviceDefinition previamente creado ....................... 206 4.4.16 Actualización de un recurso Device previamente creado ........................................ 209 4.4.17 Actualización de un recurso DeviceMetric previamente creado ............................. 212 4.4.18 Actualización de recurso Observation previamente creado .................................... 214 4.4.19 Eliminación de una familia de dispositivos ................................................................ 216 4.4.20 Eliminación de un dispositivo concreto ..................................................................... 218 5 Conclusiones ....................................................................................................................... 221 5.1 Esfuerzos necesarios ............................................................................................................. 221 5.2 Línea futura de desarrollo .................................................................................................... 222 5.3 Conclusión ............................................................................................................................. 222 6 Referencias ......................................................................................................................... 223 17 ÍNDICE DE TABLAS Tabla 1. Recurso Device de FIWARE 60 Tabla 2. Recurso DeviceModel de FIWARE 63 Tabla 3. FHIR: DeviceDefinition.identifier 71 Tabla 4. FHIR: DeviceDefinition.udiDeviceIdentifier 71 Tabla 5. FHIR: DeviceDefinition.udiDeviceIdentifier.deviceIdentifier 71 Tabla 6. FHIR: DeviceDefinition.udiDeviceIdentifier.issuer 72 Tabla 7. FHIR: DeviceDefinition.udiDeviceIdentifier.jurisdiction 72 Tabla 8. FHIR: DeviceDefinition.manufacturer[X] 72 Tabla 9. FHIR: DeviceDefinition.manufacturerString 72 Tabla 10. FHIR: DeviceDefinition.manufacturerReference 73 Tabla 11. FHIR: DeviceDefinition.deviceName 73 Tabla 12. FHIR: DeviceDefinition.deviceName.name 73 Tabla 13. FHIR: DeviceDefinition.deviceName.type 73 Tabla 14. FHIR: DeviceDefinition.modelNumber 74 Tabla 15. FHIR: DeviceDefinition.type 74 Tabla 16. FHIR: DeviceDefinition.specialization 74 Tabla 17. FHIR: DeviceDefinition.specialization.systemType 75 Tabla 18. FHIR: DeviceDefinition.specialization.version 75 Tabla 19. FHIR: DeviceDefinition.version 75 Tabla 20. FHIR: DeviceDefinition.safety 75 Tabla 21. FHIR: DeviceDefinition.shelfLifeStorage 76 Tabla 22. FHIR: DeviceDefinition.physicalCharacteristics 76 Tabla 23. FHIR: DeviceDefinition.languageCode 76 Tabla 24. FHIR: DeviceDefinition.capability 77 Tabla 25. FHIR: DeviceDefinition.capability.type 77 Tabla 26. FHIR: DeviceDefinition.capability.description 77 Tabla 27. FHIR: DeviceDefinition.property 77 Tabla 28. FHIR: DeviceDefinition.property.type 78 Tabla 29. FHIR: DeviceDefinition.property.valueQuantity 78 Tabla 30. FHIR: DeviceDefinition.property.valueCode 79 Tabla 31. FHIR: DeviceDefinition.owner 79 Tabla 32. FHIR: DeviceDefinition.contact 79 Tabla 33. FHIR: DeviceDefinition.url 80 Tabla 34. FHIR: DeviceDefinition.onlineInformation 80 Tabla 35. FHIR: DeviceDefinition.note 80 Tabla 36. FHIR: DeviceDefinition.quantity 81 Tabla 37. FHIR: DeviceDefinition.parentDevice 81 Tabla 38. FHIR: DeviceDefinition.material 81 Tabla 39. FHIR: DeviceDefinition.material.substance 82 Tabla 40. FHIR: DeviceDefinition.material.alternate 82 Tabla 41. FHIR: DeviceDefinition.material.allergenicIndicator 82 Tabla 42. FHIR: Device.identifier 83 Tabla 43. FHIR: Device.definition 83 Tabla 44. FHIR: Device.udiCarrier 83 Tabla 45. FHIR: Device.udiCarrier.deviceIdentifier 84 Tabla 46. FHIR: Device.udiCarrier.issuer 84 Tabla 47. FHIR: Device.udiCarrier.jurisdiction 84 Tabla 48. FHIR: Device.udiCarrier.carrierAIDC 85 Tabla 49. FHIR: Device.udiCarrier.carrierHRF 85 Tabla 50. FHIR: Device.udiCarrier.entryType 85 Tabla 51. FHIR: Device.status 85 18 Tabla 52. FHIR: Device.statusReason 86 Tabla 53. FHIR: Device.distinctIdentifier 86 Tabla 54. FHIR: Device.manufacturer 86 Tabla 55. FHIR: Device.manufacturerDate 87 Tabla 56. FHIR: Device.expirationDate 87 Tabla 57. FHIR: Device.lotNumber 87 Tabla 58. FHIR: Device.serialNumber 87 Tabla 59. FHIR: Device.deviceName 88 Tabla 60. FHIR: Device.deviceName.name 88 Tabla 61. FHIR: Device.deviceName.type 88 Tabla 62. FHIR: Device.modelNumber 88 Tabla 63. FHIR: Device.partNumber 89 Tabla 64. FHIR: Device.type 89 Tabla 65. FHIR: Device.specialization 89 Tabla 66. FHIR: Device.specialization.systemType 90 Tabla 67. FHIR: Device.specialization.version 90 Tabla 68. FHIR: Device.version 90 Tabla 69. FHIR: Device.version.type 90 Tabla 70. FHIR: Device.version.component 91 Tabla 71. FHIR: Device.version.value 91 Tabla 72. FHIR: Device.property 91 Tabla 73. FHIR: Device.property.type 92 Tabla 74. FHIR: Device.property.valueQuantity 92 Tabla 75. FHIR: Device.property.valueCode 92 Tabla 76. FHIR: Device.patient 92 Tabla 77. FHIR: Device.owner 93 Tabla 78. FHIR: Device.contact 93 Tabla 79. FHIR: Device.location 94 Tabla 80. FHIR: Device.url 94 Tabla 81. FHIR: Device.note 94 Tabla 82. FHIR: Device.safety 95 Tabla 83. FHIR: Device.parent 95 Tabla 84. FHIR: DeviceMetric.identifier 96 Tabla 85. FHIR: DeviceMetric.type 96 Tabla 86. FHIR: DeviceMetric.unit 96 Tabla 87. FHIR: DeviceMetric.source 97 Tabla 88. FHIR: DeviceMetric.operationalStatus 97 Tabla 89. FHIR: DeviceMetric.color 98 Tabla 90. FHIR: DeviceMetric.category 98 Tabla 91. FHIR: DeviceMetric.measurementPeriod 98 Tabla 92. FHIR: DeviceMetric.calibration 98 Tabla 93. FHIR: DeviceMetric.calibration.type 99 Tabla 94. FHIR: DeviceMetric.calibration.state 99 Tabla 95. FHIR: DeviceMetric.calibration.time 99 Tabla 96. FHIR: Observation.identifier 100 Tabla 97. FHIR: Observation.basedOn 100 Tabla 98. FHIR: Observation.partOf 100 Tabla 99. FHIR: Observation.status 100 Tabla 100. FHIR: Observation.category 101 Tabla 101. FHIR: Observation.code 101 Tabla 102. FHIR: Observation.subject 101 Tabla 103. FHIR: Observation.focus 101 Tabla 104. FHIR: Observation.encounter 102 Tabla 105. FHIR: Observation.effective[X] 102 Tabla 106. FHIR: Observation.issued 102 Tabla 107. FHIR: Observation.performer 102 Tabla 108. FHIR: Observation.value[X] 103 19 Tabla 109. FHIR: Observation.dateAbsentReason 103 Tabla 110. FHIR: Observation.interpretation 103 Tabla 111. FHIR: Observation.note 104 Tabla 112. FHIR: Observation.bodySite 104 Tabla 113. FHIR: Observation.method 104 Tabla 114. FHIR: Observation.specimen 104 Tabla 115. FHIR: Observation.device 104 Tabla 116. FHIR: Observation.referenceRange 105 Tabla 117. FHIR: Observation.referenceRange.low 105 Tabla 118. FHIR: Observation.referenceRange.high 105 Tabla 119. FHIR: Observation.referenceRange.type 105 Tabla 120. FHIR: Observation.referenceRange.appliesTo 106 Tabla 121. FHIR: Observation.referenceRange.age 106 Tabla 122. FHIR: Observation.referenceRange.text 106 Tabla 123. FHIR: Observation.hasMember 106 Tabla 124. FHIR: Observation.derivedFrom 106 Tabla 125. FHIR: Observation.component 107 Tabla 126. FHIR: Observation.component.code 107 Tabla 127. FHIR: Observation.component.value[X] 107 Tabla 128. FHIR: Observation.component.dataAbsentReason 107 Tabla 129. FHIR: Observation.component.interpretation 108 Tabla 130. FHIR: Observation.component.referenceRange 108 Tabla 131. Resumen correspondencia FHIR-FIWARE 110 Tabla 132. Resumen interfaz REST 129 Tabla 133. Interfaz para capturar notificaciones 130 20 21 ÍNDICE DE FIGURAS Figura 1. Sensores médicos conectados a Internet a través de una Raspberry Pi 28 Figura 2. Orion Context Broker 29 Figura 3. Relaciones de la aplicación con el resto de los componentes 30 Figura 4. Aplicación Eclipse 31 Figura 5. Aplicación Postman 32 Figura 6. Aplicación VMware Workstation 15 Player 33 Figura 7. Aplicación draw.io 33 Figura 8. Objeto JSON 36 Figura 9. Fragmento del archivo pom.xml 39 Figura 10. Componentes de una entidad de contexto 40 Figura 11. Entidad NGSI en JSON 41 Figura 12. Atributo NGSI en JSON 42 Figura 13. Representación tipo "keyValues" 42 Figura 14. Representación tipo "values" 42 Figura 15. Atributo tipo "DateTime" 43 Figura 16. Localización según Simple Location Format 46 Figura 17. Localización según GeoJSON 46 Figura 18. Notificación NGSI por defecto 47 Figura 19. Notificación NGSI con representación "keyValues" 47 Figura 20. Notificación NGSI con representación “values” 47 Figura 21. Petición POST para crear una entidad 51 Figura 22. Petición GET para recuperar una entidad 52 Figura 23. Petición GET para recuperar atributos de una entidad 52 Figura 24. Petición POST para actualizar/añadir atributos 52 Figura 25. Petición PATCH para actualizar atributos 53 Figura 26. Petición PUT para sustituir atributos 53 Figura 27. Petición DELETE para eliminar una entidad 54 Figura 28. Petición GET para recuperar un atributo concreto 54 Figura 29. Petición PUT para actualizar un atributo concreto 54 Figura 30. Petición DELETE para eliminar un atributo concreto 55 Figura 31. Petición GET para recuperar el valor de un atributo 55 Figura 32. Petición PUT para actualizar el valor de un atributo 56 Figura 33. Petición GET para listar suscripciones 56 Figura 34. Petición POST para crear una suscripción 57 Figura 35. Petición GET para recuperar una suscripción 57 Figura 36. Petición PATCH para actualizar una suscripción 57 Figura 37. Petición DELETE para borrar una suscripción 57 Figura 38. Recurso Device de FIWARE en JSON 61 Figura 39. Recurso DeviceModel de FIWARE en JSON 63 Figura 40. Container de Docker frente a una máquina virtual tradicional 66 Figura 41. Relaciones de la aplicación con el resto de los componentes 67 Figura 42. Diagrama de componentes 68 Figura 43. Diagrama de despliegue 69 Figura 44. Diagrama del correspondencia FHIR-FIWARE 70 Figura 45. Diagrama de clases general 111 Figura 46. Diagrama de clases Device FIWARE 112 Figura 47. Diagrama de clase DeviceModel 113 Figura 48. Diagrama de clase GeoJSON 113 Figura 49. Diagrama de clases NgsiParser 114 Figura 50. Diagrama de clase FhirToFiware 114 Figura 51. Diagrama de clases Entity NGSIv2 114 Figura 52. Diagrama de clases Subscription 115 Figura 53. Diagrama de clases DeviceUpdate 115 22 Figura 54. Diagrama de clase FhirClientInterface 118 Figura 55. Ejemplo de interfaz FhirClientInterface 118 Figura 56. Interfaz FhirClientInterface@Read 119 Figura 57. Interfaz FhirClientInterface@Update 119 Figura 58. Interfaz FhirClientInterface@Delete 120 Figura 59. Interfaz FhirClientInterface@Create. 120 Figura 60. Instanciación cliente FHIR 121 Figura 61. Configuración cliente FHIR 121 Figura 62. Ejemplo de suscripción 122 Figura 63. Función subsGenerator 123 Figura 64. Función createDefaultSubscriptions 123 Figura 65. Ejemplo de notificación NGSIv2 124 Figura 66. Diagrama de clase FiwClient 124 Figura 67. Diagrama de clase TemplateDB 125 Figura 68. Diagrama de clase TemplateDevice 126 Figura 69. Interfaz TemplateDBRepository 126 Figura 70. TemplateDeviceRepository 126 Figura 71. Diagrama de actividad creación plantilla DeviceDefinition 131 Figura 72. Etiquetas Spring creación DeviceDefinition 131 Figura 73. Diagrama de actividad creación plantilla Device 133 Figura 74. Etiquetas Spring creación Device 133 Figura 75. Diagrama de actividad creación plantilla DeviceMetric 135 Figura 76. Etiquetas Spring creación DeviceMetric 135 Figura 77. Diagrama de actividad creación plantilla Observation 137 Figura 78. Etiquetas Spring creación Observation 137 Figura 79. Diagrama de actividad creación plantilla Device adicional 139 Figura 80. Etiquetas Spring creación Device adicional 140 Figura 81. Diagrama de actividad recuperación plantilla DeviceDefinition 141 Figura 82. Etiquetas Spring recuperación DeviceDefinition 141 Figura 83. Diagrama de actividad recuperación plantilla Device 142 Figura 84. Etiquetas Spring recuperación Device 142 Figura 85. Diagrama de actividad recuperación plantilla DeviceMetric 143 Figura 86. Etiquetas Spring recuperación DeviceMetric 143 Figura 87. Diagrama de actividad recuperación plantilla Observation 144 Figura 88. Etiquetas Spring recuperación Observation 144 Figura 89. Diagrama de actividad actualización plantilla DeviceDefinition 145 Figura 90. Etiquetas Spring actualización DeviceDefinition 146 Figura 91. Diagrama de actividad actualización plantilla Device 147 Figura 92. Etiquetas Spring actualización Device 148 Figura 93. Diagrama de actividad actualización plantilla DeviceMetric 149 Figura 94. Etiquetas Spring actualización DeviceMetric 149 Figura 95. Diagrama de actividad actualización plantilla Observation 151 Figura 96. Etiquetas Spring actualización Observation 151 Figura 97. Diagrama de actividad eliminación familia de dispositivos 153 Figura 98. Etiquetas Spring eliminación familia de dispositivos 154 Figura 99. Diagrama de actividad eliminación Device 154 Figura 100. Etiquetas Spring eliminación Device 155 Figura 101. Diagrama de actividad actualización valor medido 156 Figura 102. Etiquetas Spring actualización valor medido 157 Figura 103. Diagrama de actividad actualización del estado 158 Figura 104. Etiquetas Spring actualización del estado 158 Figura 105. Diagrama de actividad actualización de la posición 159 Figura 106. Etiquetas Spring actualización localización 160 Figura 107. Diagrama de actividad actualización de la fecha de calibración 161 Figura 108. Etiquetas Spring actualización fecha de calibración 161 Figura 109. Diagrama de actividad actualización de la IP 163 Figura 110. Etiquetas Spring actualización dirección IP 163 23 Figura 111. Instalación git 165 Figura 112. Git clone servidor hapifhir 165 Figura 113. Versión java 166 Figura 114 .Instalador java 166 Figura 115. Actualización de paquetes y dependencias 166 Figura 116. Instalación Maven 166 Figura 117. Lanzamiento del servidor FHIR desde Maven 167 Figura 118. Página de inicio del servidor FHIR. 167 Figura 119. Página de descargas Apache Tomcat 168 Figura 120. Descompresión Tomcat 168 Figura 121. Permisos de ejecución Tomcat 168 Figura 122. Arranque de Tomcat 168 Figura 123. Página de inicio servidor Tomcat 169 Figura 124. Detención Tomcat 169 Figura 125. Creación archivo WAR con la aplicación del servidor FHIR 170 Figura 126. Traslado del WAR a Tomcat 170 Figura 127. Página de inicio servidor FHIR (imagen ETSI) 171 Figura 128. Archivo "build-docker-image.sh" 171 Figura 129. Dockerfile 171 Figura 130. Ejecución "build-docker-image.sh" 172 Figura 131. Resultado "build-docker-image.sh" 172 Figura 132. Ejecución de Dockerfile 172 Figura 133. Imágenes Docker 173 Figura 134. Lanzamiento de la imagen sobre un container 173 Figura 135. Ejecución y página de inicio del servidor FHIR 173 Figura 136. Actualización índice de paquetes 173 Figura 137. Paquetes para usar un repositorio sobre HTTPS 174 Figura 138. Comprobación de la huella 174 Figura 139. Repositorio de Docker "stable" 174 Figura 140. Instalación Docker 175 Figura 141. Versión y prueba de Docker 175 Figura 142. Descarga de Docker Compose 175 Figura 143. Arquitectura Orion + MongoDB 176 Figura 144. Primera opción para lanzar Docker y MongoDB 176 Figura 145. Lanzamiento contenedor MongoDB 176 Figura 146. Lanzamiento contenedor Orion 176 Figura 147. Petición de prueba GET a Orion 177 Figura 148. Comando para parar y eliminar los contenedores 177 Figura 149. Lanzamiento usando Docker Compose 177 Figura 150. Petición de prueba GET a Orion 178 Figura 151. Comando Docker Compose para deshacer el lanzamiento 178 Figura 152. "spring-boot-maven-plugin" 178 Figura 153. Menú Run Eclipse 179 Figura 154. Ventana de configuración Maven build 179 Figura 155. Ejecución Maven Build 179 Figura 156. Explorador de proyectos de Eclipse 180 Figura 157. Ejecución de la pasarela 180 Figura 158. "application.properties" 181 Figura 159. Ejemplo de paso de párametros 181 Figura 160. Diagrama de despliegue 182 Figura 161. "runBrokerMongo.sh" 182 Figura 162. "runFHIRServer.sh" 182 Figura 163. "runApp.sh" 183 Figura 164. Petición creación DeviceDefinition 183 Figura 165. Cabecera HTTP creación DeviceDefinition 184 Figura 166. Recurso DeviceDefinition en JSON 184 Figura 167. Respuesta exitosa creación DeviceDefinition 184 24 Figura 168. Recurso DeviceDefinition en el servidor FHIR 185 Figura 169. Respuesta en caso de error de formato 185 Figura 170. Respuesta en caso de DeviceDefinition ya existente 185 Figura 171. Petición creación Device 186 Figura 172. Cabera HTTP creación Device 186 Figura 173. Recurso Device en JSON 186 Figura 174. Respuesta exitosa creación Device 186 Figura 175. Recurso Device en el servidor FHIR 187 Figura 176. Recurso Location en el servidor FHIR 187 Figura 177. Recurso Device FIWARE 188 Figura 178. Petición GET a la entidad "fiware_glucometer_1" 188 Figura 179. Respuesta en caso de error de formato del Device 188 Figura 180. Respuesta en caso de Device ya existente 188 Figura 181. Petición creación DeviceMetric 189 Figura 182. Cabecera HTTP creación DeviceMetric 189 Figura 183. Recurso DeviceMetric en JSON 189 Figura 184. Respuesta exitosa creación DeviceMetric 190 Figura 185. Recurso DeviceMetric en el servidor FHIR 190 Figura 186. Petición GET a la entidad "fiware_glucometer" 190 Figura 187. Recurso DeviceModel 191 Figura 188. Respuesta en caso de error de formato del DeviceMetric 191 Figura 189. Respuesta en caso de DeviceMetric ya existente 191 Figura 190. Petición creación Observation 192 Figura 191. Cabecera HTTP creación Observation 192 Figura 192. Recurso Observation en JSON 192 Figura 193. Respuesta exitosa creación Observation 192 Figura 194. Petición GET a Orion de todas las suscripciones 193 Figura 195. Suscripción cambios IP 193 Figura 196. Suscripción cambios valor medido 193 Figura 197. Suscripción a cambios en la fecha de calibración 193 Figura 198. Suscripción a cambios en la localización 193 Figura 199. Suscripción a cambios del estado 194 Figura 200. Respuesta en caso de error de formato del Observation 194 Figura 201. Respuesta en caso de Observation ya existente 194 Figura 202. Petición creación Device adicional 194 Figura 203. Cabecera HTTP creación Device adicional 195 Figura 204. Recursos Device 195 Figura 205. Respuesta en caso de éxito 195 Figura 206. Recursos Device en el servidor FHIR 196 Figura 207. Petición GET a Orion del recurso "fiware_glucometer_2" 196 Figura 208. Recurso Device "fiware_glucometer_2" 196 Figura 209. Petición GET a Orion del recurso "fiware_glucometer_3" 196 Figura 210. Recurso Device "fiware_glucometer_3" 197 Figura 211. Respuesta en caso de error de formato del Device 197 Figura 212. Respuesta en caso de Device ya existente 197 Figura 213. Actualización de "value" de "fiware_glucometer_1" 197 Figura 214. Cabecera HTTP actualización "value" 198 Figura 215. Nuevo "value" 198 Figura 216. Recurso Observation en el servidor FHIR 198 Figura 217. Actualización de "location" de "fiware_glucometer_1" 199 Figura 218. Cabecera HTTP actualización "location" 199 Figura 219. Nuevo "location" 199 Figura 220. Recurso Location en el servidor FHIR 199 Figura 221. Actualización de "deviceState" de "fiware_glucometer_1" 199 Figura 222. Cabecera HTTP actualización "deviceState" 200 Figura 223. Nuevo "deviceState" 200 Figura 224. Recurso Device actualizado 200 25 Figura 225. Actualización de "dateLastCalibration" de "fiware_glucometer_1" 200 Figura 226. Cabecera HTTP actualización "dateLastCalibration" 201 Figura 227. Nueva fecha de calibración 201 Figura 228. Recurso DeviceMetric actualizado en el servidor FHIR 201 Figura 229. Actualización de "ipAddress" de "fiware_glucometer_1" 201 Figura 230. Cabecera HTTP actualización "ipAddress" 202 Figura 231. Nuevo "ipAddress" 202 Figura 232. Recurso Device modificado en el servidor FHIR 202 Figura 233. Petición recuperación Device 203 Figura 234. Cabecera HTTP recuperación Device 203 Figura 235. Fragmento del recurso Device recuperado 203 Figura 236. Respuesta en caso de que el Device solicitado no exista 203 Figura 237. Petición recuperación DeviceDefinition 203 Figura 238. Cabera HTTP recuperación DeviceDefinition 204 Figura 239. Fragmento del DeviceDefinition recuperado 204 Figura 240. Respuesta en caso de que el DeviceDefinition solicitado no exista 204 Figura 241. Petición recuperación DeviceMetric 204 Figura 242. Cabecera HTTP recuperación DeviceMetric 205 Figura 243. Fragmento del recurso DeviceMetric recuperado 205 Figura 244. Respuestas en caso de que el DeviceMetric solicitado no exista 205 Figura 245. Petición recuperación Observation 205 Figura 246. Cabecera HTTP recuperación Observation 205 Figura 247. Fragmento del recurso Observation recuperado 206 Figura 248. Respuesta en caso de que el Observation solicitado no exista 206 Figura 249. Petición actualización DeviceDefinition 206 Figura 250. Cabecera HTTP actualización DeviceDefinition 206 Figura 251. Nuevo recurso DeviceDefinition 207 Figura 252. Respuesta exitosa actualización DeviceDefinition 207 Figura 253. DeviceModel actualizado en Orion 207 Figura 254. Recurso DeviceDefinition actualizado en el servidor FHIR 208 Figura 255. Recurso DeviceDefinition actualizado en al base de datos 208 Figura 256. Respuesta en caso de que el DeviceDefinition no exista 209 Figura 257. Respuesta en caso de que el DeviceDefinition presente errores 209 Figura 258. Petición actualización Device 209 Figura 259. Cabecera HTTP actualización Device 209 Figura 260. Nuevo recurso Device 210 Figura 261. Respuesta exitosa de actualización Device 210 Figura 262. Recurso Device (FIWARE) actualizado en Orion 210 Figura 263. Recurso Device actualizado en el servidor FHIR 211 Figura 264. Recurso Device actualizado en la base de datos 211 Figura 265. Respuesta en caso de que el Device no exista 211 Figura 266. Respuesta en caso de que el Device presente errores 212 Figura 267. Petición actualización DeviceMetric 212 Figura 268. Cabecera HTTP actualización DeviceMetric 212 Figura 269. Nuevo DeviceMetric 213 Figura 270. Respuesta exitosa de actualización DeviceMetric 213 Figura 271. DeviceModel actualizado en Orion 213 Figura 272. DeviceMetric actualizado en la base de datos 214 Figura 273. Respuesta en caso de que el DeviceMetric no exista 214 Figura 274. Respuesta en caso de que el DeviceMetric presente errores 214 Figura 275. Petición actualización Observation 214 Figura 276. Cabecera actualización Observation 215 Figura 277. Nuevo recurso Observation 215 Figura 278. Respuesta exitosa actualización Observation 215 Figura 279. Recurso Observation actualizado en la base de datos 216 Figura 280. Respuesta en caso de que el Observation no exista 216 Figura 281. Respuesta en caso de que el Observation presente errores 216 32 especificar su cuerpo si es necesario. Una vez el mensaje está fabricado se envía pulsando un botón, y abajo aparece la respuesta a la petición totalmente diseccionada. Se ha usado esta aplicación tanto para probar las funcionalidades de la interfaz REST de la pasarela, como para simular las actualizaciones en los valores de los sensores. Además, se ha creado una colección con todas las peticiones que se utilizan normalmente y es posible compartirla fácilmente a otros desarrolladores. Figura 5. Aplicación Postman 1.3.3 VMware Workstation 15 Player VMware Workstation 15 Player [16] es una herramienta gratuita para ejecutar una máquina virtual en un equipo con Windows o Linux. Se ha usado para lanzar una máquina virtual con la versión de Ubuntu 18.04.3 LTS sobre Windows 10. El desarrollo resulta más cómodo en Ubuntu, además se puede compartir la máquina virtual con todo el trabajo montado listo para funcionar. 33 Figura 6. Aplicación VMware Workstation 15 Player 1.3.4 draw.io draw.io [17] es una aplicación web gratuita, muy integrada con los servicios de almacenamiento en la nube de Google Drive o OneDrive, que permite dibujar diagramas de todo tipo completamente online. Se ha usado a lo largo de este trabajo para crear algunos diagramas de apoyo a las explicaciones. Figura 7. Aplicación draw.io 34 1.4 Descripción de la memoria Una vez que se ha terminado de introducir el proyecto, se va a explicar en detalle las tecnologías que lo han hecho posible en el capítulo 2. En el capítulo 3 se va a profundizar en el trabajo realizado, tanto en la correspondencia entre los recursos de FHIR y FIWARE como en la aplicación java en sí. Explicando sus diferentes partes, el cliente FIWARE, el cliente FHIR, el cliente de la base de datos MongoDB y el controlador REST. En el capítulo 4 se va a explicar cómo se ha montado el escenario completo y se van a realizar pruebas a cada una de las funciones que ofrece la interfaz REST. Finalmente, en el capítulo 5 se enunciarán las conclusiones del proyecto. 35 2 ESTADO DE LA TÉCNICA 2.1 Java Java [18] es un lenguaje de programación de propósito general, concurrente, basado en clases y orientado a objetos. Además, está diseñado para tener el menor número de dependencias de implementación posible. El lenguaje Java, está pensado para que los desarrolladores escriban el programa una sola vez y que lo ejecuten en cualquier dispositivo. Esto significa que el código Java compilado puede ser ejecutado en todas las plataformas que soporten java sin necesidad de ser recompilado. Todo esto es posible porque las aplicaciones de Java se compilan a bytecode que puede ser ejecutado en cualquier máquina virtual de Java (JVM), independientemente de la arquitectura del ordenador que lo ejecuta. Hoy en día, Java es uno de los lenguajes de programación más populares. Se usa principalmente para aplicaciones web cliente-servidor, pero también lo encontramos en el desarrollo de aplicaciones de escritorio y aplicaciones móviles. La elección de Java para realizar este proyecto no se debe solo a su gran popularidad. Es un lenguaje ya conocido, lo que disminuye la curva de aprendizaje inicial para el desarrollo del proyecto. Además, la librería HAPI FHIR [19], que es uno de los ejes de este proyecto, está escrita en este lenguaje. Si a todo esto, le añadimos la versatilidad de frameworks como Spring [20], está claro que Java es una buena elección para este proyecto. 2.2 JSON JSON [13] (JavaScript Object Notation) es un formato de intercambio de datos basado en texto que deriva del lenguaje JavaScript. Normalmente, se usa en servicios web y otras aplicaciones. Es fácil de leer y escribir para los humanos, pero también es fácil de generar y diseccionar para las máquinas. Además, es un formato de texto totalmente independiente del lenguaje de programación utilizado. En JSON solo se definen dos estructuras de datos, objetos y arrays. Un objeto es un conjunto de pares nombre-valor, y un array es una lista de objetos. Además, solo se definen 7 tipos de valores posibles: string, número, objeto, “array”, true, false y null. El siguiente ejemplo se observa un objeto JSON que contiene algunos pares nombre-valor. El valor para “phoneNumbers” es una lista que contiene dos objetos en su interior. 36 Figura 8. Objeto JSON La plataforma FIWARE usa JSON para intercambiar información de contexto. Así como para intercambiar información sobre las suscripciones y en el cuerpo de los mensajes de notificación. En cuanto a FHIR, son válidos tantos los formatos JSON y XML. Al usarse JSON en FIWARE, se ha optado por representar los recursos FHIR y trabajar con ellos en formato JSON. Además, en la base de datos MongoDB se almacenan documentos JSON con información esencial para el funcionamiento de la aplicación. Por lo tanto, los 3 bloques del trabajo, FIWARE, FHIR y la pasarela, usan JSON para transmitir información entre ellos. 2.3 MongoDB MongoDB [7] es una base de datos no relacional de documentos que ofrece una gran escalabilidad, flexibilidad y modelo de consultas e indexación avanzado. Los datos son almacenados en documentos JSON flexibles, es decir, cada documento puede contener diferentes campos y las estructuras de datos se pueden ir modificando. El modelo de documentos concuerda con los objetos del código de la aplicación, lo que facilita trabajar con la información. Las consultas ad-hoc, la indexación y la agregación en tiempo real permiten acceder a los datos y analizarlos con gran eficacia. MongoDB es una base de datos distribuida, fácil de usar y proporciona una elevada disponibilidad, escalabilidad horizontal y distribución geográfica. El modelo de documentos de MongoDB resulta muy fácil de aprender y usar, y proporciona a los desarrolladores todas las funcionalidades que necesitan para satisfacer los requisitos más complejos a cualquier escala. Se proporcionan drivers para más de diez lenguajes, y la comunidad ha desarrollado varias decenas más. Grandes empresas como Amazon, Cisco y Adobe confían y utilizan MongoDB en sus productos. Como se ha comentado, Orion necesita una base de datos MongoDB para almacenar la información. Además, la pasarela necesitaba una base de datos y MongoDB facilitaba mucho el trabajo comparado con una alternativa tradicional de tipo SQL. FIWARE y FHIR usan JSON para transmitir la información. Por lo tanto, la solución basada en plantillas se beneficia enormemente de poder almacenar directamente documentos JSON que pueden ser modificados y enviados de forma fácil y rápida. Finalmente, el framework Spring de Java hace que usar MongoDB sea más fácil todavía. 37 2.4 HTTP HTTP [12] siglas de Hypertext Transfer Protocol, es un protocolo de nivel de aplicación sin estado, usado en sistemas de información distribuidos, colaborativos y de hipertexto. En la RFC 7231 se puede encontrar la definición de la semántica de los mensajes HTTP/1.1, profundizando en los métodos de petición, en los campos de cabecera en la petición, en los códigos de estado de la respuesta y en los campos de cabecera de la respuesta. Así como en el cuerpo de los mensajes y los mecanismos para la negociación del contenido. HTTP es el protocolo a nivel de aplicación que permite que las piezas del sistema se comuniquen entre sí. 2.5 Servicio web RESTful REST [4] equivale a “Representational State Transfer” en inglés, es un estilo arquitectural de software que especifica una serie de restricciones. Al aplicarse a un servicio web, inducen propiedades deseables como pueden ser el rendimiento, la escalabilidad, y la capacidad de cambio que permiten que los servicios web funcionen mejor. Un servicio web que implementa una arquitectura REST se describe como RESTful. En la arquitectura REST, los datos y la funcionalidad son considerados recursos y son accedidos mediante URIs (Uniform Resource Identifiers), normalmente enlaces web tradicionales. La arquitectura REST obliga a usar una arquitectura cliente-servidor y está diseñada para usar un protocolo de comunicación sin estado, típicamente HTTP. Los clientes y los servidores intercambian representaciones de recursos usando una interfaz y protocolo estandarizados. Los siguientes principios hacen que las aplicaciones RESTful sean simples, ligeras y rápidas: • Identificación de recursos mediante URI: un servicio web RESTful expone un conjunto de recursos que identifican los objetivos de la interacción con sus clientes. Los recursos se identifican mediante URIs, que proporcionan un espacio de direccionamiento global para el descubrimiento de recursos y servicios. • Interfaz uniforme: los recursos se manipulan usando un conjunto fijado de 4 operaciones de lectura, escritura, actualización y borrado. Mediante las operaciones PUT, GET, POST y DELETE. PUT puede tanto crear como actualizar un recurso si este ya existía con anterioridad. El recurso puede ser después borrado por DELETE. GET recupera el estado actual del recurso en alguna representación. POST también puede ser usado tanto para crear como actualizar recursos. Esto lleva a confusión con el método PUT. La respuesta rápida sería que POST es para crear y PUT para actualizar recursos. La principal diferencia es que el método PUT es idempotente, esto significa que producirá el mismo resultado si se ejecuta varias veces. POST no lo es, ya que al ejecutarlo varias veces estás creado varios elementos. Normalmente se sigue lo siguiente: o POST se utiliza para crear recursos y PUT para actualizar recursos ya existentes o PUT se usa cuando se conocen los identificadores de los recursos o POST se utiliza cuando es el servidor el que controla la generación de identificadores y URLs de los recursos o Como ejemplo: ▪ PUT/ítems/1/update ▪ POST/ítems/create 38 • Mensajes auto descriptivos: los recursos están desacoplados de su representación para que su contenido pueda ser accedido en una variedad de formatos, como HTML, XML, texto plano, PDF, JPEG, JSON entre otros. Los metadatos de los recursos existen y son usados para, por ejemplo, detectar errores de transmisión, negociar el formato adecuado de presentación y para realizar control de acceso o autenticación. • Interacciones con estado mediante hiperenlaces: cada interacción con un recurso es sin estado, esto quiere decir que los mensajes de petición son auto contenidos. Las interacciones con estado se basan en el concepto explícito de transferencia de estado. Existen una serie de técnicas para la transferencia de estado, como pueden ser la sobreescritura de URI, las cookies, y campos ocultos en formularios. Estas técnicas permiten, por ejemplo, mantener el estado de la sesión de un usuario sobre HTTP que es un protocolo sin estado. Tanto FIWARE como FHIR definen una interfaz REST. Además, la pasarela Java también define su propia interfaz REST que permite al gestor crear, obtener, actualizar y borrar familias de dispositivos y dispositivos concretos. 2.6 Spring Framework Spring [20] es un framework de código abierto que se utiliza para el desarrollo de aplicaciones Java. Un framework en programación es el resultado de la evolución de la ingeniería del software, estos son creados por programadores para programadores, con la finalidad de estandarizar el trabajo, resolver, agilizar y manejar los problemas y complejidades que van apareciendo. Creando así, en la comunidad de desarrolladores, un abanico de posibilidades para una creación cada vez más evolucionada de aplicaciones. Spring permite desarrollar aplicaciones de manera más rápida y eficaz, eliminando tareas repetitivas y ahorrando líneas de código. Fue escrito originalmente para la plataforma J2EE de Java, plataforma orientada al desarrollo de aplicaciones web y ha ido evolucionando rápidamente hasta el día de hoy, donde podemos encontrar diferentes ramas de desarrollo de la mano de SpringSource y todo su equipo de desarrolladores. Spring en la actualidad es la referencia en el mundo de los frameworks de programación para los desarrolladores web de todo el mundo. Su éxito se fundamenta en la constante labor de investigación e innovación que realiza su equipo de desarrollo. Spring fue una elección fácil ya que ofrecía librerías de gran utilidad para afrontar varios problemas del proyecto. Además, es uno de los frameworks más populares y recomendados del lenguaje Java. Ha ayudado, entre otras cosas, a lanzar de forma sencilla una aplicación web sobre Tomcat, ha facilitado la programación de un cliente REST, la interacción con la base de datos MongoDB y la creación de un controlador REST. 2.6.1 Spring Boot Spring Boot [21] es un proyecto construido sobre el mencionado Spring Framework. Proporciona una forma más fácil y rápida de construir y ejecutar aplicaciones autónomas y basadas en la web. Dentro del Spring Framework fundamental, hay que configurar muchas cosas a mano mediante archivos XML, esto es una de las cosas que Spring Boot facilita. Al iniciar un proyecto Java, el desarrollador tiene que tomar una serie de decisiones, como el framework a usar, la herramienta de logging, el servidor web, etc. No obstante, al final la mayoría de los desarrolladores usan las mismas herramientas una y otra vez. Lo que hace Spring Boot es 39 que carga y configura todas estas herramientas de la forma más genérica posible. Así, los desarrolladores no tienen que configurar lo mismo una y otra vez. Obviamente, esta configuración inicial puede ser posteriormente personalizada por el desarrollador, para satisfacer sus necesidades. En este proyecto se ha usado Spring Boot principalmente para el lanzamiento y despliegue de la aplicación web, ya que incluye un servidor web Tomcat embebido. Además, Spring Boot analiza automáticamente los componentes de la pasarela y realiza las configuraciones necesarias. En este caso un componente @RestController, para crear la interfaz REST. Además, configura también de forma automática la conexión a la base de datos MongoDB. 2.7 Maven Maven [22] es una herramienta software para la gestión y construcción de proyectos Java. Maven utiliza un Project Object Model (POM), que consiste en un documento XML que describe el proyecto software a construir, sus dependencias de otros módulos y componentes externos, y el orden de construcción de los elementos. Viene con objetivos predefinidos para realizar ciertas tareas claramente definidas, como la compilación de código y su empaquetado. Una característica principal de Maven es que está listo para usar en red. El motor incluido en su núcleo puede dinámicamente descargar plugins de un repositorio, el cual provee acceso a muchas versiones de diferentes proyectos Open Source en Java, de Apache, y otras organizaciones y desarrolladores. Este repositorio y su sucesor reorganizado, el repositorio Maven 2, pugnan por ser el mecanismo de facto de distribución de aplicaciones en Java. Las librerías de Spring usan archivos de configuración POM que resuelven todas las dependencias necesarias y facilitan inmensamente el trabajo. Además, el uso de herramientas como Maven, o similares como puede ser Gradle, es de gran necesidad en cualquier proyecto Java de cierta complejidad. Este es un fragmento del archivo de configuración POM de la pasarela: Figura 9. Fragmento del archivo pom.xml 40 2.8 NGSIv2 Specification NGSI [6] es una especificación propuesta por la OMA (Open Mobile Alliance) que se basa en una API Rest para comunicarse mediante peticiones HTTP. NGSI son las siglas de Next Generation Service Interface, que traducido resulta “interfaz de servicio de última generación”. Recordar el concepto de información de contexto mencionado en la introducción, “información relevante sobre lo que está pasando en un momento dado, procedente de diferentes fuentes”. NGSI está pensada para controlar el ciclo de vida completo de la información de contexto, incluyendo actualizaciones, peticiones, registros y suscripciones. Esta API define lo siguiente: • Un modelo de datos para la información de contexto, basado en el concepto de entidades de contexto. • Una interfaz de datos de contexto para el intercambio de información por medio de peticiones, suscripciones y actualizaciones. • Una interfaz de disponibilidad del contexto, para intercambiar información de cómo obtener la propia información de contexto. 2.8.1 Modelado de la información de contexto Los elementos principales en el modelo de datos de NGSI son las entidades de contexto, los atributos y los metadatos, como se puede observar en la figura de abajo. Figura 10. Componentes de una entidad de contexto 2.8.1.1 Entidades de contexto Las entidades de contexto, o simplemente las entidades, son el centro de gravedad en el modelo de información FIWARE NGSI. Una entidad representa una cosa, por ejemplo, cualquier objeto físico o lógico. Puede ser un sensor, una persona, una habitación, etc. Cada entidad posee un identificador de entidad único. Además, el sistema de tipos de FIWARE NGSI permite a las entidades tener un tipo de entidad. Los tipos de entidad están pensados para describir el tipo del objeto representado por la entidad. Por ejemplo, una entidad de contexto con el identificador “sensor-2000” podría tener el tipo “sensorTemperatura”. Cada entidad se identifica de forma unívoca mediante la combinación de su identificador (id) y su tipo (type). 2.8.1.2 Atributos de contexto Los atributos de contexto son propiedades de las entidades de contexto. Por ejemplo, la velocidad de un coche se podría modelar como el atributo “velocidad_actual” de la entidad “coche-100”. En el modelo de datos NGSI, los atributos tienen un nombre, un tipo, un valor y metadatos asociados. El nombre del atributo describe qué tipo de propiedad representa el valor del atributo, como “velocidad_actual” en el caso del coche. El tipo del atributo representa el tipo del valor 41 NGSI del valor del atributo. Finalmente, se encuentran el valor del atributo en sí y una serie de metadatos opcionales que facilitan información sobre propiedades como el proveedor de la información, su precisión o su marca de tiempo entre otros. 2.8.1.3 Metadatos de contexto Los metadatos de contexto se usan en varios lugares de FIWARE NGSI, siendo uno de ellos el caso descrito arriba. Es decir, una parte opcional que proporciona información extra del atributo. La estructura de los metadatos es la siguiente. • Un nombre, que describe el papel del metadato en el lugar que ocurre. • Un tipo, describiendo el tipo del valor NGSI del valor del metadato. • Un valor, que contiene el metadato en sí. 2.8.2 Representación JSON de la información Una entidad se representa mediante un objeto JSON con la siguiente sintaxis: • El identificador de las entidades se especifica mediante la propiedad “id” del objeto, se modela como un string. • El tipo de la entidad se especifica por la propiedad “type”, también modelado como string. • Los atributos de la entidad se especifican mediante propiedades adicionales, sus nombres son los del atributo que representan y sus posibles representaciones se discutirán en el siguiente apartado. Obviamente, los nombres id y type están reservados y no podrán ser usados como nombres de atributos. Un ejemplo de esta sintaxis sería: Figura 11. Entidad NGSI en JSON Por lo tanto, la representación normalizada de las entidades siempre incluye el campo id y type. Además de un número variable de atributos de la entidad. Existen otros tipos de representaciones, como son la simplificada o la parcial, que veremos más adelante. La especificación de cada operación incluye detalles sobre qué representación se espera como entrada, o qué representación se proporcionará a la salida. 2.8.2.1 Representación JSON de los atributos Un atributo se presenta mediante un objeto JSON con la siguiente sintaxis: • El valor del atributo se especifica mediante la propiedad “value”, cuyo valor puede ser cualquier tipo de dato soportado por JSON. • El tipo NGSI del atributo es especificado por la propiedad “type”, cuyo valor es un string conteniendo el tipo. 48 Es obligatorio usar la cabecera HTTP “Ngsiv2-AttrsFormat” en los mensajes de notificación con el valor del formato de la suscripción asociada. Así, los que reciban la notificación son conscientes del formato sin necesidad de procesar el cuerpo del mensaje. 2.8.6 Suscripciones Una suscripción en FIWARE se representa mediante un objeto JSON subscription con los siguientes campos: • “id”: identificador único de la suscripción. Es creado automáticamente cuando se crea el objeto Subscription en el Context Broker. • “description”: es un campo de texto libre usado por el cliente para describir la suscripción. Este campo es opcional. • “subject”: es un objeto que describe qué entidades se verán afectadas por la suscripción. • “notification”: es un objeto que describe la notificación que debe enviar el sistema cuando salte la suscripción. • “expires”: indica la fecha en la que caduca la suscripción en formato ISO8601. En caso de no aparecer este campo, la suscripción sería permanente. • “status”: indica el estado de la suscripción. Puede ser active (para las suscripciones activas) o inactive (para las suscripciones inactivas). En caso de no especificar este campo a la hora de la creación de la suscripción, por defecto las nuevas suscripciones se crean con este campo igual a active. Esto puede ser cambiado a posteriori por el cliente. En cuanto a las suscripciones caducadas, este campo toma el valor de expired y no puede ser cambiado por el cliente. Además, en caso de que la suscripción sufra problemas a la hora de notificar, este campo toma el valor de failed. En cuanto se solucione el problema vuelve a cambiarse a active. • “throttling”: indica el periodo mínimo de tiempo en segundos que debe pasar entre dos notificaciones consecutivas. Este campo es opcional. Un objeto “subject” contiene los siguientes subcampos: • “entities”: es una lista de objetos, cada uno de ellos con los siguientes subcampos. Aclarar que las posibilidades de los patrones son muy extensas, no se van a especificar en detalle porque solo se ha usado un tipo muy concreto que es el patrón “^prueba”, para filtrar los identificadores de las entidades por su comienzo: o “id” or “idPattern”: identificador o patrón de las entidades afectadas. No se pueden usar ambos al mismo tiempo, pero al menos uno de los dos tiene que estar presente obligatoriamente. Un ejemplo de patrón sería “.*” para seleccionar todos los identificadores del servidor. o “type” or “typePattern”: tipo o patrón aplicado al tipo de las entidades afectadas. No se pueden usar ambos a la vez. En caso de no aparecer ninguno, significa que cualquier tipo es válido. • “condition”: condición que desencadena la notificación. Este campo es opcional y puede contener además otras dos propiedades opcionales también. 49 o “attrs”: lista de nombres de atributos. Esto implica que cualquier cambio en los atributos indicados en esta lista, dentro de las entidades seleccionadas por el campo entities, desencadenará una notificación. o “expression”: una expresión compuesta por alguna o algunas de estas condiciones: “q”, “mq”, “georel”, “geometry” y “coords”. Estas condiciones sirven para realizar filtros. ▪ “q”: es utilizada para filtrar valores de atributos. ▪ “mq”: es utilizada para filtrar valores de metadatos. ▪ “georel”: es utilizada para especificar una relación espacial. ▪ “geometry”: es utilizada para definir una forma de referencia usada para “resolver” la petición (point,line,polygon,box). ▪ “coords: debe ser un string, que contenga una lista de pares de coordenadas geográficas separadas por “;”. Las coordenadas tienen que concordar con la geometría indicada en geometry. Un objeto notification tiene los siguientes subcampos: • “attrs” or “exceptAttrs”: no pueden estar ambos presentes al mismo tiempo o “attrs”: lista de atributos que deben ser incluidos en el mensaje de notificación. Una lista vacía significa que todos los atributos deben ser incluidos. o “exceptAttrs”: lista de atributos que deben ser excluidos del mensaje de notificación. Por lo tanto, el mensaje de notificación incluye todos los atributos menos los indicados en esta lista. • “http” or “httpCustom”: uno de los dos tiene que estar presente, pero no ambos al mismo tiempo. Este campo se usa para especificar parámetros del protocolo HTTP que deben ser aplicados en el envío de las notificaciones. • “attrsFormat” (opcional): especifica cómo deben ser representadas las entidades dentro de las notificaciones. Los valores acepteptados son: o normalized o keyValues o values o En caso de que el campo attrsFormat tome un valor diferente a los anteriores el sistema Orion dará un error en la suscripción. • “metadata” (opcional): lista de los metadatos que deben ser incluidos en los mensajes de notificación. • “timesSent”: este campo no es editable, solo está presente cuando hacemos un GET a la suscripción. Representa el número de notificaciones mandadas como resultado de esta suscripción. • “lastNotification”: este campo no es editable, solo está presente cuando hacemos un GET a la suscripción. Representa el instante en el que se realizó la última notificación en formato ISO8601. • “lastFailure”: este campo no es editable, solo está presente cuando hacemos un GET a la suscripción. Representa el instante en el que tuvo lugar el último fallo en el formato ISO8601. Este campo no está presente en el caso de que nunca haya habido un problema con las notificaciones. 50 • “lastSuccess”: Este campo no es editable, solo está presente cuando hacemos un GET a la suscripción. El instante de tiempo, según el formato ISO8601, en el que se realizó la última notificación con éxito. Este campo no está presente si la suscripción nunca ha tenido una notificación exitosa. Un objeto “http” tiene los siguientes subcampos: • “url”: URL que referencia al servicio que debe ser invocado cuando se genera una notificación. Un servidor que cumpla NGSIv2, deber soportar el esquema http. Otros esquemas también son posibles. Un objeto “httpCustom” tiene los siguientes subcampos: • “url”: igual que en el campo de arriba. • “headers”: este campo es opcional. Mapa de las cabeceras HTTP que deben ser incluidas en los mensajes de notificación. • “qs”: este campo es opcional. Mapa de los parámetros de la petición URL que deben ser incluidos en los mensajes de notificación. • “method”: este campo es opcional. El método HTTP a usar cuando se envía la notificación. Por defecto es POST. Sólo son válidos los métodos HTTP. En caso de especificar un método no válido, saltaría el error 400 Bad Request. • “payload”: este campo es opcional. El payload que debe ser usado en las notificaciones. En caso de ser omitido, se usa el payload por defecto. 2.8.7 Respuestas en caso de error En el cuerpo del mensaje de error se encuentra un objeto JSON con los siguientes campos: • error: es un campo obligatorio, modelado por un string. Consiste en una descripción textual del error. • description: es un campo opcional, modelado por un string. Ofrece información adicional sobre el error. Todas las implementaciones de un servidor NGSIv2 están obligadas a usar los siguientes códigos de estado HTTP y los siguientes textos en el campo error. No obstante, el texto usado en el campo description depende de la implementación. • En caso de que el objeto JSON en el cuerpo de la petición no pueda ser procesado se devuelve ParseError (400). • Los errores causados únicamente por la petición (no dependen del estado del servidor), ya sea en los parámetros de la URL o en el cuerpo, devuelven BadRequest (400). o Excepción: el primer caso es una excepción de este caso. • El intento de exceder el límite del índice espacial devuelve NoResourceAvailable (413). • En caso de ambigüedad porque la petición puede referirse a más de un recurso, se devuelve TooManyResults (409). Esto puede ocurrir si no se indica el tipo de la entidad. 51 • Si el recurso identificado por la petición no se encuentra, se devuelve NotFound (404). • En caso de errores debidos al tipo de petición combinados con el estado del recurso. Por ejemplo, cuando se intenta realizar un POST con el parámetro options=append en un atributo ya existente. Esto resulta en el error Unprocessable (422). o Excepciones: Los casos anteriores que devuelven 404, 409 o 413. • Los errores debidos a la capa HTTP son los siguientes: o HTTP 405 Method Not Allowed, se corresponde con MethodNotAllowed (405). o HTTP 411 Length Required, se corresponde con ContentLengthRequired (411). o HTTP 413 Request Entity Too Large, se corresponde con RequestEntityTooLarge (413). o HTTP 415 Unsupported Media Type, se corresponde con UnsupportedMediaType (415). 2.8.8 Puntos de entrada de la API NGSIv2 2.8.8.1 Crear una entidad Figura 21. Petición POST para crear una entidad Para crear una entidad se envía un mensaje HTTP POST. La dirección de destino se forma cogiendo la URL del servidor NGSIv2 y añadiéndole “/v2/entities”. Además, existe un parámetro opcional llamado “options” cuyos valores posibles son “keyValues” y “upsert”. Cuando se usa “keyValues”, el cuerpo de la petición usa la representación simplificada “keyValues” explicada con anterioridad. Cuando se usa “upsert”, la entidad se actualiza si ya existe en el sistema. Si no se usa “upsert” y la entidad ya existe en el sistema se devuelve el error 442 Unprocessable Entity. Destacar que el mensaje debe usar la cabecera HTTP “Content-Type:application/json” y que el cuerpo del mensaje es un objeto JSON que represente a la entidad que debe ser creada. Las respuestas posibles son las siguientes: • Las operaciones con éxito usan el código de respuesta 201, si no se usa la opción “upsert”, o el código 204 en el caso de que se use “upsert”. El mensaje de respuesta incluye una cabecera llamada “Location” con la URL de la entidad creada. • Ver la sección anterior “Respuestas en caso de error”. 52 2.8.8.2 Recuperar una entidad por su id Figura 22. Petición GET para recuperar una entidad Para recuperar una entidad por su id, se envía un mensaje HTTP GET. La dirección de destino se forma cogiendo la URL del servidor NGSIv2 y añadiéndole “v2/entities/{identificador de la entidad}”. Encontramos los siguientes parámetros: • type: es el tipo de la entidad, sirve para evitar ambigüedades en el caso de que varias entidades de diferente tipo tengan el mismo identificador. • attrs: lista de los atributos de la entidad solicitados, son los únicos atributos que se devuelven. En el caso de omitirse este campo, se incluyen en la respuesta todos los atributos de la entidad en un orden arbitrario. • metadata: una lista de nombres de metadatos que deben ser incluidos en la respuesta. • options: los posibles valores de este campo son “keyValues” y “values”. Permite elegir algún modo especial de representar los datos en la respuesta. La respuesta a esta petición es un objeto en formato JSON que representa a la entidad identificada por el campo id. Esta operación solo debe devolver un único elemento entidad. En el caso en el que haya varias entidades asociadas al mismo identificador, se devuelve un mensaje de error, con el código de estado HTTP 409, indicando que ha habido un conflicto. Esto ocurre cuando no se indica el tipo de la entidad en el campo type. Las operaciones con éxito devuelven el código 200 OK. El resto de los códigos y mensajes de error están explicados la sección anterior “Respuestas en caso de error”. 2.8.8.3 Recuperar atributos de una entidad Figura 23. Petición GET para recuperar atributos de una entidad Esta petición es muy parecida a la anterior. La primera diferencia es que a la URL se le añade “/attrs” para indicar que en la respuesta deben omitirse los campos “id” y “type”. La segunda es obviamente que en la respuesta solo se encuentran los atributos de la entidad y no la entidad completa como en el caso de arriba. El resto es todo igual. 2.8.8.4 Actualizar o añadir atributos a una entidad Figura 24. Petición POST para actualizar/añadir atributos Para actualizar o añadir atributos a una entidad enviamos un mensaje HTTP POST. Hay que recalcar que la elección del método POST la establece el estándar NGSIv2, ya que se puede pensar que sería más correcto utilizar el método PUT. La dirección de destino se forma cogiendo como base la URL del servidor NGSIv2 y añadiéndole “v2/entities/{identificador de la entidad}”. Los parámetros son: • type: es el tipo de la entidad, sirve para evitar ambigüedades en el caso de que varias entidades de diferente tipo tengan el mismo identificador. • options: los posibles valores de este campo son “keyValues” y “append”. 53 El cuerpo de la petición consiste en un objeto JSON representado los atributos que añadir o actualizar. Si no se usa “append”, los atributos de la entidad se actualizan (si existían previamente) o se añaden (si no existían con anterioridad) con los encontrados en el cuerpo del mensaje. En el caso de usar “append”, todos los atributos del cuerpo del mensaje que no existieran previamente son añadidos a la entidad. Además, si hubiera algún atributo del mensaje que ya existiera en la entidad, se devolvería un mensaje de error. Las operaciones con éxito usan el código 204. Los códigos y mensajes de error están explicados la sección anterior “Respuestas en caso de error”. 2.8.8.5 Actualizar atributos ya existentes de una entidad Figura 25. Petición PATCH para actualizar atributos Para actualizar atributos ya existentes de una entidad, enviamos un mensaje HTTP PATCH. La dirección de destino la conseguimos añadiéndole a la URL base del servidor NGSIv2 “/v2/entities/{identificador de la entidad}/attrs”. Tenemos dos parámetros: • type: es el tipo de la entidad, sirve para evitar ambigüedades en el caso de que varias entidades de diferente tipo tengan el mismo identificador. • options: el único valor posible de este campo es “keyValues”. El cuerpo de la petición es un objeto en formato JSON representando los atributos para actualizar. Es decir, consiste en una entidad, pero sin los campos id y type. Estos campos se prohíben en esta petición. Los atributos de la entidad se actualizan con los del cuerpo del mensaje. En el caso de que uno o más atributos presentes en el mensaje no existan en la entidad, se devuelve un mensaje de error. Hay que aclarar que los atributos ya existentes en la entidad que no son mencionados en esta operación se mantienen en la entidad. Esta es la diferencia con la siguiente petición donde se utiliza PUT en lugar de PATCH. Las operaciones con éxito usan el código 204. Los códigos y mensajes de error están explicados la sección anterior “Respuestas en caso de error”. 2.8.8.6 Sustituir todos los atributos de una entidad Figura 26. Petición PUT para sustituir atributos Para sustituir todos los atributos de una entidad, enviamos un mensaje HTTP PUT. La dirección de destino la conseguimos añadiéndole a la URL base del servidor NGSIv2 “/v2/entities/{identificador de la entidad}/attrs”. Tenemos dos parámetros: • type: es el tipo de la entidad, sirve para evitar ambigüedades en el caso de que varias entidades de diferente tipo tengan el mismo identificador. • options: el único valor posible de este campo es “keyValues”. El cuerpo de la petición es un objeto en formato JSON representando los atributos para actualizar. No se permiten los campos “id” ni “type”. Los atributos previamente existentes de la entidad se eliminan y son sustituidos por los del cuerpo del mensaje. Es decir, cualquier atributo que existía antes es eliminado si no aparecen en el objeto JSON de la nueva solicitud. 54 Las operaciones con éxito usan el código 204. Los códigos y mensajes de error están explicados la sección anterior “Respuestas en caso de error”. 2.8.8.7 Eliminar una entidad Figura 27. Petición DELETE para eliminar una entidad Para eliminar una entidad enviamos un mensaje HTTP DELETE. La URI destino se forma cogiendo la URL base del servidor NGSIv2 y añadiendo “/v2/entities/{identificador de la entidad}”. Tenemos un único parámetro adicional para indicar el tipo de la entidad a eliminar. En caso de éxito, la respuesta es un mensaje HTTP con el código 204. Los códigos y mensajes de error están explicados la sección anterior “Respuestas en caso de error”. Como recordatorio, si no se especifica el tipo de la entidad y hay ambigüedad en la petición, se devuelve un mensaje de error. 2.8.8.8 Recuperar un atributo concreto de una entidad Figura 28. Petición GET para recuperar un atributo concreto Para recuperar los datos de un atributo concreto dentro de una entidad, enviamos un mensaje HTTP GET. La URL destino se obtiene con la dirección base del servidor NGSIv2, más “v2/entities/{id de la entidad}/attrs/{nombre del atributo}”. Encontramos los siguientes parámetros: • type: es el tipo de la entidad, sirve para evitar ambigüedades en el caso de que varias entidades de diferente tipo tengan el mismo identificador. • attrName: nombre del atributo a recuperar • metadata: una lista de nombres de metadatos que deben ser incluidos en la respuesta. Esta petición devuelva un objeto JSON con los datos del atributo. En caso de una operación exitosa se devuelve un mensaje con el código 200 OK. Los códigos y mensajes de error están explicados la sección anterior “Respuestas en caso de error”. En el apartado 2.8.8.3 “Recuperar atributos de una entidad”, se pueden recuperar o todos los atributos de la entidad o una selección de ellos. En este caso sólo se recupera un único atributo. La diferencia con el apartado 2.8.8.11 “Recuperar el valor de un atributo concreto de una entidad” consiste en que en ese apartado solo se obtiene el valor del campo “value” dentro del atributo. Mientras que aquí se obtienen todos los otros campos del atributo también. 2.8.8.9 Actualizar un atributo concreto de una entidad Figura 29. Petición PUT para actualizar un atributo concreto Para actualizar los datos de un atributo dentro de una entidad, enviamos un mensaje HTTP PUT. La URL destino se obtiene con la dirección base del servidor NGSIv2, más “v2/entities/{id de la entidad}/attrs/{nombre del atributo}”. Encontramos los siguientes parámetros: • type: es el tipo de la entidad, sirve para evitar ambigüedades en el caso de que varias entidades de diferente tipo tengan el mismo identificador. • attrName: nombre del atributo a actualizar. 55 El cuerpo de la petición es un objeto en formato JSON representando los nuevos datos del atributo. Los datos anteriores son eliminados y sustituidos por los nuevos del cuerpo del mensaje. En caso de operación con éxito, la respuesta es un mensaje con el código 204. Los códigos y mensajes de error están explicados la sección anterior “Respuestas en caso de error”. 2.8.8.10 Eliminar un atributo concreto de una entidad Figura 30. Petición DELETE para eliminar un atributo concreto Para eliminar un solo atributo de una entidad, enviamos un mensaje HTTP DELETE. La URL destino la conseguimos con la dirección base del servidor NGSIv2 y añadiéndole “/v2/entities/{identificador de la entidad}/attrs/{nombre del atributo}”. Encontramos los siguientes parámetros: • type: es el tipo de la entidad, sirve para evitar ambigüedades en el caso de que varias entidades de diferente tipo tengan el mismo identificador. • attrName: nombre del atributo a eliminar. En caso de que se haya borrado con éxito, recibimos un mensaje con el código 204. Los códigos y mensajes de error están explicados la sección anterior “Respuestas en caso de error”. 2.8.8.11 Recuperar el valor de un atributo concreto de una entidad Figura 31. Petición GET para recuperar el valor de un atributo Para recuperar únicamente el valor de un atributo concreto, enviamos un mensaje HTTP GET. La URL destino se forma con la URL base del servidor NGSIv2 y añadiéndole “/v2/entities/{identificador de la entidad}/attrs/{nombre del atributo}/value”. Encontramos los siguientes parámetros: • type: es el tipo de la entidad, sirve para evitar ambigüedades en el caso de que varias entidades de diferente tipo tengan el mismo identificador. • attrName: nombre del atributo a recuperar. Esta operación devuelve el valor del atributo seleccionado: • Si el valor es un objeto o lista JSON: o Si la cabecera HTTP “Accept” puede ser expandida a “application/json” o “text/plain” se devuelve el valor en formato JSON con una respuesta de tipo “application/json” o “text/plain”. Se elige la que esté primero en la cabecera “Accept” o “application/json” en el caso “Accept: */*”. o Si no se cumple lo de arriba se devuelve el error HTTP : “406 Not Acceptable: accepted MIME types: application/json, text/plain”- • Si el valor es un string, numero, null o booleano: o Si la cabecera HTTP “Accept” se puede expandir a “text/plain” se devuelve el valor como text plano. En el caso de ser un string, se usan comillas dobles al inicio y al final. o Si no se cumple lo de arriba se devuelve el error HTTP: “406 Not Acceptable: accepted MIME types: text/plain”. 56 Las operaciones con éxito usan el código 200 OK. Los códigos y mensajes de error están explicados la sección anterior “Respuestas en caso de error”. 2.8.8.12 Actualizar el valor de un atributo concreto de una entidad Figura 32. Petición PUT para actualizar el valor de un atributo Para actualizar únicamente el valor (campo “value”) de un atributo concreto, enviamos un mensaje HTTP PUT. La URL destino se forma con la URL base del servidor NGSIv2 y añadiéndole “/v2/entities/{identificador de la entidad}/attrs/{nombre del atributo}/value”. Encontramos los siguientes parámetros: • type: es el tipo de la entidad, sirve para evitar ambigüedades en el caso de que varias entidades de diferente tipo tengan el mismo identificador. • attrName: nombre del atributo a actualizar. En el cuerpo de la petición encontramos el nuevo valor para el atributo. • Si el tipo MIME del cuerpo de la petición es “application/json”, entonces el valor del atributo se iguala al objeto o lista JSON codificada en el cuerpo. Si el JSON no es válido se devuelve un mensaje de error. • Si el tipo MIME del cuerpo de la petición es “text/plain”, entonces se aplica el siguiente algoritmo: o Si el cuerpo empieza y termina con comillas dobles, el valor se considera como un string. Hay que aclarar que las comillas no son parte del string. o Si es “true” o “false”, el valor se toma como un booleano. o Si es “null”, se toma el valor null. o En caso de que estos 3 primeros tests fallen, se interpreta como un número. o En caso de no ser un número válido, se devuelve un mensaje de error y el atributo no se modifica. El tipo MIME del cuerpo de la petición se indica en la cabecera HTTP “Content-Type”. En caso de éxito se devuelve un mensaje con el código 204. Los códigos y mensajes de error están explicados la sección anterior “Respuestas en caso de error”. Realmente, aunque el objetivo de esta petición sea modificar el campo value del atributo, de forma indirecta posiblemente también se cambie su tipo NGSI como se indica, por ejemplo, en el caso del tipo MIME “text/plain”. 2.8.8.13 Listar suscripciones Figura 33. Petición GET para listar suscripciones Para obtener una lista de las suscripciones existentes, enviamos un mensaje HTTP GET. La URL destino se forma con la URL base del servidor NGSIv2 y añadiéndole “/v2/subscriptions”. Encontramos los siguientes parámetros: • limit: sirve para limitar el número de suscripciones que deben ser recuperadas. • offset: sirve para saltar un número de suscripciones. • options: la única opción disponible es “count”. 57 Se devuelve una lista JSON con todos los objetos suscripción presentes en el sistema. En caso de éxito se devuelve un mensaje con el código 200 OK. Los códigos y mensajes de error están explicados la sección anterior “Respuestas en caso de error”. 2.8.8.14 Crear suscripciones Figura 34. Petición POST para crear una suscripción Para crear una nueva suscripción enviamos un mensaje HTTP POST. La URL destino se forma con la URL base del servidor NGSIv2 y añadiéndole “/v2/subscriptions”. No tenemos ningún parámetro adicional. En el cuerpo de la petición encontramos la suscripción en formato JSON. En caso de éxito se devuelve un mensaje con el código 201 Created. Los códigos y mensajes de error están explicados la sección anterior “Respuestas en caso de error”. 2.8.8.15 Recuperar una suscripción según su ID Figura 35. Petición GET para recuperar una suscripción Para obtener una suscripción según su ID enviamos un mensaje HTTP GET. Las URL destino es la dirección base del servidor más “/v2/subscriptions/{identificador de la suscripción}”. La respuesta es la suscripción representada como un objeto JSON. En caso de éxito se devuelve un mensaje con el código 200 OK. Los códigos y mensajes de error están explicados la sección anterior “Respuestas en caso de error”. 2.8.8.16 Actualizar una suscripción Figura 36. Petición PATCH para actualizar una suscripción Para actualizar una suscripción usamos el mensaje HTTP PATCH. Las URL destino es la dirección base del servidor más “/v2/subscriptions/{identificador de la suscripción}”. En el cuerpo del mensaje se incluye los campos de la suscripción que deben ser actualizados. En caso de éxito se devuelve un mensaje con el código 204 No Content. Los códigos y mensajes de error están explicados la sección anterior “Respuestas en caso de error”. Aclarar que no podría usar PUT ya que el estándar NGSI obliga a usar PATCH. 2.8.8.17 Borrar una suscripción Figura 37. Petición DELETE para borrar una suscripción Para borrar una suscripción, usamos un mensaje HTTP DELETE. Las URL destino es la dirección base del servidor más “/v2/subscriptions/{identificador de la suscripción}”. En caso de éxito se devuelve un mensaje con el código 204 No Content. Los códigos y mensajes de error están explicados la sección anterior “Respuestas en caso de error”. 64 2.10 FHIR 2.10.1 Recurso Device Un Device [8], por definición, es un tipo de objeto que se fabrica para prestar asistencia, sin ser cambiado sustancialmente durante su actividad. Puede tener carácter médico o no. Es un recurso administrativo que representa instancias individuales de un tipo de dispositivo y su localización. Es referenciado por otros recursos, por ejemplo, para dejar constancia de qué dispositivo realizó una acción como puede ser un procedimiento u observación médica. También puede ser referenciado cuando se prescriben dispositivos a un paciente concreto, además es usado para guardar y transmitir el UDI (Unique Device Identifier) asociado a un dispositivo, como puede ser un implante médico. La organización americana FDA [28] (Food and Drugs Administration) es la encargada de establecer este UDI para identificar todos los dispositivos médicos vendidos en los Estados Unidos desde su fabricación. Este identificador no es el que usa este sistema para diferenciar una entidad de otra, sino que utiliza el atributo identifier dentro de Device. Este identificador es más global ya que el sistema UDI solo funciona en los Estados Unidos. Los recursos que se relacionan directamente con Device son los siguientes, • Device (este mismo recurso). • DeviceDefinition - describe un tipo de dispositivo (no es una instancia física). • DeviceMetric - describe una capacidad de medida, cálculo o configuración de un dispositivo médico. En FHIR, el Device, al ser un recurso administrativo no cambia mucho y tiene toda la información del fabricante, esto contrasta con el DeviceMetric, el cual modela la parte física, como puede ser el estado operacional del dispositivo, así que es mucho más propenso a cambios. 2.10.2 Recurso DeviceDefinition Un recurso de tipo DeviceDefinition [9], por definición, describe las características y las capacidades de un dispositivo médico. Se puede decir que es como la definición de catálogo de un dispositivo La diferencia entre Device y DeviceDefinition es que Device fue pensado para refererirse a instancias físicas de un tipo de dispositivo, por lo tanto, tiene atributos como pueden ser la localización física, número de lote o una referencia a un paciente concreto, los cuáles no son contemplados en DeviceDefinition. En definitiva, Device es un dispositivo concreto y DeviceDefinition proporciona la información del tipo o categoría al que pertenece. Este recurso normalmente es referenciado por un Device. 2.10.3 Recurso DeviceMetric Como se ha mencionado con anterioridad, un DeviceMetric [10], por definición, describe una capacidad de medida, cálculo o configuración de un dispositivo. Por un lado, describe propiedades estáticas obligatorias que caracterizan, ya sea de forma directa o derivada, cuantitativa o cualitativa, una medida de una señal biológica o un cálculo producido por un dispositivo médico. Por otro, también puede ser usado para describir propiedades no estáticas, pero que son muy importantes para la medida como pueden ser el estado operacional, el modo de medida utilizado, la última fecha en la que fue calibrado, entre otros. 65 Este tipo de recurso está íntimamente relacionado con Device, así como otro tipo de recurso que recibe el nombre de Observation, que veremos a continuación. 2.10.4 Recurso Observation Un recurso de tipo Observation [11], por definición, contiene medidas y afirmaciones simples hechas sobre un paciente, dispositivo u otro sujeto. Las observaciones son un elemento central en el sistema médico, son utilizadas para respaldar un diagnóstico, la monitorización del progreso, para determinar puntos de referencia y patrones, e incluso para capturar características demográficas. La inmensa mayoría de las observaciones son algunos pares de atributos nombre/valor con algo de metadatos, pero también existen observaciones más complejas que agrupan otras observaciones, e incluso observaciones con varios componentes. Algunos ejemplos de uso del recurso Observation pueden ser, entre otras: • Señales vitales, como el peso corporal, la presión sanguínea y la temperatura. • Datos de laboratorio como la glucosa en sangre. • Medidas fetales. • Medidas de dispositivos como por ejemplo un pulsioxímetro. • Características personales, como el color de los ojos. Un recurso de tipo Observation permite expresar pares nombre-valor o incluso colecciones de pares nombre-valor, aunque pueda almacenar cualquier tipo de información ese no es su objetivo. Fue pensado para capturar medidas y valoraciones médicas en un instante concreto. Tampoco está pensado para contextos más específicos y casos de uso para los que existen ya otros recursos de FHIR más concretos como pueden ser AllergyIntolerance, que representa únicamente las alergias de los pacientes, o MedicationStatement, que modela la medicación que toma un paciente. Estos objetos tan concretos se salen del alcance de este TFG. 2.10.5 HAPI-FHIR HAPI-FHIR [19] es una implementación de software libre del estándar FHIR en el lenguaje de programación Java. HAPI-FHIR permite el intercambio de información de carácter médico conforme al estándar FHIR. Es una librería simple, pero muy potente para dotar a la aplicación de la capacidad de manejar y enviar recursos FHIR. Está escrita en Java puro, compatible con la versión 1.6 en adelante. Podemos encontrar módulos para codificar y decodificar recursos FHIR. Contiene un cliente FHIR que permite recuperar o almacenar recursos en un servidor FHIR externo. Así como módulos para crear servidores conformes al estándar FHIR. Además, modela los recursos del estándar FHIR, proporcionando una interfaz fluida para crear nuevos recursos de forma cómoda y rápida. 2.11 Docker Docker [29] es una plataforma de software que permite crear, probar e implementar aplicaciones rápidamente. Docker empaqueta software en unidades estandarizadas llamadas contenedores que 66 incluyen todo lo necesario para que el software se ejecute, incluidas bibliotecas, herramientas de sistema, código y entorno de ejecución. La tecnología Docker usa el kernel de Linux y las funciones de este, como Cgroups y namespaces, para segregar los procesos, de modo que puedan ejecutarse de manera independiente. El propósito de los contenedores es esta independencia: la capacidad de ejecutar varios procesos y aplicaciones por separado para hacer un mejor uso de su infraestructura y, al mismo tiempo, conservar la seguridad que tendría con sistemas separados. Docker ofrece un modelo de implementación basado en imágenes. Esto permite compartir una aplicación, o un conjunto de servicios, con todas sus dependencias en varios entornos. Docker también automatiza la implementación de las aplicaciones en este entorno de contenedores. Figura 40. Container de Docker frente a una máquina virtual tradicional En este proyecto, se va a ejecutar el Orion Context Broker de FIWARE dentro de un contenedor en Docker y en otro se va a ejecutar la base de datos MongoDB que es imprescindible para su funcionamiento. Se ha decidido hacerlo así porque la instalación de Orion es un proceso bastante complejo ya que tiene un gran número de dependencias. Depende de las librerías libstdc++, boost-thread, boostfilesystem, gnutls, libgcrypt, libcurl, openssl, logrotate y libuuid. Además, recomiendan instalarlo en las distribuciones de linux RedHat o CentOs y este proyecto se ha realizado en Ubuntu. Gracias a Docker, este despliegue tan complejo se resume en un comando. Además, se explica más adelante la opción de desplegar el servidor FHIR cómodamente usando otro contendor Docker. Así se evita la necesidad de instalar Tomcat en el sistema y la configuración que conlleva. 67 3 TRABAJO REALIZADO 3.1 Introducción Como se ha comentado con anterioridad, el objetivo principal de este TFG es el desarrollo de una aplicación que sirva de intermediaria entre dispositivos médicos de la plataforma FIWARE y la plataforma FHIR. La aplicación ofrece una interfaz REST que permite a un gestor crear, actualizar, recuperar y borrar dispositivos y familias de dispositivos. Una familia de dispositivos tiene como mínimo uno de cada uno de los recursos FHIR con los que trabaja la aplicación. Estos recursos son Device, DeviceDefinition, DeviceMetric y Observation. Al crear los recursos, el gestor tiene que enviarlos en formato JSON y obviamente los recursos tienen que cumplir el estándar FHIR. Para añadir más dispositivos basta con añadir más recursos Device, los otros tres recursos son comunes para toda la familia de dispositivos. Además, gracias a la correspondencia que se especificará en el siguiente apartado, la aplicación crea los recursos Device y DeviceModel de FIWARE con los datos proporcionados según el estándar FHIR. Esto significa que el gestor no tiene que especificar los recursos por separado en FHIR y en FIWARE, sino que sólo los envía una única vez. Además de la aplicación, se ha lanzado un servidor que maneja recursos FHIR gracias a la libería HAPI FHIR que se mencionó en el capítulo 2. También se ha lanzado una instancia del Orion Context Broker que es el bloque principal de cualquier aplicación FIWARE. Finalmente, se ha creado una base de datos MongoDB que es utilizada tanto por la aplicación como por el Context Broker. Figura 41. Relaciones de la aplicación con el resto de los componentes Como se ha explicado en el apartado dedicado a NGSI, en Orion se pueden crear suscripciones muy configurables. Cuando salta una suscripción, se notifica mediante un mensaje HTTP POST a la URLy con los campos que se hayan especificado a la hora de crear la suscripción. Cuando el gestor crea una nueva familia de dispositivos, la aplicación crea las suscripciones necesarias en Orion para que sólo se notifique cuando en el dispositivo cambia el valor de al menos 1 de 5 68 atributos clave. Estos atributos son el valor medido por el sensor, el estado del sensor, su dirección IP, su posición y la última fecha de calibración. El resto de los atributos tienen un carácter más estático y no van a ser cambiados en la operación normal del sensor. La aplicación ofrece una segunda interfaz para capturar estas notificaciones HTTP que envía Orion de forma asíncrona. En el cuerpo de estas notificaciones, encontramos nuevos valores para los 5 atributos clave mencionados. La aplicación actualiza los recursos FHIR con estos nuevos valores y envía estos recursos actualizados al servidor FHIR. La aplicación internamente se divide en 4 componentes diferenciados, un controlador REST y 3 clientes. El controlador REST es el bloque central, para llevar a cabo todas las acciones que ofrece sus dos interfaces usa 3 clientes distintos. El cliente FHIR, el cliente FIWARE y el cliente para trabajar con la base de datos MongoDB. Cada uno de estos bloques se verán en profundidad en este capítulo. Figura 42. Diagrama de componentes Al desplegar la aplicación, el servidor FHIR, Orion y la base de datos, el escenario quedaría como muestra el siguiente diagrama. Esto es en el caso de que se despliegue todo en una sola máquina. Se ha hecho así para facilitar el desarrollo de la aplicación. No obstante, al haber usado Docker esto hace que cada uno de los bloques se pueda desplegar en máquinas distintas de forma inmediata. Sólo habría que pasar por la línea de comandos a la hora de ejecutar la aplicación las direcciones IP y puertos correctos. En el siguiente capítulo se detallará como se monta este escenario. 69 Figura 43. Diagrama de despliegue 3.1.1 Tareas realizadas • Se ha establecido una correspondencia entre los recursos del estándar FIWARE y FHIR relacionados con los dispositivos en cada plataforma. • Se ha creado una clase para pasar de FHIR a FIWARE según esta correspondencia. • Se ha desarrollado una interfaz REST para manejar los dispositivos. • Se han creado una serie de suscripciones para notificar de los cambios clave. • Se ha desarrollado una interfaz para capturar las notificaciones asíncronas. • Se han modelado las suscripciones y entidades FIWARE en java. • Se han modelado los recursos asociados a dispositivos de FIWARE en java. • Se ha creado una clase para pasar los recursos FIWARE al estándar NGSIv2. • Se ha desarrollado un cliente REST para la comunicación con el Context Broker. • Se ha desarrollado cliente REST para la comunicación con el servidor FHIR R4. • Se ha desarrollado un cliente para la comunicación con la base de datos MongoDB. • Se ha desplegado un servidor FHIR R4. • Se ha desplegado una base de datos MongoDB. • Se ha desplegado una instancia del Orion Context Broker. • Se ha desplegado la pasarela sobre un contenedor de servlets. • Se han realizado una serie de pruebas. 70 3.2 Correspondencia de recursos FHIR con el ecosistema FIWARE Como se comentó en la introducción, este estudio se va a centrar en los siguientes recursos de FHIR: Device, DeviceDefinition, DeviceMetric y Observation. A continuación, se van a describir los componentes de cada uno de estos recursos y se va a comentar si existen campos equivalentes en la plataforma FIWARE. Antes de empezar a describir en detalle los componentes de FHIR, recordar que en la plataforma FIWARE se van a utilizar los recursos Device y DeviceModel. La relación entre los recursos quedaría así. Figura 44. Diagrama de la correspondencia FHIR-FIWARE 3.2.1 DeviceDefinition – Descripción detallada Hay que recordar que el recurso DeviceDefinition proporciona la información del tipo o categoría al que pertenece un dispositivo médico. Se puede decir que es como la definición de catálogo de un dispositivo. FHIR: DeviceDefinition.identifier Definición Son uno o varios identificadores únicos de instancia, asignados a un dispositivo ya sea por una herramienta software, el fabricante, otras organizaciones o por los propietarios del dispositivo. Cardinalidad 0..* Tipo Identifier Notas Es considerado como un identificador de negocio, no como un identificador lógico del recurso. Esto quiere decir que el identificador lógico del recurso cambia dependiendo del servidor FHIR al que sea enviado, o cambia si un recurso es movido de un lugar a otro. No obstante, el identificador de negocio, 71 independientemente del servidor al que sea enviado y de las copias que se hagan, siempre se refiere al mismo recurso, por lo que nos permite mantener la consistencia independientemente del contexto de uso. Todos los recursos FHIR que implementen este identifier, permiten ser buscados por este atributo en cualquier servidor. FIWARE: DeviceModel En el estándar FIWARE encontramos un atributo obligatorio de cardinalidad 1, llamado id. Realiza la misma funcionalidad que el identifier de FHIR. No obstante, se diferencian en la cardinalidad, y en la forma de presentar los datos. En FIWARE es un simple string, mientras que en FHIR es un objeto de tipo Identifier con múltiples campos. El id de FIWARE se corresponde con el campo value dentro de Identifier. En FIWARE también encontramos el campo source, este campo opcional indica la fuente de los datos de la entidad, este campo se puede mapear con el campo assigner dentro del tipo Identifier. Tabla 3. FHIR: DeviceDefinition.identifier FHIR: DeviceDefinition.udiDeviceIdentifier Definición Es un identificador único de un dispositivo (siglas UDI en inglés, Unique Device identifier) que puede estar asignado a una etiqueta de un dispositivo o paquete. Un dispositivo puede incluir múltiples identificadores UDI, ya que puede incluir uno por cada jurisdicción en la que podría ser vendido el dispositivo. Cardinalidad 0..* Tipo BackboneElement Notas El tipo BackboneElement usado en FHIR, indica que el elemento en cuestión tiene una serie de hijos que se definen dentro de él. A continuación, procederé a examinarlos uno a uno. Tabla 4. FHIR: DeviceDefinition.udiDeviceIdentifier FHIR: DeviceDefinition.udiDeviceIdentifier.deviceIdentifier Definición Este es el identificador que se asocia a cada Device que referencie esta DeviceDefinition para el distribuidor y la jurisdicción indicados en el elemento DeviceDefinition.udiDeviceIdentifier . Cardinalidad 1..1 Tipo string FIWARE: DeviceModel No se corresponde a nada en FIWARE. Tabla 5. FHIR: DeviceDefinition.udiDeviceIdentifier.deviceIdentifier FHIR: DeviceDefinition.udiDeviceIdentifier.issuer Definición Indica la organización que asigna el algoritmo de identificación. Cardinalidad 1..1 72 Tipo uri FIWARE: DeviceModel No se corresponde a nada en FIWARE. Tabla 6. FHIR: DeviceDefinition.udiDeviceIdentifier.issuer FHIR: DeviceDefinition.udiDeviceIdentifier.jurisdiction Definición Indica la jurisdicción a la cual aplica el deviceIdentifier. Cardinalidad 1..1 Tipo uri FIWARE: DeviceModel No se corresponde a nada en FIWARE. Tabla 7. FHIR: DeviceDefinition.udiDeviceIdentifier.jurisdiction FHIR: DeviceDefinition.manufacturer[X] Definición Datos del fabricante Cardinalidad 0..1 Tipo Choice [String | Reference (Organization)] Notas Hay que elegir entre manufacturerString [String] y manufacturerReference [Reference (Organization)]. Ambas opciones mostradas en las siguientes tablas. No pueden aparecer a la vez. Tabla 8. FHIR: DeviceDefinition.manufacturer[X] FHIR: DeviceDefinition.manufacturerString Definición Nombre del fabricante del dispositivo. Cardinalidad 0..1 Tipo string FIWARE DeviceModel Se corresponde con el campo manufacturerName de DeviceModel. No obstante, el nombre del fabricante también se puede expresar mediante el campo DeviceName.name, si su atributo type toma el valor “manufacturerName”. Se ha decido usar DeviceName por encima de este campo manufacturerString en la correspondencia. Tabla 9. FHIR: DeviceDefinition.manufacturerString FHIR: DeviceDefinition.manufacturerReference Definición Referencia a la organización que fabricó el dispositivo. Cardinalidad 0..1 Tipo Reference (Organization) 73 FIWARE: DeviceModel No se corresponde a nada en FIWARE. Tabla 10. FHIR: DeviceDefinition.manufacturerReference FHIR: DeviceDefinition.deviceName Definición Nombre dado al dispositivo para identificarlo Cardinalidad 0..* Tipo BackboneElement Notas El tipo BackboneElement usado en FHIR, indica que el elemento en cuestión tiene una serie de hijos que se definen dentro de él. A continuación, se procederá a examinarlos uno a uno. Tabla 11. FHIR: DeviceDefinition.deviceName FHIR: DeviceDefinition.deviceName.name Definición Nombre del dispositivo Cardinalidad 1 Tipo string Notas Arriba se ha descrito manufacturerString, que sería equivalente a un nombre indicando el tipo manufacturer-name. Se ha decidido usar mejor este campo. FIWARE DeviceModel En FIWARE tenemos varios campos que indican algún tipo de nombre, tenemos modelName, manufacturerName, brandName y name. Serían de los tipos model-name, manufacturer-name, other y user-friendly-name respectivamente. El tipo de nombre se especifica en el siguiente campo. Tabla 12. FHIR: DeviceDefinition.deviceName.name FHIR: DeviceDefinition.deviceName.type Definición Tipo del nombre. Puede ser: udi-label-name | user-friendly-name | patientreported-name | manufacturer-name | model-name | other Cardinalidad 1..1 Tipo code FIWARE DeviceModel No se corresponde directamente a nada en FIWARE. En FIWARE se puede inferir el tipo del nombre a partir del nombre del atributo como se puede observar en modelName, brandName, etc. Tabla 13. FHIR: DeviceDefinition.deviceName.type FHIR: DeviceDefinition.modelNumber Definición El número de modelo del dispositivo Cardinalidad 0..1 80 Tipo uri Notas Si el dispositivo está ejecutando un servidor FHIR, la dirección de red debería ser la URL base desde la cual la declaración de conformidad pueda ser recuperada. FIWARE: DeviceModel El recurso Device de FIWARE cuenta con un campo similar que recibe el nombre de ipAddress. No obstante, mientras que aquí la dirección solo puede ser una, en FIWARE es una lista de direcciones IP. Dado que este campo también aparece en el Device de FHIR, se va a relacionar con ese en lugar de este campo url de DeviceDefinition, ya que las direcciones IP se asignan a los dispositivos concretos. Tabla 33. FHIR: DeviceDefinition.url FHIR: DeviceDefinition.onlineInformation Definición Dirección que permite acceder a información en línea sobre el dispositivo Cardinalidad 0..1 Tipo uri FIWARE DeviceModel En FIWARE encontramos el campo documentation, que es opcional, y se modela como una URL. Es un link a la documentación del dispositivo. Sería una correspondencia directa. Tabla 34. FHIR: DeviceDefinition.onlineInformation FHIR: DeviceDefinition.note Definición Una serie de notas y comentarios descriptivos acerca del dispositivo Cardinalidad 0..* Tipo Annotation Notas El tipo Annotation consta de tres campos, uno que indica el autor de la nota, otro su contenido en forma de texto y finalmente uno que nos informa de cuándo se hizo la nota. FIWARE DeviceModel En FIWARE, encontramos el campo description, es simplemente un campo de texto para describir un dispositivo. Sería una versión muy simplificada de campo note, ya que note aparte de indicar la fecha y el autor, permite almacenar varias notas, a diferencia del campo de FIWARE que sólo permite una única descripción. Tabla 35. FHIR: DeviceDefinition.note FHIR: DeviceDefinition.quantity Definición La cantidad de dispositivos presente en el paquete, por ejemplo, el número de dispositivos presentes dentro de un pack, o el número de dispositivos en el mismo paquete de un producto médico Cardinalidad 0..1 81 Tipo Quantity Notas El tipo Quantity sirve para describir una cantidad que haya sido medida o que se pueda medir. Tiene campos que describen el valor, su unidad, su forma codificada y el sistema en el que se codifica. FIWARE: DeviceModel No se corresponde a nada en FIWARE. Tabla 36. FHIR: DeviceDefinition.quantity FHIR: DeviceDefinition.parentDevice Definición El dispositivo padre del cual puede formar parte Cardinalidad 0..1 Tipo Reference (DeviceDefinition) Notas El recurso Reference, tiene campos que permiten indicar cualquier tipo de referencia, ya sea literal, relativa, interna o una URL absoluta. También puede indicar el tipo del recurso. Así como una referencia lógica cuando no se sabe la referencia literal. Incluso contiene un campo para indicar un texto alternativo en caso de que no haya ninguna referencia a otro recurso. FIWARE: DeviceModel En FIWARE no existe esta capacidad de crear modelos tan complejos con dispositivos padres de otros dispositivos. Tabla 37. FHIR: DeviceDefinition.parentDevice FHIR: DeviceDefinition.material Definición Indica una sustancia usada en la creación de los materiales de los que está hecho el dispositivo. Cardinalidad 0..* Tipo BackboneElement Notas El tipo BackboneElement usado en FHIR, indica que el elemento en cuestión tiene una serie de hijos que se definen dentro de él. A continuación, se procederá a examinarlos uno a uno. Tabla 38. FHIR: DeviceDefinition.material FHIR: DeviceDefinition.material.substance Definición La sustancia en sí Cardinalidad 1 Tipo CodeableConcept Notas El tipo CodeableConcept de FHIR está formado por texto plano que representa el concepto y un elemento de tipo Coding que define el concepto dentro de un sistema terminológico. 82 FIWARE: DeviceModel No se corresponde a nada en FIWARE Tabla 39. FHIR: DeviceDefinition.material.substance FHIR: DeviceDefinition.material.alternate Definición Indica si hay un material alternativo para el dispositivo Cardinalidad 0..1 Tipo boolean FIWARE No se corresponde a nada en FIWARE Tabla 40. FHIR: DeviceDefinition.material.alternate FHIR: DeviceDefinition.material.allergenicIndicator Definición Indica si la sustancia es un alérgeno conocido o sospechado Cardinalidad 0..1 Tipo boolean FIWARE: DeviceModel No se corresponde a nada en FIWARE Tabla 41. FHIR: DeviceDefinition.material.allergenicIndicator 3.2.2 Device – Descripción detallada Como se ha mencionado con anterioridad, un Device es un recurso administrativo que representa instancias individuales de un tipo de dispositivo y su localización. Es referenciado por otros recursos, por ejemplo, para dejar constancia de qué dispositivo realizó una acción como puede ser un procedimiento u observación médica. FHIR: Device.identifier Definición Son uno o varios identificadores únicos de instancia, asignados a un dispositivo ya sea por una herramienta software, el fabricante, otras organizaciones o por los propietarios del dispositivo. Cardinalidad 0..* Tipo Identifier Notas Es considerado como un identificador de negocio, no como un identificador lógico del recurso. Esto quiere decir que el identificador lógico del recurso cambia dependiendo del servidor FHIR al que sea enviado, o cambia si un recurso es movido de un lugar a otro. No obstante el identificador de negocio, independientemente del servidor al que sea enviado y de las copias que se hagan, siempre se refiere al mismo recurso, por lo que nos permite mantener la consistencia independientemente del contexto de uso. Todos los recursos FHIR 83 que implementen este identifier, permiten ser buscados por este atributo en cualquier servidor. FIWARE Device En el estándar FIWARE encontramos un atributo obligatorio de cardinalidad 1, llamado id. Realiza la misma funcionalidad que el identifier de FHIR. Se diferencian en la cardinalidad, y en la forma de presentar los datos. En FIWARE es un simple string, mientras que en FHIR es un objeto de tipo Identifier con múltiples campos. El id de FIWARE se corresponde con el campo value dentro de Identifier. Tabla 42. FHIR: Device.identifier FHIR: Device.definition Definición Es la referencia a la definición (DeviceDefinition) correspondiente de este dispositivo. Cardinalidad 0..1 Tipo Reference (DeviceDefinition) Notas El recurso Reference, tiene campos que permiten indicar cualquier tipo de referencia, ya sea literal, relativa, interna o una URL absoluta. También puede indicar el tipo del recurso. Así como una referencia lógica cuando no se sabe la referencia literal. Incluso contiene un campo para indicar un texto alternativo en caso de que no haya ninguna referencia a otro recurso. FIWARE Device En FIWARE encontramos el campo refDeviceModel, es un campo opcional, modelado como una referencia de FIWARE. Realiza la misma función exactamente, así que sería una correspondencia directa. Tabla 43. FHIR: Device.definition FHIR: Device.udiCarrier Definición Es un identificador único de un dispositivo (siglas UDI en Inglés, Unique Device identifier) que puede estar asignado a una etiqueta de un dispositivo o paquete. Un dispositivo puede incluir múltiples identificadores UDI, ya que puede incluir una por cada jurisdicción en la que podría ser vendido el dispositivo. Cardinalidad 0..* Tipo BackboneElement Notas El tipo BackboneElement usado en FHIR, indica que el elemento en cuestión tiene una serie de hijos que se definen dentro de él. A continuación, se procederá a examinarlos uno a uno. El UDI puede identificar una única instancia de un dispositivo, o también puede que solo identifique el tipo del dispositivo. FIWARE Device Ningún campo se corresponde con nada en FIWARE. Tabla 44. FHIR: Device.udiCarrier 84 FHIR: Device.udiCarrier.deviceIdentifier Definición Es una porción fija y obligatoria de un UDI, que identifica quién ha etiquetado el producto y el modelo o versión específica del dispositivo. El nombre abreviado de este campo es DI. Cardinalidad 0..1 Tipo string Tabla 45. FHIR: Device.udiCarrier.deviceIdentifier FHIR: Device.udiCarrier.issuer Definición Es la organización encargada de administrar los UDIs para los dispositivos. Cardinalidad 0..1 Tipo uri Notas Algunos ejemplos de organizaciones son: • GS1: http://hl7.org/fhir/NamingSystem/gs1-di • HIBCC: http://hl7.org/fhir/NamingSystem/hibcc-dI • ICCBBA para contenedores de sangre: http://hl7.org/fhir/NamingSystem/iccbba-blood-di • ICCBA para otros dispositivos: http://hl7.org/fhir/NamingSystem/iccbba-other-di Tabla 46. FHIR: Device.udiCarrier.issuer FHIR: Device.udiCarrier.jurisdiction Definición Es la identidad de la fuente autorizada para generar UDIs dentro de una jurisdicción. Todas las UDIs son únicas globalmente dentro de un único espacio de nombres. Cardinalidad 0..1 Tipo uri Notas Permite saber qué base de datos contendrá todos los metadatos asociados. Por ejemplo, para las UDIs de los dispositivos manejados dentro del ámbito americano, por la FDA (Food and Drug Administration), el valor sería: http://hl7.org/fhir/NamingSystem/fda-udi. Tabla 47. FHIR: Device.udiCarrier.jurisdiction FHIR: Device.udiCarrier.carrierAIDC Definición Es la representación del código de barras UDI impreso en el empaquetado del dispositivo en una forma que solo entienden las máquinas. Lo leen usando la tecnología AIDC [30](Automatic Identification and Data Capture). En el siguiente campo se encuentra la versión que puede ser leída por los humanos. 85 Cardinalidad 0..1 Tipo base64Binary Notas Debido a las limitaciones de los juegos de caracteres en XML, los formatos AIDC DEBERÁN estar codificados en base64. Actualmente no existe un límite máximo para el tamaño de la codificación, pero los sistemas tendrán que imponer un valor máximo en la implementación final, debiendo quedar esto documentado. Tabla 48. FHIR: Device.udiCarrier.carrierAIDC FHIR: Device.udiCarrier.carrierHRF Definición Es la representación del código de barras UDI impreso en el empaquetado del dispositivo en la forma HRF (Human Readable Form). Cardinalidad 0..1 Tipo string Tabla 49. FHIR: Device.udiCarrier.carrierHRF FHIR: Device.udiCarrier.entryType Definición Indica de qué forma fueron registrados los datos en el sistema. Permite distinguir si fueron introducidos por un humano o una máquina. Los códigos permitidos son barcode, rfid y manual entre otros. Aquí está el listado completo: https://www.hl7.org/fhir/valueset-udi-entry-type.html Cardinalidad 0..1 Tipo code Tabla 50. FHIR: Device.udiCarrier.entryType FHIR: Device.status Definición Estado de disponibilidad del recurso Device. Los códigos posibles para este campo son active, inactive, entered-in-error y unkown. Cardinalidad 0..1 Tipo code FIWARE Device En FIWARE encontramos un campo opcional con el nombre deviceState que tiene exactamente la misma utilidad. La diferencia radica en que en FIWARE se modela el campo con un simple texto, que puede tomar cualquier valor. En FHIR, al estar representado por un code, por lo tanto solo puede tomar una serie de valores predefinidos. Tabla 51. FHIR: Device.status FHIR: Device.statusReason Definición Define la razón del estado de disponibilidad del campo Device.status . 86 Los posibles valores son: online, paused, standby, offline, not-ready, trasnducdiscon, hw-discon y off. Cardinalidad 0..* Tipo CodeableConcept Notas El tipo CodeableConcept de FHIR está formado por texto plano que representa el concepto y un elemento de tipo Coding que define el concepto dentro de un sistema terminológico. FIWARE Device No se corresponde a nada en FIWARE Tabla 52. FHIR: Device.statusReason FHIR: Device.distinctIdentifier Definición Es un identificador distintivo requerido por algunas regulaciones, como puede ser la regulación federal americana (CFR [31]). Aplica tanto a células, o tejidos humanos, como a productos basados en ellos. Cardinalidad 0..1 Tipo string Notas Su abreviatura es DIC de Distinct Identification Code FIWARE Device No se corresponde a nada en FIWARE Tabla 53. FHIR: Device.distinctIdentifier FHIR: Device.manufacturer Definición Nombre del fabricante del dispositivo Cardinalidad 0..1 Tipo string FIWARE Device En Device de FIWARE existe un campo opcional llamado provider que indica el fabricante del dispositivo. Así que sería una correspondencia directa. Tabla 54. FHIR: Device.manufacturer FHIR: Device.manufacturerDate Definición La fecha y la hora en la que el dispositivo fue fabricado Cardinalidad 0..1 Tipo dateTime Notas En FHIR el formato es el siguiente: YYYY, YYYY-MM, YYYY-MM-DD o YYYY-MM-DDThh:mm:ss+zz:zz 87 FIWARE Device Encontramos una correspondencia directa con el campo opcional dateManufactured de FIWARE. Tiene la misma función. En algún caso habrá que adaptar el formato de la fecha. En FIWARE es: [-]YYYY-MM- DDThh:mm:ss[Z|(+|-)hh:mm], según la ISO 8601. Tabla 55. FHIR: Device.manufacturerDate FHIR: Device.expirationDate Definición La fecha y la hora a partir de la cual el dispositivo no es válido, o no debería ser usado. Cardinalidad 0..1 Tipo dateTime FIWARE Device No se corresponde a nada en FIWARE Tabla 56. FHIR: Device.expirationDate FHIR: Device.lotNumber Definición Número de lote asignado por el fabricante Cardinalidad 0..1 Tipo string FIWARE Device No se corresponde a nada en FIWARE Tabla 57. FHIR: Device.lotNumber FHIR: Device.serialNumber Definición Número de serie asignado por el fabricante Cardinalidad 0..1 Tipo string FIWARE Device Hay una correspondencia directa con el campo opcional serialNumber de FIWARE. Tabla 58. FHIR: Device.serialNumber FHIR: Device.deviceName Definición Este campo representa el nombre del dispositivo, puede ser proporcionado por el mismo dispositivo, una etiqueta UDI o una persona que describa el dispositivo. Normalmente este campo se usa cuando una persona le da un nombre o nombres, o cuando el dispositivo representa uno de los campos mencionados en su DeviceDefinition. Cardinalidad 0..* Tipo BackboneElement 88 Notas El tipo BackboneElement usado en FHIR, indica que el elemento en cuestión tiene una serie de hijos que se definen dentro de él. A continuación, se procederá a examinarlos uno a uno. Tabla 59. FHIR: Device.deviceName FHIR: Device.deviceName.name Definición El nombre del dispositivo Cardinalidad 1 Tipo string Notas En DeviceModel hay más tipos de nombres, pero estos ya se han relacionado con DeviceDefinition. FIWARE Device Hay una correspondencia directa con el campo name de FIWARE. Tener en cuenta que mientras que en FIWARE solo se permite un nombre, aquí se pueden asociar varios nombres, mediante un deviceName cada uno. Tabla 60. FHIR: Device.deviceName.name FHIR: Device.deviceName.type Definición Tipo del nombre. Puede ser UDILabelName | UserFriendlyName | PatientReportedName | ManufactureDeviceName | ModelName. Cardinalidad 1 Tipo code FIWARE Device No se corresponde a ningún campo en FIWARE. Por lo que se puede leer en la documentación de FIWARE, el tipo del nombre mencionado arriba sería UserFriendlyName. Tabla 61. FHIR: Device.deviceName.type FHIR: Device.modelNumber Definición Número de modelo del dispositivo Cardinalidad 0..1 Tipo string FIWARE Device No se corresponde a ningún campo en FIWARE Tabla 62. FHIR: Device.modelNumber FHIR: Device.partNumber Definición Número de identificador de una parte concreta dentro del dispositivo Cardinalidad 0..1 Tipo string 89 FIWARE Device No se corresponde a ningún campo en FIWARE Tabla 63. FHIR: Device.partNumber FHIR: Device.type Definición La familia o tipo de un dispositivo Cardinalidad 0..1 Tipo CodeableConcept Notas El tipo CodeableConcept de FHIR está formado por texto plano que representa el concepto y un elemento de tipo Coding que define el concepto dentro de un sistema terminológico. FIWARE Device En Device de FIWARE existe un atributo opcional, que también aparece en DeviceModel, con el nombre category que pretende el mismo objetivo final. Lo que pasa que en FHIR existen más de 1000 tipos diferentes de tipos establecidos como se puede observar en este enlace. https://www.hl7.org/fhir/valuesetdevice-kind.html. Mientras que en FIWARE sólo existe un número reducido de tipos. Tabla 64. FHIR: Device.type FHIR: Device.specialization Definición Define las capacidades y los estándares compatibles con el dispositivo que son usados para la comunicación. Cardinalidad 0..* Tipo BackboneElement Notas El tipo BackboneElement usado en FHIR, indica que el elemento en cuestión tiene una serie de hijos que se definen dentro de él. A continuación, se procederá a examinarlos uno a uno. Tabla 65. FHIR: Device.specialization FHIR: Device.specialization.systemType Definición Indica el estándar que se usa para operar y comunicar. Cardinalidad 1 Tipo CodeableConcept Notas El tipo CodeableConcept de FHIR está formado por texto plano que representa el concepto y un elemento de tipo Coding que define el concepto dentro de un sistema terminológico. FIWARE Device En DeviceModel de FIWARE existe un atributo con el nombre supportedProtocol que consiste en una lista de string. Este indica todos los estándares usados en la comunicación del dispositivo. Se estableció una correspondencia con el campo specialization de DeviceDefinition. En el recurso 96 FIWARE DeviceModel Dado que las capacidades de medir un valor en FIWARE se especifican dentro del recurso DeviceModel, no hay nada equivalente a un id de un DeviceMetric. Se podría generar cogiendo como base el id del DeviceModel y añadiendo algo al final del id como por ejemplo el número que representa el orden de la capacidad en la lista de capacidades del dispositivo. Tabla 84. FHIR: DeviceMetric.identifier FHIR: DeviceMetric.type Definición Tipo de la medida, ejemplos de medida son el pulso del corazón o el nivel de oxígeno en sangre. Cardinalidad 1 Tipo CodeableConcept Notas El tipo CodeableConcept de FHIR está formado por texto plano que representa el concepto y un elemento de tipo Coding que define el concepto dentro de un sistema terminológico. Los tipos se obtienen de los estándares LOINC [32] y IEEE 11073-10101 [33] FIWARE DeviceModel En DeviceModel encontramos el atributo obligatorio controlledProperty, su implementación es una lista de texto y contiene todo lo que el dispositivo puede medir, sentir o controlar. Cada una de sus entradas deberá corresponder con un recurso DeviceMetric asociado a ese dispositivo. En FHIR hay un catálogo más amplio de tipos que en FIWARE. Tabla 85. FHIR: DeviceMetric.type FHIR: DeviceMetric.unit Definición Describe la unidad del valor observado del tipo especificado en type. Por ejemplo, porcentaje o segundos. Cardinalidad 0..1 Tipo CoadeableConcept Notas El tipo CodeableConcept de FHIR está formado por texto plano que representa el concepto y un elemento de tipo Coding que define el concepto dentro de un sistema terminológico. FIWARE DeviceModel En DeviceModel hay un campo opcional con el nombre de supportedUnits. Es una lista de texto, al igual que controlledProperty, y enumera las unidades de medidas soportadas por el dispositivo. En la documentación no se indica como utilizar la lista. No hay muchos ejemplos, así que se va a considerar que el orden de la lista de supportedUnits se refiere al elemento de controlledProperty en el mismo puesto. Tabla 86. FHIR: DeviceMetric.unit FHIR: DeviceMetric.source 97 Definición Describe un enlace al recurso Device al que pertenece este DeviceMetric. Este recurso contiene la información administrativa del dispositivo como puede ser el fabricante y el número de serie. Cardinalidad 0..1 Tipo Reference (Device) Notas El recurso Reference, tiene campos que permiten indicar cualquier tipo de referencia, ya sea literal, relativa, interna o una URL absoluta. También puede indicar el tipo del recurso. Así como una referencia lógica cuando no se sabe la referencia literal. Incluso contiene un campo para indicar un texto alternativo en caso de que no haya ninguna referencia a otro recurso. FIWARE DeviceModel No se corresponde a nada en FIWARE. Tabla 87. FHIR: DeviceMetric.source FHIR: DeviceMetric.operationalStatus Definición Indica el estado de operación actual del dispositivo. Por ejemplo, on, off, standby. Cardinalidad 0..1 Tipo code Notas FIWARE Device No se corresponde a nada en FIWARE. En Device de FIWARE hay un campo con el nombre de deviceState, que justo representa el estado del dispositivo desde el punto de vista operacional. No obstante, este campo ya se ha relacionado con un campo equivalente en Device. Se entiende que ese estado se refiere al estado operacional de una capacidad de medida concreta del dispositivo, pero el de FIWARE se refiere al dispositivo en general, por lo que la correspondencia que se ha realizado sigue siendo correcta. Este campo tiene un nivel superior de granularidad que no es reflejado en FIWARE, por lo que se ha decidido dejarlo sin mapear. Tabla 88. FHIR: DeviceMetric.operationalStatus FHIR: DeviceMetric.color Definición Describe el color de representación para la medida. Esto se usa normalmente para ayudar a los médicos para hacer un seguimiento e identificar los tipos de parámetros por color. Cardinalidad 0..1 Tipo code Notas Un ejemplo práctico sería un dispositivo monitor asociado a un paciente que muestra los niveles de 3 constantes vitales, mostrando cada constante en un color diferente. FIWARE No se corresponde a nada en FIWARE. 98 Device Tabla 89. FHIR: DeviceMetric.color FHIR: DeviceMetric.category Definición Indica la categoría del proceso de generación de una observación médica. Un recurso DeviceMetric puede tomar los valores: setting, measurement, calculation o unspecified. Cardinalidad 1 Tipo code Notas FIWARE DeviceModel Este elemento a priori parece que se puede enlazar con el campo category de DeviceModel. Pero este es una lista con todas las categorías del dispositivo, que aparte que incluye varias que no son aplicables en este campo, al tener una lista no es posible saber cuál corresponde a cada capacidad de medida. Así que no se va a mapear. Tabla 90. FHIR: DeviceMetric.category FHIR: DeviceMetric.measurementPeriod Definición Describe con qué frecuencia se realizan las medidas por parte del dispositivo. Puede variar desde milisegundos en un electrocardiograma hasta horas en otras pruebas. Cardinalidad 0..1 Tipo Timing FIWARE Device No se corresponde a nada en FIWARE. Tabla 91. FHIR: DeviceMetric.measurementPeriod FHIR: DeviceMetric.calibration Definición Describe las calibraciones que han sido realizadas o que requieren realizarse. Cardinalidad 0..* Tipo BackboneElement Notas El tipo BackboneElement usado en FHIR, indica que el elemento en cuestión tiene una serie de hijos que se definen dentro de él. A continuación, se procedrá a examinarlos uno a uno. Tabla 92. FHIR: DeviceMetric.calibration FHIR: DeviceMetric.calibration.type Definición Describe el tipo del método de calibración. Los posibles valores son: unspecified, offset, gain y two-point. 99 Cardinalidad 0..1 Tipo code FIWARE Device No se corresponde a nada en FIWARE. Tabla 93. FHIR: DeviceMetric.calibration.type FHIR: DeviceMetric.calibration.state Definición Describe el estado de calibración. Los posibles valores son: not-calibrated, calibration-required,calibrated y unspecified. Cardinalidad 0..1 Tipo code FIWARE Device No se corresponde a nada en FIWARE. Tabla 94. FHIR: DeviceMetric.calibration.state FHIR: DeviceMetric.calibration.time Definición Describe cuando se realizó la última calibración Cardinalidad 0..1 Tipo instant FIWARE Device Hay una relación directa con el campo de FIWARE dateLastCalibration, tiene exactamente la misma función. Tabla 95. FHIR: DeviceMetric.calibration.time 3.2.4 Observation – Descripción detallada Un recurso de tipo Observation contiene medidas y afirmaciones simples hechas sobre un paciente, dispositivo u otro sujeto. Las observaciones son un elemento central en el sistema médico. La inmensa mayoría de las observaciones son algunos pares de atributos nombre/valor con algo de metadatos, pero también existen observaciones más complejas que agrupan otras observaciones, e incluso observaciones con varios componentes. FHIR: Observation.identifier Definición Identificador único asignado a esta observación. Cardinalidad 0..* Tipo Identifier Notas Es considerado como un identificador de negocio, no como un identificador lógico del recurso. El identificador lógico del recurso cambia dependiendo del servidor FHIR al que sea enviado, o cambia si un recurso es movido de un lugar 100 a otro. No obstante, el identificador de negocio, independientemente del servidor al que sea enviado y de las copias que se hagan, siempre se refiere al mismo recurso, por lo que nos permite mantener la consistencia independientemente del contexto de uso. Todos los recursos FHIR que implementen este identifier, permiten ser buscados por este atributo en cualquier servidor. FIWARE Device Dado que el value en FIWARE está dentro del recurso Device. En FIWARE no tiene un identificador propio. Teniendo en cuenta que un Device normalmente va a generar más de una observación, una solución sería generar un id cogiendo el identificar del Device como base y añadiendo al final el número de la observación generada por ese Device. Tabla 96. FHIR: Observation.identifier FHIR: Observation.basedOn Definición Un plan, propuesta o petición que es completada total o parcialmente por este evento. Cardinalidad 0..* Tipo Reference (CarePlan | DeviceRequest | ImmunizationRecommendation | MedicationRequest | NutritionOrder | ServiceRequest) FIWARE Device No se corresponde a nada en FIWARE. Tabla 97. FHIR: Observation.basedOn FHIR: Observation.partOf Definición Un evento más grande, del cual este recurso es un componente o paso. Cardinalidad 0..* Tipo Reference (MedicationAdministration | MedicationDispense | MedicationStatement | Procedure | Immunization | ImagingStudy) FIWARE Device No se corresponde a nada en FIWARE. Tabla 98. FHIR: Observation.partOf FHIR: Observation.status Definición El estado del valor resultante. Puede tomar los valores: registered | preliminary | final | amended Cardinalidad 1 Tipo code FIWARE Device No se corresponde a nada en FIWARE. Tabla 99. FHIR: Observation.status 101 FHIR: Observation.category Definición Un código que clasifica el tipo general de observación que se está haciendo. Cardinalidad 0..* Tipo CodeableConcept FIWARE Device No se corresponde a nada en FIWARE. Tabla 100. FHIR: Observation.category FHIR: Observation.code Definición Describe que fue observado. A veces también se llama el “nombre” de la observación. Cardinalidad 1 Tipo CodeableConcept FIWARE Device No se corresponde a nada en FIWARE. Tabla 101. FHIR: Observation.code FHIR: Observation.subject Definición El paciente, o grupo de pacientes, localización o dispositivo del que trata esta observación y donde se coloca la observación. Si el objetivo de la observación es diferente del sujeto, los campos focus o el propio campo code especifican el objetivo real de la observación. Cardinalidad 0..1 Tipo Reference (Patient | Group | Device | Location) FIWARE Device No se corresponde a nada en FIWARE. Ya que la observación del valor tiene lugar dentro del Device en FIWARE. Tabla 102. FHIR: Observation.subject FHIR: Observation.focus Definición Este campo sólo se usa en ocasiones especiales. Normalmente basta con los campos code y subject. Este campo se utiliza en el caso de que el objetivo no sea el paciente en cuestión, sino algo o alguien asociado al paciente ya sea su pareja padre, feto o donante. Cardinalidad 0..* Tipo Reference (Any) FIWARE Device No se corresponde a nada en FIWARE. Tabla 103. FHIR: Observation.focus 102 FHIR: Observation.encounter Definición El evento médico durante el cual se realiza la observación. Cardinalidad 0..1 Tipo Reference (Encounter) FIWARE Device No se corresponde a nada en FIWARE. Tabla 104. FHIR: Observation.encounter FHIR: Observation.effective[X] Definición El instante o periodo de tiempo en el que se hizo la observación. Cardinalidad 0..1 Tipo Choice [datetime | Period | Timing | Instant] Notas Al menos una fecha debería estar presente, a menos que la observación sea un reporte histórico. FIWARE Device Es una correspondencia directa con el medatado timestamp del campo value de Device. Tabla 105. FHIR: Observation.effective[X] FHIR: Observation.issued Definición La fecha y hora en la que hicieron disponible esta versión de la observación, normalmente después de que los resultados hayan sido revisados y verificados. Cardinalidad 0..1 Tipo instant FIWARE Device No se corresponde a nada en FIWARE. Tabla 106. FHIR: Observation.issued FHIR: Observation.performer Definición Indica quién fue responsable de indicar que el valor de la observación es verdadero Cardinalidad 0..* Tipo Reference (Practitioner | PractitionerRole | Organization | CareTeam | Patient | RelatedPerson ) FIWARE Device No se corresponde a nada en FIWARE. Tabla 107. FHIR: Observation.performer 103 FHIR: Observation.value[X] Definición La información resultante de hacer la observación, en el caso de que sea un valor simple. Cardinalidad 0..1 Tipo Choice [Quantity|CodeableConcept|string|boolean|integer|Range|Ratio| SampledData|time|dateTime|Period] FIWARE Device Hay una correspondencia directa con el campo value de Device. Tabla 108. FHIR: Observation.value[X] FHIR: Observation.dateAbsentReason Definición Proporciona la razón de por qué el valor esperado en el campo value de este recurso no existe, si fuese necesario. Cardinalidad 0..1 Tipo CodeableConcept FIWARE Device No se corresponde a nada en FIWARE. Tabla 109. FHIR: Observation.dateAbsentReason FHIR: Observation.interpretation Definición Una valoración categórica de un valor observado, por ejemplo, alto, bajo o normal. Cardinalidad 0..* Tipo CodeableConcept FIWARE Device No se corresponde a nada en FIWARE. Tabla 110. FHIR: Observation.interpretation FHIR: Observation.note Definición Comentarios sobre la observación de los resultados Cardinalidad 0..* Tipo Annotation Notas Puede incluir afirmaciones generales sobre la observación, o afirmaciones sobre valores significantes, inesperados, o poco fiables. También puede haber comentarios sobre la fuente de la información si fuese relevante. FIWARE No se corresponde a nada en FIWARE. 104 Device Tabla 111. FHIR: Observation.note FHIR: Observation.bodySite Definición Indica en qué parte del cuerpo del sujeto fue realizada la observación. Cardinalidad 0..1 Tipo CodeableConcept FIWARE Device No se corresponde a nada en FIWARE. Tabla 112. FHIR: Observation.bodySite FHIR: Observation.method Definición Indica el mecanismo usado para realizar la observación. Cardinalidad 0..1 Tipo CodeableConcept FIWARE Device No se corresponde a nada en FIWARE. Tabla 113. FHIR: Observation.method FHIR: Observation.specimen Definición Referencia al recurso de tipo Specimen que fue utilizado para hacer esta observación. Este recurso modela una muestra o material tomado de una entidad biológica viva o muerta o de un objeto físico del ambiente. Cardinalidad 0..1 Tipo Reference (Specimen) FIWARE Device No se corresponde a nada en FIWARE. Tabla 114. FHIR: Observation.specimen FHIR: Observation.device Definición Referencia al dispositivo usado para generar los datos de esta observación. Cardinalidad 0..1 Tipo Reference (Device | DeviceMetric) FIWARE Device No se corresponde a nada en FIWARE. Ya que el valor medido aparece dentro del Device en sí. Tabla 115. FHIR: Observation.device 105 FHIR: Observation.referenceRange Definición Guía de cómo interpretar el valor de la observación, en comparación a un rango de valores normal o recomendado. Si hay más de una referencia se interpretan como un OR lógico. En otras palabras, para representar dos poblaciones distintas de objetivos, se usarían dos elementos referenceRange. Cardinalidad 0..* Tipo BackboneElement FIWARE Device No se corresponden a nada en FIWARE ninguno de sus elementos. Tabla 116. FHIR: Observation.referenceRange FHIR: Observation.referenceRange.low Definición El valor del límite inferior del rango de referencia. El valor límite se incluye en el rango, en caso de ser omitido, se considera que es insignificante. Cardinalidad 0..1 Tipo SimpleQuantity Tabla 117. FHIR: Observation.referenceRange.low FHIR: Observation.referenceRange.high Definición El valor del límite superior del valor de referencia. El valor límite se incluye en el rango, en caso de ser omitido se considera que es insignificante. Cardinalidad 0..1 Tipo SimpleQuantity Tabla 118. FHIR: Observation.referenceRange.high FHIR: Observation.referenceRange.type Definición En caso de haber más de un rango de valores, este código indica cual debe aplicarse al valor medido. En caso de omitirse este campo, se considera el rango normal de valores. Cardinalidad SimpleQuantity Tipo 0..1 Tabla 119. FHIR: Observation.referenceRange.type FHIR: Observation.referenceRange.appliesTo Definición Códigos para indicar a qué tipo de población objetivo aplica este rango. Por ejemplo, un rango de referencia se puede basar en la población normal, o en sexo o raza concretos. Al haber varios elementos appliesTo, son interpretados como un AND lógico. Cardinalidad 0..* 112 3.3.3 Modelo del recurso FIWARE DeviceModel En el repositorio de FIWARE en Github [34] está el recurso modelado en Python, pero no se ha encontrado nada en Java. Así que se ha creado esta clase a partir de la especificación del modelo de datos. Figura 46. Diagrama de clases Device FIWARE 113 3.3.4 Modelo de la posición según GeoJSON Figura 48. Diagrama de clase GeoJSON 3.3.5 Conversor al estándar NGSIv2 Mediante los métodos estáticos de esta clase, se puede dar el formato que impone el estándar NGSIv2 a los recursos DeviceFiw y DeviceModel. Como se ha comentado con anterioridad, el Orion Context Broker trabaja con el formato NGSIv2 por lo que este paso intermedio es necesario para poder, por ejemplo, crear los recursos en Orion desde la aplicación Java. Figura 47. Diagrama de clase DeviceModel 114 La otra opción hubiera sido modelar las clases DeviceFiw y DeviceModel directamente según NGSIv2. No obstante, hubiera complicado mucho el modelo de datos y se pensó que era mejor crear este conversor intermedio. Figura 49. Diagrama de clases NgsiParser 3.3.6 Conversor FHIR-FIWARE Esta clase es la materialización del estudio comparativo y la correspondencia de los recursos del mundo FHIR al mundo FIWARE. Presenta métodos estáticos para pasar de los recursos de FHIR a los recursos FIWARE. Figura 50. Diagrama de clase FhirToFiware 3.3.7 Modelo de las entidades NGSIv2 Figura 51. Diagrama de clases Entity NGSIv2 115 3.3.8 Modelo de las suscripciones NGSIv2 Figura 52. Diagrama de clases Subscription 3.3.9 Modelo de las notificaciones de Orion Figura 53. Diagrama de clases DeviceUpdate 116 3.4 Asignación de Identificadores 3.4.1 Identificadores de los recursos FHIR-FIWARE En primer lugar, hay que asignar un identificador que englobe a toda una familia de dispositivos, tanto en FHIR como en FIWARE. Esto afecta a los recursos DeviceModel (FIWARE) y DeviceDefinition (FHIR). Se ha decidido usar el mismo identificador para ambos y se construye así: “fiware_{nombre del tipo de dispositivo}” Una vez que se cuenta con un identificador para el conjunto de dispositivos, hay que asignar un identificador a cada uno de los dispositivos físicos que forman parte de la familia. Esto afecta a los recursos Device de ambas plataformas. Se ha decidido usar el mismo identificador para ambos y se construye así: “fiware_{nombre del tipo de dispositivo}_{número asignado al dispositivo físico}” En FIWARE sólo se usan los recursos DeviceModel y Device. No obstante, en FHIR también se manejan recursos DeviceMetric y Observation. Un dispositivo puede tener más de una capacidad de medida (DeviceMetric) y obviamente puede generar cualquier número de observaciones. Se ha decidido nombrar a los recursos DeviceMetric así: “fiware_{nombre del tipo de dispositivo}_{número asignado al dispositivo físico}_{número asignado a la capacidad}” La primera capacidad tendrá el número 1 y así incrementalmente. En cuanto a las observaciones se emplea algo similar: “fiware_{nombre del tipo de dispositivo}_{número asignado al dispositivo físico}_{número de la observación}” La primera observación tendrá el número 1 y así incrementalmente. Como ejemplo, la familia de glucómetros del apartado de pruebas tiene los siguientes identificadores: • Los recursos DeviceModel y DeviceDefinition tienen el identificador “fiware_glucometer” • Se ha creado 3 dispositivos dentro de la familia con los identificadores: o “fiware_glucometer_1” o “fiware_glucometer_2” o “fiware_glucometer_3” • En este caso los dispositivos sólo tienen una capacidad de medida y se identifica así: o “fiware_glucometer_1_1” o “fiware_glucometer_2_1” o “fiware_glucometer_3_1” • Si se supone que el primer dispositivo ha realizado 5 observaciones, el segundo 10 y el tercero 15, tendremos las observaciones con los siguientes identificadores: o de “fiware_glucometer_1_1” hasta “fiware_glucometer_1_5” o de “fiware_glucometer_2_1” hasta “fiware_glucometer_2_10” o de “fiware_glucometer_3_1” hasta “fiware_glucometer_3_15” 117 3.4.2 Identificadores de la base de datos En la base de datos MongoDB, se crea una entrada por cada familia de dispositivos y una entrada por cada dispositivo perteneciente a la familia. En el ejemplo de arriba, se habrán creado por tanto 4 entradas en la base de datos. La entrada correspondiente a la familia de dispositivos se identifica con el mismo identificador que los recursos DeviceModel y DeviceDefinition, esto es: “fiware_{nombre del tipo de dispositivo}” Para cada una de las entradas asociadas a los dispositivos físicos, se usa el mismo identificador que en los recursos Device de ambas plataformas, esto es: “fiware_{nombre del tipo de dispositivo}_{número asignado al dispositivo físico}” Por tanto, siguiendo el mismo ejemplo se tendrían estos identificadores: • Entrada asociada a la familia de dispositivos: o “fiware_glucometer” • Entradas asociadas a cada uno de los dispositivos físicos: o “fiware_glucometer_1” o “fiware_glucometer_2” o “fiware_glucometer_3” 3.5 Cliente FHIR La librería HAPI FHIR usada en este proyecto ofrece dos tipos de clientes RESTful para interaccionar con servidores FHIR. La primera opción es un cliente fluido/genérico y la segunda un cliente basado en anotaciones. El cliente genérico es más fácil de usar y generalmente proporciona una forma más rápida de empezar. Sin embargo, el cliente basado en anotaciones confía en una vinculación estática a una serie de operaciones específicas, lo que da una mejor comprobación de errores en tiempo de compilación. Este segundo modelo requiere más esfuerzo para usarlo, pero puede ser muy útil si la persona que especifica los métodos a invocar no es la misma que los usa. Dado que está pensado reutilizar este trabajo, se ha optado por el cliente basado en anotaciones. 118 Figura 54. Diagrama de clase FhirClientInterface 3.5.1 Definición de una interfaz cliente RESTful El primer paso para crear un cliente basado en anotaciones consiste en definir una interfaz RESTful. Una clase que describa una interfaz de cliente RESTful debe extender a la interfaz IRestfulClient, y contendrá uno o más métodos que habrán sido anotados con anotaciones especiales que indican que operación RESTful soportan. Un ejemplo sería: Figura 55. Ejemplo de interfaz FhirClientInterface A continuación, se van a describir los métodos anotados que se han usado en la aplicación. 119 3.5.1.1 Métodos de la interfaz FhirClientInterface para obtener recursos del servidor Figura 56. Interfaz FhirClientInterface@Read 3.5.1.2 Métodos de la interfaz FhirClientInterface para actualizar recursos del servidor Figura 57. Interfaz FhirClientInterface@Update 120 3.5.1.3 Métodos de la interfaz FhirClientInterface para borrar recursos del servidor Figura 58. Interfaz FhirClientInterface@Delete 3.5.1.4 Métodos de la interfaz FhirClientInterface para crear recursos del servidor Figura 59. Interfaz FhirClientInterface@Create. 3.5.2 Instanciación del cliente RESTful Una vez que la interfaz del cliente haya sido definida, hay que crear un objeto FhirContext e instanciar el cliente que estaría listo para usarse. La librería HAPI FHIR se encarga de la implementación de los métodos de la interfaz. La creación del objeto FhirContext es bastante costosa, por lo que hay que controlar el número de objetos FhirContext que se crean en la vida de la aplicación. En la pasarela, sólo se crea una única vez al lanzar la aplicación. 121 Figura 60. Instanciación cliente FHIR 3.5.3 Configurar la codificación (JSON/XML) La interfaz IRestfulClient, que hemos extendido a la hora de crear la interfaz del cliente, viene con algunos métodos muy útiles para configurar la interacción con el servidor. En la siguiente imagen, se muestra como configurar el cliente para elegir entre la codificación JSON o XML. Además, se muestra como pedir que las respuestas sean “pretty printed”, es decir, que el texto de la respuesta venga espaciado de una forma que sea más fácil de leer para los humanos. Figura 61. Configuración cliente FHIR 3.6 Cliente FIWARE Tras investigar por la red, no se encontró ningún cliente NGSIv2 completo, actualizado y programado en java. Por lo tanto, se decidió crear uno con ayuda de la clase RestTemplate de la librería Spring usada en este proyecto. RestTemplate es la clase central de Spring para programar aplicaciones cliente HTTP y consumir servicios web Restful. Proporciona métodos para consumir servicios web para todos los distintos tipos de mensajes HTTP, ya sea GET, POST, PUT, DELETE, etc. Además del cliente, se ha modelado en java los recursos entidad y suscripción según el estándar NGSIv2. Están especificados en el apartado dedicado al modelado de la aplicación. 3.6.1 Suscripciones y Notificaciones En el apartado dedicado a NGSIv2 dentro del capítulo 2, se especificó la estructura tanto de las suscripciones como de las notificaciones dentro de este estándar. Se observó entonces que las suscripciones permiten especificar filtros con la granularidad que se desee. Además, permiten especificar completamente el contenido del mensaje de notificación. En este proyecto, cuando el gestor crea una nueva familia de dispositivos, se crean 5 nuevas suscripciones dentro del Orion Context Broker. Estas suscripciones notifican cambios en 5 atributos clave de las entidades tipo Device pertenecientes a esta nueva familia. Los atributos, como se han comentado con anterioridad, son: “value”, “deviceState”, “dateLastCalibration”, “location” e “ipAddress”. Estos campos son los que se modifican en el funcionamiento del 128 En caso de que el recurso presente errores de sintaxis se devuelve un mensaje HTTP 400 BAD REQUEST. También se devuelve un mensaje HTTP 400 BAD REQUEST si el recurso existe ya en la pasarela. {base}/device/{id} GET Recupera la plantilla del recurso Device identificada con id. Devuelve un mensaje HTTP 200 OK si no ocurre ningún error. En caso de no existir ninguna plantilla en la pasarela que se identifique con id, se devuelve un mensaje HTTP 404 NOT FOUND. {base}/device/{id} PUT Actualiza una plantilla Device ya existente identificada con id. Devuelve un mensaje HTTP 200 OK si no ocurre ningún error. En caso de que el recurso presente errores de sintaxis se devuelve un mensaje HTTP 400 BAD REQUEST. También se devuelve un mensaje HTTP 400 BAD REQUEST si el recurso a actualizar no existe en la pasarela. {base}/device/{id} DELETE Borra la plantilla de un recurso Device del sistema identificada con id. Devuelve un mensaje HTTP 200 OK si no ocurre ningún error. En caso de no existir ninguna entrada en el sistema identificada con id, se devuelve un mensaje HTTP 400 BAD REQUEST. {base}/devicemetric POST Crea una nueva plantilla de tipo DeviceMetric. En el cuerpo del mensaje se encuentra el recurso en formato JSON. El identificador se obtiene del campo identifier dentro del recurso codificado en el mensaje. Devuelve un mensaje HTTP 200 OK si no ocurre ningún error. En caso de que el recurso presente errores de sintaxis se devuelve un mensaje HTTP 400 BAD REQUEST. También se devuelve un mensaje HTTP 400 BAD REQUEST si el recurso existe ya en la pasarela. {base}/devicemetric/{id} GET Recupera la plantilla del recurso DeviceMetric identificada con id. Devuelve un mensaje HTTP 200 OK si no ocurre ningún error. En caso de no existir ninguna plantilla que se identifique con id, se devuelve un mensaje HTTP 404 NOT FOUND. {base}/devicemetric/{id} PUT Actualiza una plantilla DeviceMetric ya existente identificada con id. Devuelve un mensaje HTTP 200 OK si no ocurre ningún error. En caso de que el recurso presente errores de sintaxis se devuelve un mensaje HTTP 400 129 BAD REQUEST. También se devuelve un mensaje HTTP 400 BAD REQUEST si el recurso a actualizar no existe en el sistema. {base}/observation POST Crea una nueva plantilla de tipo Observation. En el cuerpo del mensaje se encuentra el recurso en formato JSON. El identificador se obtiene del campo identifier dentro del recurso codificado en el mensaje. Devuelve un mensaje HTTP 200 OK si no ocurre ningún error. En caso de que el recurso presente errores de sintaxis se devuelve un mensaje HTTP 400 BAD REQUEST. También se devuelve un mensaje HTTP 400 BAD REQUEST si el recurso existe ya en la pasarela. {base}/observation/{id} GET Recupera la plantilla del recurso Observation identificada con id. Devuelve un mensaje HTTP 200 OK si no ocurre ningún error. En caso de no existir ninguna plantilla que se identifique con id, se devuelve un mensaje HTTP 404 NOT FOUND. {base}/observation/{id} PUT Actualiza una plantilla Observation ya existente identificada con id. Devuelve un mensaje HTTP 200 OK si no ocurre ningún error. En caso de que el recurso presente errores de sintaxis se devuelve un mensaje HTTP 400 BAD REQUEST. También se devuelve un mensaje HTTP 400 BAD REQUEST si el recurso a actualizar no existe en la pasarela. {base}/devicefamily/{id} DELETE Borra todas las plantillas pertenecientes a una familia de dispositivos identificada con id. Devuelve un mensaje HTTP 200 OK si no ocurre ningún error. En caso de no existir ninguna entrada en el sistema identificada con id, se devuelve un mensaje HTTP 400 BAD REQUEST. Recordar que una familia de dispositivos consiste como mínimo de los recursos DeviceDefinition, DeviceMetric, Observation y Device. Tabla 132. Resumen interfaz REST 130 Esta tabla muestra la interfaz encargada de capturar las notificaciones procedentes de Orion. URL OPERACIÓN DESCRIPCIÓN {base}/value POST Procesa la notificación asíncrona de Orion como consecuencia del cambio en el valor medido de un dispositivo. {base}/state POST Procesa la notificación asíncrona de Orion como consecuencia del cambio en el estado de un dispositivo. {base}/location POST Procesa la notificación asíncrona de Orion como consecuencia del cambio en la posición de un dispositivo. {base}/calibration POST Procesa la notificación asíncrona de Orion como consecuencia del cambio en la calibración de un dispositivo. {base}/ipaddress POST Procesa la notificación asíncrona de Orion como consecuencia del cambio en la dirección IP de un dispositivo. Tabla 133. Interfaz para capturar notificaciones 3.8.1 Nueva familia de dispositivos fase 1: Creación de plantilla DeviceDefinition Consiste en el paso inicial para crear las plantillas de una nueva familia de dispositivos en la pasarela. Se crea un nuevo recurso DeviceDefinition. Se envía por la línea de comandos, o por una aplicación como Postman, un mensaje POST con el recurso ya sea en formato texto plano o JSON. La URL destino es de la forma, “{base}/devicedefinition”. 131 Figura 71. Diagrama de actividad creación plantilla DeviceDefinition En la figura de abajo, se observa como mediante la etiqueta @PostMapping se indica que se espera un mensaje POST, le indicamos también la url (“/devicedefinition”) y que el cuerpo del mensaje puede estar codificado en JSON o en texto plano. Además, usando la etiqueta @RequestBody indicamos que el recurso codificado en el cuerpo del mensaje recibido tiene que ser convertido en un String. Figura 72. Etiquetas Spring creación DeviceDefinition Lo primero que hay que hacer es convertir el texto plano o el JSON recibido en la petición a un objeto de tipo DeviceDefinition. Hay que usar un objeto del tipo IParser de la librería HAPI FHIR, se obtiene del objeto de contexto FHIR. Se utiliza un bloque try/catch para capturar los posibles errores del recurso enviado. En caso de tener errores de sintaxis, se enviaría un mensaje HTTP BAD REQUEST al usuario con un mensaje indicando que el recurso enviado no es correcto. 132 A continuación, hay que comprobar que el recurso enviado no exista ya en el sistema. En caso de haber sido creado anteriormente, se envía al usuario un mensaje HTTP 400 BAD REQUEST con un mensaje indicando el error. En el caso de que no exista en el sistema, se procede a crear un cliente de FHIR y enviar el recurso al servidor. Además, se crea una nueva plantilla y se guarda dentro el id del recurso en el servidor, el id del recurso en mi sistema y la plantilla del DeviceDefinition recibida. Finalmente, se introduce esta nueva plantilla en la base de datos y se contesta al usuario con un mensaje de éxito. 3.8.2 Nueva familia de dispositivos fase 2: Creación de plantilla Device Consiste en el segundo paso para crear una nueva familia de dispositivos en la pasarela. Se envía por la línea de comandos, o por una aplicación como Postman, un mensaje POST con el recurso Device ya sea en formato texto plano o JSON. La URL destino es de la forma, “{base}/device”. 133 Figura 73. Diagrama de actividad creación plantilla Device En la figura de abajo, se observa que mediante la etiqueta @PostMapping se indica que se espera un mensaje POST, se indica también la url (“/device”) y que el cuerpo del mensaje puede estar codificado en JSON o como texto plano. Además, usando la etiqueta @RequestBody se indica que el recurso codificado en el cuerpo del mensaje recibido tiene que ser convertido en un String. Figura 74. Etiquetas Spring creación Device 134 Lo primero que se hace es convertir el texto plano o el JSON a un objeto de tipo Device. Debemos usar un objeto del tipo IParser de la librería HAPI FHIR, se obtiene del objeto de contexto FHIR. Se utiliza un bloque try/catch para capturar los posibles errores del recurso enviado. En caso de tener errores de sintaxis, se envía un mensaje HTTP 400 BAD REQUEST al usuario con un mensaje indicando que el recurso enviado no es correcto. A continuación, hay que comprobar que el recurso enviado no exista ya en el sistema. En caso de haber sido creado anteriormente, se envía al usuario un mensaje HTTP 400 BAD REQUEST con un mensaje indicando el error. Ahora, se recupera la dirección del DeviceDefinition asociado a este Device de la base de datos y se introduce como una referencia dentro del objeto Device. Hay que crear un recurso Location y un cliente FHIR para subirlo posteriormente al servidor. El identificador de este recurso en el servidor hay que guardarlo como una referencia dentro del recurso Device en el campo location. Hay que guardar la plantilla del Device en la base de datos, así como añadir el identificador de este recurso Device a la lista de identificadores de esta familia de dispositivos. Esto se hace por si quisiera borrar todas las entradas de la base de datos asociadas a una familia de dispositivos. Posteriormente se sube el recurso Device al servidor FHIR y se crea una nueva entrada en la base de datos exclusivamente para este dispositivo en concreto. Aquí se guarda el identificador único del dispositivo, los identificadores de los recursos Device y Location en el servidor FHIR y se establece a cero el número de observaciones asociadas a este dispositivo. A continuación, se convierte este recurso Device a un recurso Device del mundo FIWARE. Tras esto, se pasa al estándar NGSIv2 para poder enviarlo al Context Broker. Se crea un cliente FIWARE y se envía el recurso en formato NGSIv2 al Broker. Tras esto, se devuelve un mensaje de éxito al usuario. 3.8.3 Nueva familia de dispositivos fase 3: Creación de plantilla DeviceMetric Crea un nuevo recurso DeviceMetric, consiste en el tercer paso para crear una nueva familia de dispositivos. Se envía por la línea de comandos, o por una aplicación como Postman, un mensaje POST con el recurso ya sea en formato texto plano o JSON. La URL destino es de la forma “{base}/devicemetric”. 135 Figura 75. Diagrama de actividad creación plantilla DeviceMetric Mediante la etiqueta @PostMapping se indica que esperamos recibir un mensaje POST, se indica también la URL (“/devicemetric”) y que el cuerpo del mensaje puede estar codificado en JSON o como texto plano. Además, usando la etiqueta @RequestBody se indica que el recurso codificado en el cuerpo del mensaje recibido tiene que ser convertido en un String. Figura 76. Etiquetas Spring creación DeviceMetric 136 Lo primero que se hace es convertir el texto plano o el JSON a un objeto de tipo DeviceMetric. Hay que usar un objeto del tipo IParser de la librería HAPI FHIR, se obtiene del objeto de contexto FHIR. Se utiliza un bloque try/catch para capturar los posibles errores del recurso enviado. En caso de tener errores de sintaxis, se envía un mensaje HTTP BAD REQUEST al usuario con un mensaje indicando que el recurso enviado no es correcto. A continuación, hay que comprobar que el recurso enviado no exista ya en el sistema. En caso de haber sido creado anteriormente, se envía al usuario un mensaje HTTP BAD REQUEST con un mensaje indicando el error. Ahora, se obtiene de la base de datos el identificador del recurso Device dentro del servidor FHIR. Con este identificador se crea una referencia al recurso que se mete dentro del DeviceMetric. Se crea un cliente FHIR y se sube el DeviceMetric al servidor FHIR. Como consecuencia se crea un identificador del DeviceMetric en el servidor que hay que guardar en la base de datos para su posterior uso. Posteriormente, se guarda la plantilla del DeviceMetric en la base de datos asociada a la familia de dispositivos. Para terminar, hay que crear y enviar el recurso DeviceModel de FIWARE. Se genera a partir del recurso DeviceDefinition y DeviceMetric de FHIR. Por lo que hay que recuperar el DeviceDefinition de la base de datos. Así se genera la entidad DeviceModel, que tras pasar al estándar NGSIv2, se envía al Context Broker de FIWARE. Tras esto, se envía un mensaje de éxito al usuario. 3.8.4 Nueva familia de dispositivos fase 4: Creación de plantilla Observation Este método se usa para crear un nuevo recurso Observation, es el paso final en el proceso de creación de una nueva familia. Se envía por la línea de comandos, o por una aplicación como Postman, un mensaje POST con el recurso ya sea en formato texto plano o JSON. La URL destino es de la forma “{base}/observation”. 137 Figura 77. Diagrama de actividad creación plantilla Observation Mediante la etiqueta @PostMapping se indica que se espera un mensaje POST, se indica también la url (“/observation”) y que el cuerpo del mensaje puede estar codificado en JSON o como texto plano. Además, usando la etiqueta @RequestBody se indica que el recurso codificado en el cuerpo del mensaje recibido tiene que ser convertido en un String. Figura 78. Etiquetas Spring creación Observation Lo primero que se hace es convertir el texto plano o el JSON a un objeto de tipo Observation. Hay que usar un objeto del tipo IParser de la librería HAPI FHIR, se obtiene del objeto de contexto FHIR. Se utiliza un bloque try/catch para capturar los posibles errores del recurso enviado. En caso de tener errores de sintaxis, se enviaría un mensaje HTTP BAD REQUEST al usuario con un mensaje indicando que el recurso enviado no es correcto. 144 3.8.9 Recuperación de plantilla del recurso Observation por su identificador Este método se usa para recuperar la plantilla de un recurso Observation previamente creado en el sistema usando su identificador. El gestor envía por la línea de comandos, o por una aplicación como Postman, un mensaje GET indicando el identificador de la familia del recurso a recuperar en la propia URL. La URL es de la forma “{base}/observation/{id}”. Figura 87. Diagrama de actividad recuperación plantilla Observation Mediante la etiqueta @GetMapping se indica que se espera recibir un mensaje GET, se indica también la URL que es de la forma (“/observation/{id}”). Con la etiqueta @PathVariable se obtiene el identificador de la URL y se convierte a un String. En caso de no existir ningún recurso con el identificador seleccionado se responde al usuario con un mensaje HTTP 404 NOT FOUND. Si existiera se devuelve al usuario un mensaje HTTP 200 OK con el recurso Observation seleccionado en el cuerpo del mismo en formato JSON. Figura 88. Etiquetas Spring recuperación Observation 145 3.8.10 Actualización de plantilla del recurso DeviceDefinition Este método se usa para actualizar una plantilla de recurso DeviceDefinition previamente creada en nuestro sistema. El gestor envía por la línea de comandos, o por una aplicación como Postman, un mensaje PUT indicando el identificador de la familia del recurso a actualizar en la propia URL. La URL es de la forma “{base}/devicedefinition/{id}”. El nuevo recurso DeviceDefinition se envía en el cuerpo del mensaje, ya sea en formato texto plano o JSON. Figura 89. Diagrama de actividad actualización plantilla DeviceDefinition Mediante la etiqueta @PutMapping se indica que se espera recibir un mensaje PUT, se indica también la URL (“/devicedefinition/{id}”) y que el cuerpo del mensaje puede estar codificado en JSON o como texto plano. Con la etiqueta @PathVariable se obtiene el identificador de la URL y se convierte a un String. Además, usando la etiqueta @RequestBody se indica que el recurso DeviceDefinition codificado en el cuerpo del mensaje recibido tiene que ser convertido en un String. 146 Figura 90. Etiquetas Spring actualización DeviceDefinition Lo primero que se hace es convertir el texto plano o el JSON a un objeto de tipo DeviceDefinition. Hay que usar un objeto del tipo IParser de la librería HAPI FHIR, se obtiene del objeto de contexto FHIR. Se utiliza un bloque try/catch para capturar los posibles errores del recurso enviado. En caso de tener errores de sintaxis, se enviaría un mensaje HTTP 400 BAD REQUEST al usuario con un mensaje indicando que el recurso enviado no es correcto. A continuación, hay que comprobar que el recurso enviado exista en el sistema. En caso de no haber sido creado anteriormente, se envía al usuario un mensaje HTTP 400 BAD REQUEST con un mensaje indicando el error. En el caso de que exista en el sistema, se obtiene de la base de datos el identificador del recurso en el servidor, se crea un cliente de FHIR y se envía el recurso al servidor. Además, se actualiza la plantilla que tenía almacenada en mi base de datos con los nuevos datos. Ahora hay que crear un recurso equivalente en el mundo FIWARE llamado DeviceModel. Para ello se recupera primero el recurso DeviceMetric de la base de datos. Con este recurso recién recuperado y el recurso DeviceDefinition que mandó el usuario se genera el recurso DeviceModel. Para terminar, se pasa este recurso al estándar NGSIv2, se crea un cliente FIWARE y se actualiza el recurso en el Context Broker. Si todo va bien, se responde al usuario con un mensaje HTTP 200 OK y un breve mensaje de éxito. 3.8.11 Actualización de plantilla del recurso Device Este método se usa para actualizar una plantilla de recurso Device previamente creada en nuestro sistema. El gestor envía por la línea de comandos, o por una aplicación como Postman, un mensaje PUT indicando el identificador del recurso a actualizar en la propia URL. La URL es de la forma “{base}/device/{id}”. El nuevo recurso Device se envía en el cuerpo del mensaje, ya sea en formato texto plano o JSON. 147 Figura 91. Diagrama de actividad actualización plantilla Device Mediante la etiqueta @PutMapping se indica que se espera recibir un mensaje PUT, se indica también la URL (“/device/{id}”) y que el cuerpo del mensaje puede estar codificado en JSON o como texto plano. Con la etiqueta @PathVariable se obtiene el identificador de la URL y se convierte a un String. Además, usando la etiqueta @RequestBody se indica que el recurso Device codificado en el cuerpo del mensaje recibido tiene que ser convertido en un String. 148 Figura 92. Etiquetas Spring actualización Device Lo primero que se hace es convertir el texto plano o el JSON a un objeto de tipo Device. Se debe usar un objeto del tipo IParser de la librería HAPI FHIR, se obtiene del objeto de contexto FHIR. Se utiliza un bloque try/catch para capturar los posibles errores del recurso enviado. En caso de tener errores de sintaxis, se enviaría un mensaje HTTP 400 BAD REQUEST al usuario con un mensaje indicando que el recurso enviado no es correcto. A continuación, hay que comprobar que el recurso enviado exista en el sistema. En caso de no haber sido creado anteriormente, se envía al usuario un mensaje HTTP 400 BAD REQUEST con un mensaje indicando el error. En el caso de que exista el Device en el sistema, se recupera de la base de datos el identificador del recurso DeviceDefinition asociado en el servidor y se crea una referencia a este dentro del recurso Device enviado por el usuario. Se hace algo parecido a lo anterior pero ahora con el recurso Location, se recupera su referencia y se le añade al recurso Device. Ahora, se actualiza el recurso Device en el servidor FHIR. Si todo va bien, se actualiza también el recurso en mi base de datos. Si hubiera algún error a la hora de actualizar el recurso, se mandaría un mensaje de error al usuario. Finalmente hay que crear un recurso equivalente Device en el mundo FIWARE. Mediante la clase FhirToFiware y el recurso Device de FHIR enviado por el usuario se genera este modelo equivalente FIWARE. Para terminar, se pasa este recurso al estándar NGSIv2, se crea un cliente FIWARE y se actualiza el recurso en el Context Broker. Si todo va bien, se responde al usuario con un mensaje HTTP 200 OK y un breve mensaje de éxito. 3.8.12 Actualización de plantilla del recurso DeviceMetric Este método se usa para actualizar una plantilla de recurso DeviceMetric previamente creada en nuestro sistema. El gestor envía por la línea de comandos, o por una aplicación como Postman, un mensaje PUT indicando el identificador de la familia del recurso a actualizar en la propia URL. La URL es de la forma “{base}/devicemetric/{id}”. El nuevo recurso DeviceMetric se envía en el cuerpo del mensaje, ya sea en formato texto plano o JSON. 149 Figura 93. Diagrama de actividad actualización plantilla DeviceMetric Mediante la etiqueta @PutMapping se indica que se espera recibir un mensaje PUT, se indica también la URL (“/devicemetric/{id}”) y que el cuerpo del mensaje puede estar codificado en JSON o como texto plano. Con la etiqueta @PathVariable se obtiene el identificador de la URL y se convierte a un String. Además, usando la etiqueta @RequestBody se indica que el recurso codificado en el cuerpo del mensaje recibido tiene que ser convertido en un String. Figura 94. Etiquetas Spring actualización DeviceMetric Lo primero que se hace es convertir el texto plano o el JSON a un objeto de tipo DeviceMetric. Se debe usar un objeto del tipo IParser de la librería HAPI FHIR, se obtiene del objeto de contexto FHIR. Se utiliza un bloque try/catch para capturar los posibles errores del recurso enviado. En caso de tener errores de sintaxis, se enviaría un mensaje HTTP 400 BAD REQUEST al usuario con un mensaje indicando que el recurso enviado no es correcto. 150 A continuación, hay que comprobar que el recurso enviado exista en el sistema. En caso de no haber sido creado anteriormente, se envía al usuario un mensaje HTTP 400 BAD REQUEST con un mensaje indicando el error. En el caso de que exista en el sistema, se guarda el nuevo recurso DeviceMetric en la base de datos. Ahora hay que crear un recurso equivalente en el mundo FIWARE llamado DeviceModel. Para ello se recupera primero el recurso DeviceDefinition de la base de datos. Con este recurso recién recuperado y el recurso DeviceMetric que mandó el usuario se genera el recurso DeviceModel. Para terminar, se pasa este recurso al estándar NGSIv2, se crea un cliente FIWARE y se actualiza el recurso en el Context Broker. Si todo va bien, se responde al usuario con un mensaje HTTP 200 OK y un breve mensaje de éxito. Destacar que esta no es la vía correcta para cambiar la fecha de calibración de ningún dispositivo, sino que debe modificarse a través del Orion Context Broker. Es decir, esta funcionalidad está pensada para cambiar propiedades estáticas y no propiedades dinámicas que se actualizan a través del Orion Context Broker. 3.8.13 Actualización de plantilla del recurso Observation Este método se usa para actualizar una plantilla de recurso Observation previamente creada en nuestro sistema. El gestor envía por la línea de comandos, o por una aplicación como Postman, un mensaje PUT indicando el identificador de la familia del recurso a actualizar en la propia URL. La URL es de la forma “{base}/observation/{id}”. El nuevo recurso Observation se envía en el cuerpo del mensaje, ya sea en formato texto plano o JSON. 151 Figura 95. Diagrama de actividad actualización plantilla Observation Mediante la etiqueta @PutMapping se indica que se espera recibir un mensaje PUT, se indica también la URL (“/observation/{id}”) y que el cuerpo del mensaje puede estar codificado en JSON o como texto plano. Con la etiqueta @PathVariable se obtiene el identificador de la URL y se convierte a un String. Además, usando la etiqueta @RequestBody se indica que el recurso codificado en el cuerpo del mensaje recibido tiene que ser convertido en un String. Figura 96. Etiquetas Spring actualización Observation Lo primero que se hace es convertir el texto plano o el JSON a un objeto de tipo Observation. Hay que usar un objeto del tipo IParser de la librería HAPI FHIR., se obtiene del objeto de contexto FHIR. Se utiliza un bloque try/catch para capturar los posibles errores del recurso enviado. En caso de tener errores de sintaxis, se enviaría un mensaje HTTP 400 BAD REQUEST al usuario con un mensaje indicando que el recurso enviado no es correcto. 152 A continuación, hay que comprobar que el recurso enviado exista en el sistema. En caso de no haber sido creado anteriormente, se envía al usuario un mensaje HTTP 400 BAD REQUEST con un mensaje indicando el error. En el caso de que exista en el sistema, se guarda la nueva plantilla de Observation en la base de datos para su posterior uso y se responde al usuario con un mensaje HTPP 200 OK, con un breve mensaje de éxito. 3.8.14 Eliminación de una familia de dispositivos Este método se usa para borrar las entradas de la base de datos y las entidades correspondientes en FIWARE pertenecientes a una familia de dispositivos. El gestor envía por la línea de comandos, o por una aplicación como Postman, un mensaje DELETE indicando el identificador de la familia de dispositivos a borrar en la propia URL. La URL destino es del tipo “{base}/devicefamily/{id}”. 153 Figura 97. Diagrama de actividad eliminación familia de dispositivos Mediante la etiqueta general @RequestMapping y seleccionando el método “RequestMethod.DELETE” se indica que se espera recibir un mensaje HTTP DELETE, se indica también la URL que es de la forma (“/devicefamily/{id}”). Donde {id} se sustituye por el identificador de la familia de dispositivos que se desea borrar. Con la etiqueta @PathVariable se obtiene el identificador de la URL y se convierte a un String.