3
* $Id: parserxmlenglish.cpp 3720 2011-04-15 13:39:05Z carlos $
6
* Copyright 2008-10 MetaEmotion S.L. All rights reserved.
7
* http://ginkgo-cadx.com
9
* This file is licensed under LGPL v3 license.
10
* See License.txt for details
14
//#define _GINKGO_TRACE
21
#include <wx/xml/xml.h>
23
#include <wx/sstream.h>
24
#include <wx/msgdlg.h>
28
#include <wx/tokenzr.h>
29
#include <wx/config.h>
30
#include <wx/filename.h>
31
#include <api/internacionalizacion.h>
33
#include "parserxmlenglish.h"
34
#include <api/globals.h>
35
#include <api/imodelohl7.h>
36
#include <api/icontroladormodulo.h>
37
#include <api/icontroladorhl7.h>
38
#include <api/iguiasmensajeriasacyl.h>
39
#include <api/aetwildcards.h>
40
#include <main/controllers/controladorextensiones.h>
41
#include <main/controllers/controladorlog.h>
42
#include <main/entorno.h>
43
#include "dcmtk/dicomservers.h"
45
//creacion de la base de datos de mensajes
46
GIL::HL7::ParserXMLEnglish::ParserXMLEnglish()
50
GIL::HL7::ParserXMLEnglish::~ParserXMLEnglish()
54
//region "Interfaz generica"
56
std::string GIL::HL7::ParserXMLEnglish::GetKey()
58
return "gnkworkflows";
61
/* Parsea la cadena XML y construye el modelo de integracion. Los parametros no encontrados se asignan por defecto segun lo especificado en la configuracion global */
62
void GIL::HL7::ParserXMLEnglish::ParseIntegrationXML(GNC::GCS::IEntorno::ListaModelosIntegracion& models, wxXmlNode* pRoot)
64
std::string xpp; // XML Pretty Printed for extended information info.
65
if (pRoot->GetName().CmpNoCase(wxT("gnkworkflows")) == 0) {
68
typedef std::map<std::string, GIL::IModeloPACSServer> MapaServers;
72
// PreCargamos la lista de PACS de la configuracion
73
for (DicomServerHolder* sl = DicomServerList::Instance()->GetList(); sl != NULL; sl = sl->next) {
74
IModeloPACSServer pacs;
75
pacs.sid = sl->server.ID;
76
pacs.AET = sl->server.AET;
77
pacs.hostname = sl->server.HostName;
78
pacs.puerto = sl->server.Port;
80
servers[pacs.sid] = pacs;
84
// Parseamos los PACS especificados por fichero
85
for (wxXmlNode* nodo = pRoot->GetChildren(); nodo != NULL; nodo = nodo->GetNext()) {
86
if (nodo->GetName().CmpNoCase(wxT("pacs")) == 0) { // Configuracion de PACS
87
GIL::IModeloPACSServer pacsServer;
89
propVal = nodo->GetPropVal(wxT("sid"), wxEmptyString);
90
if( !propVal.empty() ) {
91
pacsServer.sid = propVal.ToUTF8();
94
throw HL7XMLException(_Std("Omitted Identificator"), xpp, "CONF/pacs");
97
propVal = nodo->GetPropVal(wxT("aet"), wxEmptyString);
98
if( !propVal.empty() ) {
99
pacsServer.AET = propVal.ToUTF8();
102
throw HL7XMLException(_Std("Omitted AET"), xpp, "CONF/pacs");
105
propVal = nodo->GetPropVal(wxT("hostname"), wxEmptyString);
106
if( !propVal.empty() ) {
107
pacsServer.hostname = propVal.ToUTF8();
110
throw HL7XMLException(_Std("Hostname missing"), xpp, "CONF/pacs");
113
propVal = nodo->GetPropVal(wxT("port"), wxEmptyString);
114
if( !propVal.empty() ) {
115
pacsServer.puerto = propVal.ToUTF8();
118
throw HL7XMLException(_Std("Omitted port"), xpp, "CONF/pacs");
121
propVal = nodo->GetPropVal(wxT("tls"), wxEmptyString);
122
if( propVal.CmpNoCase(wxT("yes")) == 0 || propVal.CmpNoCase(wxT("true")) == 0 || propVal.CmpNoCase(wxT("si")) == 0 || propVal.CmpNoCase(wxT("1")) == 0 ) {
123
pacsServer.tls = true;
126
pacsServer.tls = false;
129
propVal = nodo->GetPropVal(wxT("pacs-user"), wxEmptyString);
130
if( !propVal.empty()) {
131
pacsServer.user = propVal.ToUTF8();
134
propVal = nodo->GetPropVal(wxT("pacs-password"), wxEmptyString);
135
if( !propVal.empty()) {
136
pacsServer.password = propVal.ToUTF8();
139
propVal = nodo->GetPropVal(wxT("verify-credentials"), wxEmptyString);
140
if( propVal.CmpNoCase(wxT("yes")) == 0 || propVal.CmpNoCase(wxT("true")) == 0 || propVal.CmpNoCase(wxT("si")) == 0 || propVal.CmpNoCase(wxT("1")) == 0 ) {
141
pacsServer.verify = true;
144
pacsServer.verify = false;
147
propVal = nodo->GetPropVal(wxT("retrieve-method"), wxEmptyString);
148
if( propVal.CmpNoCase(wxT("get")) == 0 ) {
149
pacsServer.metodo = GIL::IModeloPACSServer::IMPS_GET;
152
pacsServer.metodo = GIL::IModeloPACSServer::IMPS_MOVE;
155
propVal = nodo->GetPropVal(wxT("pdu"), wxEmptyString);
156
if( propVal.empty()) {
157
pacsServer.pdu = "16384";
160
pacsServer.pdu = propVal.ToUTF8();
163
propVal = nodo->GetPropVal(wxT("retrieve-level"), wxEmptyString);
164
if( propVal.empty()) {
165
pacsServer.retrieveLevel = "SERIES";
168
pacsServer.retrieveLevel = propVal.ToUTF8();
171
for (wxXmlNode* subnodo = nodo->GetChildren(); subnodo != NULL; subnodo = subnodo->GetNext()) {
172
if (subnodo->GetName().CmpNoCase(wxT("client-cert")) == 0) {
173
pacsServer.cert = subnodo->GetNodeContent().ToUTF8();
175
else if (subnodo->GetName().CmpNoCase(wxT("client-key")) == 0) {
176
pacsServer.key = subnodo->GetNodeContent().ToUTF8();
180
servers[pacsServer.sid] = pacsServer;
182
DicomServer* server = DicomServerList::Instance()->GetServer(pacsServer.sid);
183
server->AET = pacsServer.AET;
184
server->HostName = pacsServer.hostname;
187
if(!wxString::FromUTF8(pacsServer.pdu.c_str()).ToLong(&pdu)) {
188
throw HL7XMLException(_Std("The pdu size is not a valid number"), xpp, "CONF/pacs");
191
if(wxString::FromUTF8(pacsServer.puerto.c_str()).ToLong(&puerto)) {
192
server->Port = puerto;
194
throw HL7XMLException(_Std("Port is not a valid number"), xpp, "CONF/pacs");
196
if (pacsServer.metodo == GIL::IModeloPACSServer::IMPS_GET) {
197
server->retrieveWithMove = false;
200
server->retrieveWithMove = true;
202
server->retrieveSeries = wxString::FromUTF8(pacsServer.retrieveLevel.c_str()).CmpNoCase(wxT("SERIES")) == 0;
203
server->useTLS = pacsServer.tls;
204
server->verifyCredentials = pacsServer.verify;
205
server->certificate = pacsServer.cert;
206
server->privateKey = pacsServer.key;
207
server->pacsUser = pacsServer.user;
208
server->pacsPass = pacsServer.password;
210
DicomServerList::Instance()->SetDefaultServer(server->ID);
212
} catch (GinkgoNoServerFoundException& ){
215
if(!wxString::FromUTF8(pacsServer.pdu.c_str()).ToLong(&pdu)) {
216
throw HL7XMLException(_Std("The pdu size is not a valid number"), xpp, "CONF/pacs");
218
if(wxString::FromUTF8(pacsServer.puerto.c_str()).ToLong(&puerto)) {
219
DicomServerList::Instance()->AddServer( DicomServer(pacsServer.sid, pacsServer.AET, pacsServer.hostname, (int)puerto, 0, true, pdu, pacsServer.tls, pacsServer.user, pacsServer.password, pacsServer.metodo == GIL::IModeloPACSServer::IMPS_MOVE, wxString::FromUTF8(pacsServer.retrieveLevel.c_str()).Upper() == wxT("SERIES"), pacsServer.verify, pacsServer.cert, pacsServer.key), true );
221
throw HL7XMLException(_Std("The port is not a valid number"), xpp, "CONF/pacs");
227
std::string codigoAplicacion;
228
//se extrae de la configuracion el codigo de aplicacion
230
wxConfigBase* config = wxConfigBase::Get();
231
config->SetPath(wxT("/GinkgoCore/HCE"));
233
config->Read(wxT("CodigoAplicacion"), &valor, wxEmptyString);
234
codigoAplicacion = valor.ToUTF8();
236
// Parseamos las gnkworkflows
237
for (wxXmlNode* nodo = pRoot->GetChildren(); nodo != NULL; nodo = nodo->GetNext()) {
238
if (nodo->GetName().CmpNoCase(wxT("gnkworkflow") ) == 0) { // gnkworkflow
240
GIL::IModeloIntegracion* modelo = new IModeloIntegracion();
241
//se copia el raw data
243
wxXmlNode* pNodo = new wxXmlNode(*nodo);
244
wxXmlDocument docTmp;
245
docTmp.SetRoot(pNodo);
246
wxStringOutputStream out;
247
docTmp.Save(out,wxXML_NO_INDENTATION);
248
modelo->rawXmlData = out.GetString().ToUTF8();
252
propVal = nodo->GetPropVal(wxT("tid"), wxEmptyString);
253
if( !propVal.empty() ) {
254
modelo->idPlantilla = propVal.ToUTF8();
256
modelo->idPlantilla = "";
259
propVal = nodo->GetPropVal(wxT("action"), wxEmptyString).Lower();
260
if ( !propVal.empty() ) {
262
if (propVal.CmpNoCase(wxT("retrieve")) == 0){
263
modelo->accion = GIL::IModeloIntegracion::TA_Obtener;
265
else if (propVal.CmpNoCase(wxT("dicomize")) == 0 ) {
266
modelo->accion = GIL::IModeloIntegracion::TA_Dicomizar;
268
else if (propVal.CmpNoCase(wxT("print")) == 0) {
269
modelo->accion = GIL::IModeloIntegracion::TA_Imprimir;
272
throw HL7XMLException(_Std("\"action\" attribute invalid at \"gnkworkflow\" scope" ), xpp, "CONF/template");
276
throw HL7XMLException(_Std("\"action\" attribute expected at \"gnkworkflow\" scope"), xpp, "CONF/template");
279
propVal = nodo->GetPropVal(wxT("petition-id"), wxEmptyString);
280
if( !propVal.empty() ) {
281
modelo->idPeticion = propVal.ToUTF8();
284
modelo->idPeticion = "";
287
propVal = nodo->GetPropVal(wxT("scope"), wxEmptyString);
288
if( !propVal.empty() ) {
289
modelo->idAmbitoPeticion = propVal.ToUTF8();
292
modelo->idAmbitoPeticion = "";
295
if( nodo->HasProp(wxT("pacs-retrieve-sid")) ) {
296
propVal = nodo->GetPropVal(wxT("pacs-retrieve-sid"), wxEmptyString);
297
if (!propVal.IsEmpty()) {
298
modelo->PACSObtencion = propVal.ToUTF8();
301
throw HL7XMLException(_Std("\"pacs-retrieve-sid\" attribute empty at \"gnkworkflow\" scope"), xpp, "CONF/template");
305
if( nodo->HasProp(wxT("pacs-store-sid")) ) {
306
propVal = nodo->GetPropVal(wxT("pacs-store-sid"), wxEmptyString);
307
if (!propVal.IsEmpty()) {
308
modelo->PACSAlmacenamiento = propVal.ToUTF8();
311
throw HL7XMLException(_Std("\"pacs-store-sid\" attribute empty at \"gnkworkflow\" scope"), xpp, "CONF/template");
315
//recorremos los hijos de las gnkworkflows
316
for (wxXmlNode* hijo = nodo->GetChildren(); hijo != NULL; hijo = hijo->GetNext()) {
317
//parseamos los campos dimse
318
if(hijo->GetName().CmpNoCase(wxT("query-retrieve-level")) == 0){
319
propVal = hijo->GetPropVal(wxT("value"), wxEmptyString);
320
if ( !propVal.empty() ) {
321
modelo->ambitoDIMSE = propVal.ToUTF8();
324
throw HL7XMLException(_Std("\"value\" attribute expected at \"query-retrieve-level\" scope"), xpp, "CONF/template");
328
//parseamos los campos d paciente
329
if(hijo->GetName().CmpNoCase(wxT("patient")) == 0) {
330
for (wxXmlNode* hijosPaciente = hijo->GetChildren(); hijosPaciente != NULL; hijosPaciente = hijosPaciente->GetNext()) {
331
if(hijosPaciente->GetName().CmpNoCase(wxT("name")) == 0) {
332
if(hijosPaciente->GetChildren() != NULL){
333
modelo->Paciente.nombre = hijosPaciente->GetChildren()->GetContent().ToUTF8();
335
} else if(hijosPaciente->GetName().CmpNoCase(wxT("first-surname")) == 0) {
336
if(hijosPaciente->GetChildren() != NULL){
337
modelo->Paciente.apellido1 = hijosPaciente->GetChildren()->GetContent().ToUTF8();
339
} else if(hijosPaciente->GetName().CmpNoCase(wxT("second-surname")) == 0) {
340
if(hijosPaciente->GetChildren() != NULL){
341
modelo->Paciente.apellido2 = hijosPaciente->GetChildren()->GetContent().ToUTF8();
343
} else if(hijosPaciente->GetName().CmpNoCase(wxT("episode-number")) == 0) {
344
if(hijosPaciente->GetChildren() != NULL){
345
modelo->Paciente.numEpisodio = hijosPaciente->GetChildren()->GetContent().ToUTF8();
347
}else if(hijosPaciente->GetName().CmpNoCase(wxT("id")) == 0) {
348
std::string codigo(propVal.ToUTF8());
349
std::string valor(propVal.ToUTF8());
350
propVal = hijosPaciente->GetPropVal(wxT("code"), wxEmptyString);
351
if ( !propVal.empty() ) {
352
codigo = propVal.ToUTF8();
355
throw HL7Exception(_Std("\"code\" attribute expected at \"patient\" scope"), xpp, "CONF/template");
357
propVal = hijosPaciente->GetPropVal(wxT("value"), wxEmptyString);
358
if ( !propVal.empty() ) {
359
valor = propVal.ToUTF8();
360
modelo->Paciente.listaIdentificadores.push_back(IModeloIdentificador(codigo,valor));
366
//parseamos los campos d medico
367
if(hijo->GetName().CmpNoCase(wxT("physician")) == 0) {
368
for (wxXmlNode* hijosMedico = hijo->GetChildren(); hijosMedico != NULL; hijosMedico = hijosMedico->GetNext()) {
369
if(hijosMedico->GetName().CmpNoCase(wxT("name")) == 0) {
370
if(hijosMedico->GetChildren() != NULL){
371
modelo->Medico.nombre = hijosMedico->GetChildren()->GetContent().ToUTF8();
373
} else if(hijosMedico->GetName().CmpNoCase(wxT("first-surname")) == 0) {
374
if(hijosMedico->GetChildren() != NULL){
375
modelo->Medico.apellido1 = hijosMedico->GetChildren()->GetContent().ToUTF8();
377
} else if(hijosMedico->GetName().CmpNoCase(wxT("second-surname")) == 0) {
378
if(hijosMedico->GetChildren() != NULL){
379
modelo->Medico.apellido2 = hijosMedico->GetChildren()->GetContent().ToUTF8();
381
} else if(hijosMedico->GetName().CmpNoCase(wxT("id")) == 0) {
382
std::string codigo(propVal.ToUTF8());
383
std::string valor(propVal.ToUTF8());
384
propVal = hijosMedico->GetPropVal(wxT("code"), wxEmptyString);
385
if ( !propVal.empty() ) {
386
codigo = propVal.ToUTF8();
389
throw HL7XMLException(_Std("\"code\" attribute expected at \"physician\" scope"), xpp, "CONF/template");
391
propVal = hijosMedico->GetPropVal(wxT("value"), wxEmptyString);
392
if ( !propVal.empty() ) {
393
valor = propVal.ToUTF8();
396
throw HL7XMLException(_Std("\"value\" attribute expected at \"physician\" scope"), xpp, "CONF/template");
398
modelo->Medico.listaIdentificadores.push_back(IModeloIdentificador(codigo,valor));
399
} else if(hijosMedico->GetName() == wxT("institution")) {
400
propVal = hijosMedico->GetPropVal(wxT("iid"), wxEmptyString);
401
if ( !propVal.empty() ) {
402
modelo->Medico.idCentro = propVal.ToUTF8();
405
throw HL7XMLException(_Std("\"iid\" atribute expected at \"institution\" scope"), xpp, "CONF/template");
408
if(hijosMedico->GetChildren() != NULL){
409
modelo->Medico.nombreCentro = hijosMedico->GetChildren()->GetContent().ToUTF8();
415
if(hijo->GetName().CmpNoCase(wxT("hce")) == 0) {
416
propVal = hijo->GetPropVal(wxT("aid"), wxEmptyString);
417
if ( !propVal.empty() ) {
418
modelo->HCE.Sid = propVal.ToUTF8();
421
throw HL7XMLException(_Std("\"aid\" attribute expected at \"hce\" scope"), xpp, "CONF/template");
425
if (hijo->GetName().CmpNoCase(wxT("metadata")) == 0) {
429
std::string descripcion;
431
propVal = hijo->GetPropVal(wxT("code"), wxEmptyString);
432
if ( !propVal.empty() ) {
433
codigo = propVal.Upper().ToUTF8();
435
throw HL7XMLException(_Std("\"code\" attribute expected at \"metadata\" scope"), xpp, "CONF/template");
438
propVal = hijo->GetPropVal(wxT("key"), wxEmptyString);
439
if ( !propVal.empty() ) {
440
clave = propVal.Lower().ToUTF8();
442
throw HL7XMLException(_Std("\"key\" attribute expected at \"metadata\" scope"), xpp, "CONF/template");
445
propVal = hijo->GetPropVal(wxT("value"), wxEmptyString);
446
if ( !propVal.empty() ) {
447
valor = propVal.ToUTF8();
450
propVal = hijo->GetPropVal(wxT("description"), wxEmptyString);
451
if ( !propVal.empty() ) {
452
descripcion = propVal.ToUTF8();
455
IModeloTupla tupla(codigo,clave, valor,descripcion);
456
modelo->Metadatos.push_back(tupla);
459
if (hijo->GetName().CmpNoCase(wxT("observations")) == 0) {
460
if(hijo->GetChildren() != NULL) {
461
modelo->observaciones = hijo->GetChildren()->GetContent().ToUTF8();
464
}//fin hijos gnkworkflow
465
if (modelo->accion == GIL::IModeloIntegracion::TA_Obtener && modelo->Paciente.listaIdentificadores.size() != 0)
467
modelo->Metadatos.push_back(IModeloTupla("DICOM","0010|0020", modelo->Paciente.GetIdentificadorPreferido().valor,""));
469
if (modelo->accion == GIL::IModeloIntegracion::TA_Dicomizar) {
470
if (modelo->idPlantilla == "") {
471
throw HL7XMLException(_Std("\"tid\" attribute omitted"), xpp, "CONF/template");
473
if (modelo->idAmbitoPeticion == "") {
474
throw HL7XMLException(_Std("\"scope\" attribute expected at \"gnkworkflow\" scope"), xpp, "CONF/template");
476
if (modelo->idPeticion == "") {
477
throw HL7XMLException(_Std("\"petition-id\" attribute expected at \"gnkworkflow\" scope"), xpp, "CONF/template");
479
if(modelo->Medico.listaIdentificadores.size() == 0) {
480
throw HL7XMLException(_Std("It has been read a \"medico\" tag without identifiers"), xpp, "CONF/template");
482
} else if (modelo->accion == GIL::IModeloIntegracion::TA_Obtener) {
483
if (modelo->Metadatos.size() == 0) {
484
throw HL7XMLException(_Std("You must specify attributes you want to use in the query"), xpp, "CONF/template");
487
if(modelo->HCE.Sid == "") {
488
throw HL7XMLException(_Std("id_application expected"), xpp, "CONF/template");
490
if(modelo->Paciente.listaIdentificadores.size() == 0 && modelo->accion == GIL::IModeloIntegracion::TA_Dicomizar) {
491
throw HL7XMLException(_Std("It has been read a \"patient\" tag without identifiers"), xpp, "CONF/template");
493
//se pone el codigo de aplicacion y el primer PACS de la configuracion si no nos ha venido ninguno
494
modelo->CodigoAplicacion = codigoAplicacion;
495
if(servers.size() > 0) {
496
DicomServer* pServer = DicomServerList::Instance()->GetDefaultServer();
497
if (modelo->PACSObtencion.size() == 0 && pServer != NULL) {
498
modelo->PACSObtencion = pServer->ID;
500
if (modelo->PACSAlmacenamiento.size() == 0 && pServer != NULL) {
501
modelo->PACSAlmacenamiento = pServer->ID;
504
if ( (modelo->accion == GIL::IModeloIntegracion::TA_Dicomizar && modelo->PACSAlmacenamiento.size() == 0) ||
505
(modelo->accion == GIL::IModeloIntegracion::TA_Obtener && modelo->PACSObtencion.size() == 0) )
507
throw HL7XMLException(_Std("You must define a default PACS in the integration XML or in the settings menu"), xpp, "CONF/template");
509
models.push_back(modelo);
511
} //fin de parseo de gnkworkflows
514
throw HL7XMLException(_Std("Setting not found"), xpp, "CONF");