MODELOS PARA INTEROPERABILIDADE DE SISTEMAS … · entre sistemas através do envio de mensagens,...

189
UNIVERSIDADE FEDERAL DE SANTA CATARINA DEPARTAMENTO DE INFORMÁTICA E ESTATÍSTICA CURSO DE SISTEMAS DE INFORMAÇÃO KARINE PETRY PAULA MARIEN ALBRECHT LOPES MODELOS PARA INTEROPERABILIDADE DE SISTEMAS HOSPITALARES UTILIZANDO PADRÃO HL7 Trabalho de Conclusão de Curso apresentado como parte dos requisitos para obtenção do grau de Bacharel em Sistemas de Informação FLORIANÓPOLIS, 2005/2

Transcript of MODELOS PARA INTEROPERABILIDADE DE SISTEMAS … · entre sistemas através do envio de mensagens,...

UNIVERSIDADE FEDERAL DE SANTA CATARINA DEPARTAMENTO DE INFORMÁTICA E ESTATÍSTICA

CURSO DE SISTEMAS DE INFORMAÇÃO

KARINE PETRY PAULA MARIEN ALBRECHT LOPES

MODELOS PARA INTEROPERABILIDADE DE SISTEMAS

HOSPITALARES UTILIZANDO PADRÃO HL7

Trabalho de Conclusão de Curso apresentado como parte dos requisitos para obtenção

do grau de Bacharel em Sistemas de Informação

FLORIANÓPOLIS, 2005/2

Karine Petry

Paula Marien Albrecht Lopes

MODELOS PARA INTEROPERABILIDADE DE SISTEMAS

HOSPITALARES UTILIZANDO PADRÃO HL7

Trabalho de Conclusão de Curso apresentado como parte dos

requisitos para obtenção do grau de bacharel em

Sistemas de Informação

Orientador: Prof. Dr. Rer. Nat. Aldo Von Wangenheim

Co-orientador: Bel. Rafael Simon Maia

Banca Examinadora: Me. Rafael Andrade

Bel.Thiago Ramos dos Santos

III

AGRADECIMENTOS

Aos nossos pais pelo incentivo e apoio durante nossas vidas.

Pelos quitutes oferecidos pela Andrea nos dias cansativos de trabalho.

Pela oportunidade oferecida pelo professor Aldo no desenvolvimento deste projeto.

Ao nosso co-orientador Rafael Simon Maia que apesar de comer nossas bolachas, muito nos

ajudou nos momentos de dificuldade.

A todos os colegas do laboratório de Telemedicina, responsáveis pela nossa necessária perda

de concentração.

Ao Eduardo pela paciência e pelos almoços tardios.

Ao Thiago Machado e Evandro Espindola pela amizade e companheirismo oferecidos durante

todo o curso.

Enfim, agradecemos a todos que de alguma forma contribuíram para este trabalho.

IV

“Bem-vindas ao mundo real!!!”

Rafael Simon Maia, 04/04/2005.

V

RESUMO A aceitação em grande escala da informática proporcionou maior investimento no setor. Em

decorrência disto, houve um aprimoramento tecnológico em hardware e software. Dessa

forma, diversos sistemas de informação foram desenvolvidos. Surge então, o problema da

interoperabilidade- sistemas necessitam se comunicar para permitir o acesso às informações.

Assim, torna-se indispensável o estabelecimento de padrões com o intuito de promover esta

tão esperada interoperabilidade. A área de saúde por manipular com informações de elevada

importância deve receber um tratamento especial, dessa forma, em 1987, um conjunto de

membros de diversos países reuniu-se com o objetivo de elaborar um padrão de caráter

internacional que promova a interoperabilidade de sistemas da área de saúde. Este padrão foi

denominado de HL7. O HL7 é um padrão reconhecido pela ANSI que permite a comunicação

entre sistemas através do envio de mensagens, sendo que sua flexibilidade permite a

interoperabilidade de sistemas independente dos equipamentos, sistemas operacionais,

linguagens e banco de dados utilizados. Explorando ainda mais esta flexibilidade, verificou-se

que é possível o desenvolvimento de um middleware projetado segundo as especificações do

padrão HL7 capaz de facilitar a integração de sistemas legados com os sistemas de última

geração.

Palavras-chave: interoperabilidade, saúde, HL7, flexibilidade, mensagens, middleware, sistemas legados.

VI

Listas de Abreviaturas ABRAMGE – Associação Brasileira de Medicina de Grupo AMB – Associação Médica Brasileira ANSI – American National Standards Institute CID – Código Internacional de Doenças DATASUS – Departamento de Informação e Informática do Sistema Único de Saúde DICOM – Digital Imaging and Communications in Medicine EDIFACT – Electronic Data Interchange For Administration, Commerce and Transport HIPAA – Health Insurance Portability and Accountability Act HIS – Hospital Information System HL7 – Health Level Seven IEEE 1073 – Standard for Medical Device Communications ISO – International Standards Organization LOINC – Logical Observation Identifiers Names and Codes NCDCP – National Council for Prescription Drug Programs OSI – Open System Interconnection PACS – Picture Archive and Communications System PEP – Prontuário Eletrônico de Paciente PRC – Padronização de Registros Clínicos SBIS – Sociedade Brasileira de Informática em Saúde SNOMED - Systematized Nomenclature of Medicine XML – Extensible Markup Language

VII

Listas de Figuras Figura 1 – Modelo ISO / OSI ...................................................................................................21 Figura 2 – O evento "admissão de paciente" origina o envio automático de informação........27 Figura 3 – Formato de uma mensagem HL7 ............................................................................28 Figura 4 – Constituição de uma mensagem de identificação de paciente(A01).......................29 Figura 5 – Mensagem HL7 para admissão de paciente ............................................................29 Figura 6 – Alguns tipos de mensagens .....................................................................................30 Figura 7 – Admissão de Paciente – Mensagem ADT-A01 ......................................................31 Figura 8 – Exemplos de eventos da mensagem ADT...............................................................31 Figura 9 – Segmentos da mensagem de solicitação de informação de paciente ......................31 Figura 10 – Mensagem HL7 para solicitação de informação de paciente................................32 Figura 11 – Segmento resposta Confirmação...........................................................................32 Figura 12 – Mensagem HL7 ACK ...........................................................................................32 Figura 13 – Segmentos da resposta à solicitação de informação de paciente ..........................33 Figura 14 – Mensagem HL7 resposta à solicitação de informação de paciente.......................33 Figura 15 – Mensagem de atualização dados do paciente........................................................33 Figura 16 – Principais segmentos do padrão HL7....................................................................34 Figura 17 – Geração dos analisadores léxico e sintático ..........................................................41 Figura 18 – Tabela da Análise Léxica ......................................................................................45 Figura 19 – Gramática referente ao campo MSH.....................................................................47 Figura 20 – Arquitetura do Modelo Especializado..................................................................48 Figura 21 – Estrutura do servidor (tabelas base de dados) .......................................................48 Figura 22 – Tabela de Configurações do servidor....................................................................49 Figura 23 – Tabela de Caixa de Saída ......................................................................................49 Figura 24 – Tabela de Erros .....................................................................................................49 Figura 25 – Arquitetura do Modelo Genérico ..........................................................................50 Figura 26 – Mensagens Trocadas Entre Aplicação e Cliente...................................................53 Figura 27 – Mensagens Trocadas Entre Cliente x Servidor .....................................................54 Figura 28 – Mensagem de solicitação de dados de paciente ....................................................55 Figura 29 – Mensagem de resposta à solicitação de dados de paciente ..................................55 Figura 30 – Cadastro de Paciente .............................................................................................75 Figura 31 – Recebimento de mensagem...................................................................................75 Figura 32 – Prontuário Eletrônico - Recebimento de Cadastro de Paciente ............................76 Figura 33 – Prontuário Eletrônico - Recebimento de resultado de exames..............................76 Figura 34 – Prontuário Eletrônico - Mensagem de recebimento de cadastro...........................76 Figura 35 – Gerência de Exames - Cadastro Exame ................................................................77 Figura 36 – Gerência Exames - Buscar Paciente......................................................................77 Figura 37 – Gerência Exames - Resultado Exame ...................................................................78 Figura 38 – Gerência Exames - Mensagens Recebidas............................................................78 Figura 39 – Servidor HL7 - Recebimento de mensagem admissão de paciente ......................79 Figura 40 – Cliente HL7...........................................................................................................79

VIII

Sumário

1 INTRODUÇÃO.......................................................................................................................7

1.2 JUSTIFICATIVA .............................................................................................................8 1.3 OBJETIVO .......................................................................................................................9

1.3.1 Objetivo Geral ...........................................................................................................9 1.3.2 Objetivos Específicos ................................................................................................9

1.4 MÉTODO .........................................................................................................................9 2 A INFORMATIZAÇÃO NA ÁREA DE SAÚDE................................................................11

2.1 VANTAGENS DA INFORMATIZAÇÃO NA ÁREA DA SAÚDE ............................11 2.2 INFORMATIZAÇÃO DA SAÚDE NO MUNDO ........................................................12 2.3 INFORMATIZAÇÃO DA SAÚDE NO BRASIL .........................................................13

3 INTEROPERABILIDADE DE SISTEMAS.........................................................................17 3.1 INTEROPERABILIDADE DE SISTEMAS HOSPITALARES ...................................17

3.1.2 Padronização............................................................................................................17 4 TECNOLOGIAS E PADRÕES ............................................................................................20

4.1 HL7.................................................................................................................................20 4.1.1 Princípios Básicos do Padrão HL7 ..........................................................................21 4.1.2 Versões Publicadas ..................................................................................................24 4.1.3 Potencialidades do HL7...........................................................................................26 4.1.4 Utilizações das versões 2.x......................................................................................26 4.1.5 Especificação da Versão 2.3....................................................................................27 4.1.6 Quem utiliza HL7? ..................................................................................................34

4.2 MIDDLEWARE.............................................................................................................35 4.3 PROGRAMAÇÃO PARALELA E DISTRIBUÍDA .....................................................37

4.3.1 C++..........................................................................................................................39 4.4 G.A.L.S...........................................................................................................................40

5 SISTEMAS MODELOS .......................................................................................................43 5.1 GRAMÁTICA................................................................................................................43 5.2 ARQUITETURA............................................................................................................48

5.2.1 Modelo Especializado .............................................................................................48 5.2.2 Modelo Genérico .....................................................................................................49

5.3 FUNCIONALIDADES ..................................................................................................51 5.3.1 Modelo Especializado .............................................................................................51 5.3.2 Modelo Genérico .....................................................................................................52

5.4 MODELO ESPECIALIZADO X MODELO GENÉRICO............................................55 6 CONCLUSÃO.......................................................................................................................57 7 TRABALHOS FUTUROS....................................................................................................58 REFERÊNCIAS .......................................................................................................................59 ANEXO 1 – ANÁLISE DE REQUISITOS .............................................................................62 ANEXO 2 – GRAMÁTICA IMPLEMENTADA....................................................................80 ANEXO 3 – ARTIGO ..............................................................................................................87 ANEXO 4 – CÓDIGO FONTE................................................................................................91

7

1 INTRODUÇÃO

O surgimento da informática pode ser visto como um passo fundamental para se

atingir a era da sabedoria. Com o decorrer dos tempos, e o aprimoramento tecnológico,

tornou-se possível armazenar grandes volumes de dados; em seguida, permitiu-se analisar

informações para gerar conhecimento e, agora estamos em busca da sabedoria usando como

fonte o conhecimento adquirido das nossas informações.

Já que é praticável armazenar informações, é conseqüentemente vital compartilhá-las

com outros sistemas, dessa maneira, diversos protocolos foram desenvolvidos para

proporcionar a comunicação entre os mais variados tipos de sistemas, incluindo dispositivos,

sistemas operacionais, aplicativos e bases de dados. Como os investimentos no setor

tecnológico partem geralmente do meio empresarial, a grande maioria destes mecanismos foi

projetada para a área de negócios. Porém, tornou-se evidente que o ambiente de saúde

também merece uma atenção especial, pois os registros de informações de saúde de um

paciente como laudos, sinais vitais, exames laboratoriais, e imagens médicas, não devem ser

armazenados exclusivamente em papel, e sim, em meio eletrônico, para então proporcionar

uma disponibilidade agilizada, de modo confiável, com integridade garantida, admitindo

redução de custos e ainda com uma independência física do local de armazenamento. Dessa

forma, surgiu o Prontuário Eletrônico de Pacientes (PEP), com a finalidade de permitir a

integração e armazenamento da informação clínica e administrativa de pacientes de forma

individual.

O emprego do prontuário eletrônico trouxe como conseqüência imediata à necessidade

de uma padronização para garantir a transmissão das informações clínicas de um paciente,

entre os mais diversos sistemas de informação que englobam um ambiente de saúde. Assim,

com este propósito, foram projetados alguns padrões, destacando-se o padrão HL7 (Health

Leavel Seven) a nível internacional.

O HL7 tem o objetivo de definir normas para a transmissão de dados como, por

exemplo, dados sobre registros de pacientes, admissão, transferências de pacientes, seguros,

taxas e contas a pagar, pedidos e testes de laboratório, exames de imagem, observações

médicas e de enfermagem, prescrições de dieta, pedidos à farmácia, pedidos de suprimentos e

arquivos; enfim, o padrão HL7 tem a capacidade de comunicar sistemas considerados

8

heterogêneos como o sistema administrativo de um hospital, o sistema financeiro e o sistema

de informações clínicas do paciente. (FERNANDES et al., 1999)

O HL7 não restringe o sistema operacional, nem a linguagem de programação a ser

utilizada para a troca de informação. Além disso, o HL7 é independente de meio físico e de

protocolo de comunicação. O padrão HL7 permite que o implementador defina suas próprias

mensagens, o que mais uma vez, torna-o flexível.(HENRIQUES, CARVALHO, 2005).

É a possibilidade de interoperabilidade entre os diversos sistemas da área de saúde

utilizando duas modelagens distintas, porém desenvolvidas conforme as especificações do

padrão HL7 que serão abordadas como objeto de estudo.

1.2 JUSTIFICATIVA

Em virtude da disparidade existente entre os sistemas projetados para o mundo dos

negócios e aqueles que englobam a área da saúde, tornou-se necessário à elaboração de

mecanismos que facilitem as transações num meio constituído por diversas peculiaridades

como é o serviço de saúde em qualquer lugar do globo.

Torna-se justificável realizar um estudo sobre uma tecnologia que tenha como

propósito solucionar alguns problemas encontrados em um ambiente de saúde:

• Evitar o desperdício de tempo cadastrando novamente um paciente em outra

aplicação pertencente ao mesmo sistema de saúde;

• Evitar repetição desnecessária de exames, laudos e imagens médicas quando o

paciente não puder apresentar o resultado dos seus exames (extravio de exames

de qualquer forma);

• Manter o histórico dos medicamentos em uso e já utilizados pelo paciente;

• Reduzir os custos operacionais;

• Manter a uniformidade e coerência dos dados.

Portanto, com a finalidade de utilizar um padrão de transmissão de informações em

Sistemas de Informação Hospitalares - os denominados HIS(Hospital Information System), e

constatar a importância de sua utilização, será implementado o padrão HL7 em um ambiente

fictício.

9

1.3 OBJETIVO

1.3.1 Objetivo Geral

Desenvolver modelos de sistemas que proporcionem a comunicação entre sistemas de

saúde heterogêneos através do uso do padrão HL7.

1.3.2 Objetivos Específicos

Para a implementação destes modelos de sistemas foram definidos como objetivos

específicos:

• Desenvolver um modelo que apresente uma arquitetura cliente-servidor e que

implemente o padrão HL7 diretamente na aplicação, denominado aqui de Modelo

Especializado;

• Desenvolver um modelo que contemple a arquitetura cliente-servidor de modo que

as aplicações existentes necessitem de uma mínima alteração para possibilitar a

troca de informações. Neste modelo, denominado Modelo Genérico, o padrão HL7

é implementado com a funcionalidade de um middleware HL7;

• Construir a gramática para estabelecer a estrutura de uma mensagem, através do

desenvolvimento dos analisadores léxico, sintático e semântico, a partir da

linguagem especificada pelo padrão HL7;

• Desenvolver aplicações para comprovar a transmissão de mensagens, cumprindo

com todos os requisitos e especificações da interface de comunicação exigidas pelo

middleware HL7.

1.4 MÉTODO

Para o desenvolvimento de um modelo de interoperabilidade de sistemas hospitalares

foi indispensável o conhecimento aprofundado do funcionamento da troca de mensagens

proposto pelo padrão HL7, bem como qual a versão do padrão HL7 deveria ser

implementada.

10

Depois de compreendida a especificação do padrão HL7, tornou-se necessário adquirir

o conhecimento de quais são as aplicações que constituem este ambiente de saúde, quais as

informações que uma aplicação deseja obter de outras aplicações (buscas), em qual sistema

operacional executa, em qual linguagem de programação foi desenvolvido. Para que assim, o

padrão HL7 seja implementado de acordo com as características de cada aplicação ou

sistema.1

Conhecidos os requisitos e características de cada sistema, partiu-se para o

levantamento de quais tipos de mensagens e segmentos deveriam ser implementados de

acordo com a versão do padrão HL7 selecionado.

Para o desenvolvimento dos modelos, partiu-se para a seleção da linguagem de

programação para implementar o padrão HL7, uma vez identificados os tipos de mensagens.

Constatou-se que esta linguagem deve suportar programação paralela e distribuída, para que

contemple a arquitetura cliente- servidor e multithreading.

A fim de satisfazer todas as exigências necessárias para a interoperabilidade utilizando

o padrão HL7, iniciou-se o desenvolvimento de um cliente e de um servidor, utilizando a

linguagem C++ e banco de dados PostgreSQL. Esta estrutura foi projetada, de forma que

possa ser operada tanto no ambiente Microsoft Windows quanto no Unix, e para que suporte

que um mesmo equipamento possa executar mais de uma aplicação utilizando apenas um

cliente HL7.

Uma vez implementado a arquitetura cliente servidor, implementou-se a gramática da

versão 2.3 do padrão HL7, porque está ainda é a versão mais utilizada no momento, utilizando

o aplicativo G.A.L.S. para gerar os analisadores léxico e sintático.

Ao nível de desenvolvimento e teste foram utilizados os sistemas operacionais

Microsoft Windows 2000, Microsoft Windows XP e Linux Slackware 10.1.

Para comprovar a utilidade do padrão HL7 foram desenvolvidas três aplicações que

simulam o funcionamento de um sistema hospitalar. As aplicações Cadastro de Pacientes e

Prontuário Eletrônico de Pacientes foram desenvolvidas em Object Pascal (Borland Delphi

7.0), já a aplicação Gerência de Exames foi desenvolvida em C++. Foram selecionadas

linguagens diferentes para comprovar que o uso dos modelos desenvolvidos é independente

de linguagens de programação e de plataforma.

1 Com o objetivo de cumprir o cronograma, os sistemas hospitalares também foram implementados para simular o comportamento de sistemas legados.

11

2 A INFORMATIZAÇÃO NA ÁREA DE SAÚDE A adoção da informática na área da saúde pode ser considerada como algo

relativamente novo. Seu desenvolvimento teve início na década de sessenta, onde as primeiras

atuações compreenderam análises estatísticas, epidemiológicas, sistemas de informatização

hospitalar e prontuários eletrônicos. (RODRIGUES, 2000).

Na década seguinte, o uso de recursos informatizados passou a ser utilizado também em

sistemas administrativos hospitalares. Com o aparecimento e desenvolvimento de

microcomputadores, tornou-se viável a informatização em sistemas de controle de farmácias e

laboratórios hospitalares. (RODRIGUES, 2000).

A década de noventa foi marcada por um aumento na utilização da informática em

gerenciamento e administração na área da saúde com o objetivo de suprir as crescentes

necessidades de organização exigidas pelo setor de saúde que se encontra em expansão

constantemente. (RODRIGUES, 2000).

2.1 VANTAGENS DA INFORMATIZAÇÃO NA ÁREA DA SAÚDE

A informatização na área da saúde tem como propósito atender às necessidades

operacionais dos diversos setores ou serviços, proporcionando uma integração e uma

interação entre as mais variadas unidades que compreendem um ambiente de saúde. Para isto,

foram projetados sistemas de informação para a saúde. Assim, geralmente, dentro de um

sistema que rege um hospital, podem-se encontrar subsistemas com módulos do laboratório

central, da admissão, da radiologia, do centro cirúrgico entre outros; estes diversos módulos

apresentam vantagens como total acesso às informações produzidas em cada setor do hospital,

maior facilidade e agilidade em pedidos de exames, localização rápida e fácil do histórico

clínico do paciente, possibilitando desse modo, a recuperação de diagnósticos decorridos

anteriormente, internações, consultas ambulatoriais, exames antigos ou ainda cirurgias

realizadas. (SILVA et al., 1999).

Através de um sistema de informação em saúde, ainda é possível obter-se um controle

total sobre os leitos hospitalares, evitando a subutilização e possibilitando uma noção mais

precisa das necessidades de cada enfermaria em um dado momento (remédios, refeições,

aparelhos e instrumentos, entre outros). O módulo na emergência irá cadastrar todos os

atendimentos ocorridos nos setores de emergência ou pronto atendimento. Assim, evita-se o

12

alto índice de perda de documentos que ocorre nas emergências e maior agilidade durante

atendimento. O módulo do laboratório ainda pode permitir armazenamento de resultado de

exames, coleta, requisições, permitindo assim a possibilidade do laboratório estar localizado

dentro do hospital ou ser independente do hospital. (SILVA et al., 1999).

Estas podem ser consideradas como facilidades iniciais proporcionadas pela

informatização na área da saúde, que ainda traz como conseqüência o exercício da

telemedicina junto com o avanço da telecomunicação, permitindo assim transferência de

dados eletrônicos (como imagens de alta resolução, som, imagens ao vivo e informações do

paciente) de um local a outro através de um sistema de redes e telecomunicações. Assim, a

telemedicina possibilita que o diagnóstico médico possa ser realizado mesmo estando o

paciente geograficamente distante do centro médico. (RODRIGUES, 2000).

2.2 INFORMATIZAÇÃO DA SAÚDE NO MUNDO

Nos últimos anos, houve uma maior preocupação com a informatização na área de

saúde em todo o mundo. Os investimentos em sistemas de saúde nos países desenvolvidos, é

considerável. Podemos citar como um dos principais interessados, os Estados Unidos, que

buscam por novas tecnologias e investem constantemente na interoperabilidade de sistemas.

(VASCONCELLOS, 2004).

Nos Estados Unidos, a discussão sobre padrões de informação em saúde está em

evidência. Existe uma busca para a constituição de uma infra-estrutura de informação em

saúde, que permita a troca de informações e a avaliação de riscos à saúde. Com esse objetivo,

o governo norte-americano adotou recentemente cinco padrões para uso na integração entre

agências federais: HL7, NCDCP (National Council for Prescription Drug Programs), IEEE

1073 (Standard for Medical Device Communications), DICOM (Digital Imaging and

Communications in Medicine) e LOINC (Logical Observation Identifiers Names and Codes).

Esses padrões são elaborados com o objetivo de promover a interoperabilidade de sistemas,

mas ainda não está se verificando a interoperabilidade de componentes de diferentes

fornecedores. (VASCONCELLOS, 2004).

Nos últimos dez anos uma nova tendência surgiu nos Estados Unidos - a integração

entre serviços e instituições de saúde. Este movimento iniciou com a consolidação do setor de

saúde privado americano ao redor de conglomerados (Integrated Healthcare Delivery

13

Systems). Os conglomerados se formam pela junção de instituições que tinham histórias,

sistemas e tradições diferentes, cujos sistemas, a partir do momento da fusão, devem ser

integrados. Assim, necessitou-se o desenvolvimento de uma nova tecnologia que é o cadastro

central de pacientes, ou MPI (Master Patient Index ou Cadastro Integrado de Pacientes). O

MPI permite ligar múltiplos domínios cadastrais com informações sobre pessoas e pacientes.

Assim, é possível reunir todos os dados de saúde de um indivíduo ao longo do processo de

assistência à saúde. Este tipo de integração permite melhor faturamento, melhores análises do

uso dos serviços e dos resultados. (VASCONCELLOS, 2004).

Já quando se trata da informatização em países em desenvolvimento, é possível

identificar um grave atraso da informatização na área da saúde, principalmente ao nível de

armazenamento e compartilhamento de informações médicas. Os motivos de tal atraso podem

ser citados como:

• Forma de trabalho do profissional de saúde: profissionais da área da saúde pouco

habituados com o uso de computadores nas tarefas diárias e contrárias às regras que se

fazem necessárias para que a implantação de sistemas de informática seja bem

implementada;

• Estrutura organizacional dos sistemas de saúde: desatualização e despreparo para as

mudanças sociais que o avanço tecnológico vem trazendo à sociedade;

• Custos elevados: como o investimento inicial de um processo de informatização é

relativamente alto, muitas vezes opta-se pela manutenção do sistema tradicional.

(SAÚDE TOTAL, 2000).

2.3 INFORMATIZAÇÃO DA SAÚDE NO BRASIL

Para se manter adaptado às novas tecnologias, o Brasil, também passou a investir na

informatização hospitalar e ambulatorial. Mediante esse interesse, verificou-se que existem

algumas particularidades nos sistemas de saúde brasileiros devido ao contexto econômico,

político, social, cultural, histórico, entre outros. Uma das características mais notáveis nos

sistemas de saúde do Brasil refere-se ao enfoque, que é predominantemente administrativo,

priorizando procedimentos de contabilidade, como a prestação de contas e o faturamento, em

detrimento de todos os demais aspectos, ou seja, a informação clínica é deixada para segundo

plano. Um outro ponto de destaque relevante é que os sistemas hospitalares e ambulatoriais

14

brasileiros divergem consideravelmente nos setores públicos e privados, isto ocorre em

conseqüência da prioridade atribuída ao faturamento que possui regras diferentes em cada

setor. (VASCONCELLOS, 2004).

No Brasil é muito comum a fragmentação dos sistemas de informação em saúde. Segundo Vasconcellos(2004):

“Organizações complexas de saúde quase sempre utilizam vários sistemas de informação em paralelo: um ou mais sistemas centrais para dar conta do atendimento principal; sistemas administrativos; sistemas departamentais; entre outros. Cada um destes sistemas possui uma parte da informação sobre os pacientes e sobre as atividades da instituição, gerando necessidade continuada de integração entre sistemas heterogêneos. A solução mais comum para este problema é o uso de interfaces ad hoc entre os vários sistemas. A implementação e uso destas interfaces podem ser vistas como uma solução trabalhosa, mas mesmo assim, deve continuar sendo muito popular no curto e médio prazo, principalmente considerando que muitos sistemas legados continuarão sendo utilizados por tempo indeterminado. Portanto, a adoção de padrões de informação em saúde facilita e torna mais direto o desenvolvimento destas interfaces, reduzindo muito o seu custo. “

Apesar da utilização da Internet ser consideravelmente difundida, a integração dos

sistemas de informação em saúde brasileiros com a Web ainda não atinge a mesma proporção.

Já existem iniciativas para permitir acesso através da internet a algumas funcionalidades, tais

como resultados de exames, agendas, cadastros, entre outras. (VASCONCELLOS,2004).

Os sistemas brasileiros aos poucos começaram a oferecer recursos para facilitar a

emissão de laudos. Atualmente, estão finalmente se voltando para o tratamento das imagens e

alguns o estão fazendo seguindo padrões internacionais como PACS (Picture Archive and

Communications System) e DICOM.

A essência dos sistemas de informação na área de saúde está no prontuário eletrônico

de paciente, que deve reunir informações de todo o processo de atendimento. Apesar de

existirem dificuldades técnicas, o prontuário eletrônico está ganhando aceitação de maneira

acelerada, isto se deve também porque o preconceito e a dificuldade das novas gerações de

médicos em lidar com a informática está desaparecendo. Estudos realizados nos Estados

Unidos indicam que quando o sistema de prescrição é parte de um conjunto de sistemas

clínicos seu uso é aceito mais rapidamente pelos médicos; e também consideram que a adoção

de sistemas de prescrição eletrônica é uma estratégia para a diminuição de erros médicos e a

melhoria da qualidade da assistência. (VASCONCELLOS,2004).

15

De acordo com Vasconcellos(2004), legalmente, no Brasil, o prontuário eletrônico

ainda não pode substituir o papel. Além disso, há muitas questões tecnológicas envolvidas no

projeto do prontuário eletrônico: a representação dos conceitos clínicos por meio de

vocabulários adequados, a modelagem conceitual dos dados clínicos, a tecnologia de

armazenamento a ser utilizada, entre outras.

Uma vez que a modelagem conceitual dos dados clínicos é pouco estruturada a

tecnologia de bancos de dados relacional não é eficiente. A tecnologia XML (Extensible

Markup Language) está gradativamente assumindo um papel relevante e cumprindo a

promessa de se tornar a principal ferramenta de suporte ao prontuário eletrônico e ao

intercâmbio de informações entre sistemas. A versão 3.x do padrão HL7 é baseada em XML,

podendo então facilitar a integração.

Mas mesmo com o uso das tecnologias citadas acima, ainda persiste dois problemas

em se tratando da identificação de pacientes: o problema de estabelecer corretamente a

identidade da pessoa que se apresenta a um serviço de saúde, ou seja, um problema de

identificação; e o problema de estabelecer referências cruzadas entre as informações relativas

a uma mesma pessoa, porém armazenadas em diferentes sistemas ou bancos de dados; ou

armazenadas em um mesmo sistema, no entanto vinculadas a eventos ou momentos

diferentes, ou seja, um problema de integração.(VASCONCELLOS, 2004).

O problema de identificação é muito importante sempre, mas é crucial para os

prestadores de serviços privados de saúde e planos de saúde, que precisam estabelecer com

precisão e antecipadamente se um determinado paciente, é ou não, elegível para receber

algum tratamento. A solução mais simples e comum para o problema de identificação, embora

de eficácia limitada, é estabelecer documentos de identificação, através de cartões. Novas

técnicas e abordagens incluem o uso de biometria e reconhecimento de digitais. A HIPAA

(Health Insurance Portability and Accountability Act) norte-americana prevê o uso de

biometria como alternativa para identificação de pessoas e esse tipo de recurso já começa a

ser usado também no Brasil. (VASCONCELLOS, 2004).

No Brasil, o Cartão Nacional de Saúde é a mais abrangente iniciativa de identificação

de pacientes. Até meados de 2004, cerca de dois terços da população brasileira já estavam

recadastrados. A integração do sistema Cartão Nacional de Saúde com os demais sistemas

públicos de saúde ainda não foi concluída, mas o processo está avançando.

(VASCONCELLOS, 2004).

16

No que se refere ao uso de software no Brasil para o setor de saúde, pode-se destacar

que a utilização de software livre é considerada pequena, mas crescente. Apesar do

pioneirismo de outros países no desenvolvimento de sistemas de saúde, no Brasil a aquisição

de sistemas provenientes do mercado externo não é significativa devido às particularidades

das normas governamentais brasileiras não estarem implementadas nestes sistemas.

(VASCONCELLOS, 2004).

Quanto ao uso de hardware, podemos considerar que o computador de mão pode

contribuir muito para a informatização na área de saúde se convertendo então, a médio prazo,

na tão esperada clinical workstation, ou seja, na interface mais comum entre os médicos e os

sistemas computadorizados de informação em saúde. (VASCONCELLOS, 2004).

Foi estabelecido em 2002, que a SBIS (Sociedade Brasileira de Informática em Saúde)

seria responsável pela certificação de software na área da saúde, para atender às normas

técnicas para o Uso de Sistemas Informatizados para a Guarda e Manuseio do Prontuário

Médico, da resolução 1639/2002 do Conselho Federal de Medicina. A SBIS também é

responsável pela elaboração do Manual de Requisitos de Segurança, Conteúdo e

Funcionalidades para Sistemas de Registro Eletrônico em Saúde (RES), que consolida os

requisitos para que Sistemas RES possam ser certificados pela SBIS e o Conselho Federal de

Medicina. Outra importante iniciativa da SBIS é a adoção de um Código de Ética para os

Profissionais de Informática em Saúde. O Código limita-se a questões éticas vinculadas à

relação entre o especialista em Informática em Saúde e seus interlocutores (pacientes,

profissionais da saúde, pessoal administrativo, instituições de saúde, operadoras de planos de

saúde e agências governamentais, etc.) e não inclui qualquer referência aos procedimentos

técnicos. (FRICK, LORO, 2004).

Considerando o retorno proporcionado pela informatização com o surgimento de

tecnologias concebidas especialmente para a área da saúde, cabe às instituições brasileiras,

investirem seu capital a fim de manterem-se sintonizadas com as novidades e partir para a

adoção de tecnologias que respeitem a usabilidade necessária no ambiente de saúde.

17

3 INTEROPERABILIDADE DE SISTEMAS

“Interoperabilidade é a habilidade de dois ou mais sistemas (computadores, meios de comunicação, redes, software e outros componentes de tecnologia da informação) de interagir e de intercambiar dados de acordo com um método definido, de forma a obter os resultados esperados.” (BRASIL, 2005).

Interoperabilidade não é somente a integração entre sistemas e nem somente a

integração de redes. Não referencia unicamente troca de dados entre sistemas e não contempla

simplesmente definição de tecnologia. Na verdade, é uma soma de todos esses fatores,

considerando, também, a existência de um legado de sistemas, de plataformas de hardware e

software instaladas. A interoperabilidade tem por meta a consideração de todos os fatores para

que os sistemas possam atuar cooperativamente, fixando as normas, as políticas e os padrões

necessários para consecução desses objetivos. (BRASIL, 2005).

3.1 INTEROPERABILIDADE DE SISTEMAS HOSPITALARES

Com a evolução da tecnologia e a crescente informatização em ambientes clínicos e

hospitalares no início dos anos noventa, começou-se a pensar na distribuição das informações

armazenadas nestes sistemas. Desta forma, a interoperabilidade entre os sistemas hospitalares

passou a ser o principal foco de estudo para a disseminação das informações médicas.

Porém, quando se pensa em interoperabilidade, na qual sistemas "conversam" com

outros sistemas e com equipamentos biomédicos, não se pode deixar de pensar em padrões.

Para essa interoperabilidade entre os sistemas é necessário que os dados sejam estruturados e

não ambíguos. Além disso, é fundamental ter dados com uma semântica que possa ser

compreendida pelos outros sistemas (COSTA, 2001).

3.1.2 Padronização A padronização da informação em saúde é necessária devido a diversos fatores, dos

quais pode-se destacar segundo Costa (2001):

• Diversidade de fontes e termos (existem mais de 150.000 conceitos médicos);

18

• Sistemas estão em diferentes plataformas de software e hardware,

necessitando de uma linguagem comum (padrão) para que esses possam

intercambiar informações;

• Para facilitar a busca e a comunicação de informações;

• Devido a pontos importantes para a área da saúde como estatística,

epidemiologia, prestação de contas (faturamento), indexação de documentos e

pesquisa clínica;

• Viabilizar o uso de sistemas de apoio à decisão e sistemas de alerta, que são

indispensáveis para a interoperabilidade entre os sistemas.

Os padrões elaborados para a área de saúde podem ser classificados segundo Costa

(2001) em:

• Identificação: para pacientes (Social Security Number - nos Estados Unidos,

Cartão Nacional de Saúde no Brasil), médicos (Número no Conselho Regional

de Medicina);

• Comunicação: padrão para mensagens entre sistemas (HL7, X12, EDIFACT

(Electronic Data Interchange For Administration, Commerce and Transport),

XML;

• Conteúdo e Estrutura: padronização do Registro Clínico do DATASUS

(Departamento de Informação e Informática do Sistema Único de Saúde),

ABRAMGE (Associação Brasileira de Medicina de Grupo);

• Representação de dados clínicos (Códigos): CID (Código Internacional de

Doenças), SNOMED (Systematized Nomenclature of Medicine), LOINC, AMB

(Associação Médica Brasileira);

• Confidencialidade, Segurança e Autenticação;

• Indicadores de Qualidade, Conjunto de Dados e Diretrizes.

Além desses existem padrões para imagens, como o DICOM e padrões para objetos,

como o CORBAMed.

No Brasil, quanto à padronização, é possível identificar o DATASUS como

responsável pela padronização das informações médicas do país. De acordo com Costa

(2001), um exemplo de padronização brasileira é o comitê de Padronização de Registros

19

Clínicos (PRC) que aprovou, através de um processo aberto, um conjunto mínimo de dados

que um PEP deve ter, além de elaborar a Document Type Definition (DTD) correspondente à

estrutura de dados proposta pelo PRC para troca de dados via XML.

Ainda no Brasil, outro exemplo de padronização é o chamado Padrão ABRAMGE,

utilizado para a troca de faturamento entre prestadores de serviços médicos e as operadoras de

planos de saúde. (COSTA, 2001).

Porém existe a necessidade de adoção de um padrão a nível internacional que

regularize a troca de informações dentro de um contexto global. Com esta finalidade que

surgiu o padrão de comunicação para troca de dados clínicos como o HL7.

20

4 TECNOLOGIAS E PADRÕES A fim de produzir modelos de interoperabilidade de sistemas hospitalares, é necessário

entender o que é o padrão HL7, seu princípio, suas versões publicadas, suas potencialidades

para que então possa ser realizada a construção de sua gramática.

Já para a implementação de uma arquitetura cliente servidor é necessário conhecer

quais recursos e funcionalidades que a linguagem selecionada proporciona para programação

paralela e distribuída para atingir os objetivos esperados.

São as tecnologias selecionadas para concepção deste modelo de interoperabilidade

que serão abordadas a seguir.

4.1 HL7

Em 1987, foi fundada uma organização sem fins lucrativos denominada Health Level

Seven, com a responsabilidade de produzir normas para a área de saúde, relacionados com a

informação clínica e administrativa. A sede da instituição está localizada nos Estados Unidos,

mas conta com delegações de vinte e sete países como Alemanha, Argentina, Austrália,

Brasil, Canadá, China, Coréia, Croácia, Dinamarca, Espanha, Finlândia, França, Grécia,

Holanda, Índia, Irlanda, Itália, Japão, Lituânia, México, Nova Zelândia, Polônia, Reino

Unido, República Tcheca, Suíça, Taiwan e Turquia. Teve seu reconhecimento

internacionalmente, pela ANSI (American National Standards Institute) em 1994.

O estabelecimento das normas é realizado pelos seus membros, que incluem

organizações governamentais, vendedores, consultores e engenheiros de sistemas. A

organização atualmente é constituída por mais de 2000 membros, representando

aproximadamente 500 organizações, sendo que 90% dos principais fabricantes/fornecedores

de sistemas de informação clínica dos Estados Unidos estão incluídos. Estes se encontram

divididos em Grupos de Trabalho, que por sua vez são organizados em comitês técnicos e

grupos de interesses especiais. Os comitês técnicos são diretamente responsáveis pela

especificação das normas, enquanto os grupos de interesses especiais investigam novas áreas

que possam ser incluídas nas especificações do HL7.

O HL7 tem por missão:

21

“Promover o desenvolvimento de normas relacionadas com a troca, integração, partilha e recuperação de informação eletrônica na saúde, assim como no apoio à prática médica e administrativa e avaliação dos serviços de saúde. Em concreto, a sua missão orienta-se para o desenvolvimento de uma linguagem flexível, de baixo custo, possível de parametrizar, seguindo uma metodologia que permita a interoperabilidade entre os mais diversos sistemas de informação na área de saúde”.

A origem do termo Level Seven está associada à camada de mais alto nível do modelo

de comunicação da ISO/OSI, ou seja, a camada de aplicação. A camada de aplicação

relaciona-se com a implementação de sistemas abertos, portanto, não é necessária nenhuma

restrição quanto à comunicação, tipo de rede ou meio físico, resultando apenas como função a

definição da estrutura da informação para trocar, a seqüência e instantes para o fazer e as

correspondentes mensagens de confirmação ou erro. Dessa forma, estabeleceu-se que o

padrão HL7 tem a finalidade de definir o conteúdo e formato das mensagens que poderão ser

trocadas na camada de aplicação. (HENRIQUES, CARVALHO, 2005).

A figura 1 mostra as sete camadas do modelo ISO/OSI.

Figura 1 – Modelo ISO / OSI

4.1.1 Princípios Básicos do Padrão HL7

4.1.1.1 Visão Geral do HL7

A unidade básica de informação, a ser trocada entre os vários intervenientes, é

designada no padrão HL7 por mensagem. O padrão especifica além das características

principais da troca de mensagens entre sistemas distintos, os vários tipos de mensagem e

respectiva constituição.

Transporte

Sessão

Enlace

Rede

Apresentação

Aplicação

Física

Protocolo de Aplicação

Protocolo de Apresentação

Protocolo de Sessão

Protocolo de Transporte

Protocolo de Rede

Protocolo de Enlace

Protocolo de Física

Transporte

Sessão

Enlace

Rede

Apresentação

Aplicação

Física

22

Genericamente uma mensagem é constituída por segmentos, que por sua vez são

constituídos por campos, sendo estes últimos organizados em componentes.

Tipos de Mensagens e Formato

O padrão especifica quais as mensagens a serem trocadas entre os diversos setores do

hospital. Dentre os vários tipos de mensagens definidos pelo HL7 podem ser citadas: gestão

de pacientes ao nível de admissão, transferências e saídas, pedidos, resultados, observações

clínicas e contabilidade.

O padrão HL7 define o formato das mensagens, ou seja, descreve como os dados

devem ser representados, o seu tipo e quais os caracteres usados para delimitar os vários

segmentos numa mensagem.

Eventos

O padrão HL7 especifica as circunstâncias em que as mensagens devem ocorrer,

regras como conseqüência de eventos (trigger event). Por exemplo, se for definido que os

dados pessoais de um paciente devem ser disponibilizados, então quando houver uma

admissão de paciente, automaticamente deve ser desencadeada uma mensagem que transmita

a informação a todos os interessados (consulta não solicitada – unsolicited message).

Confirmação/Erro

O padrão HL7 também define os procedimentos que devem ser realizados na

ocorrência de certos erros entre as aplicações. Por exemplo, caso uma aplicação não receba os

dados que esperava, esta pode comunicar o fato para a aplicação emissora através de uma

mensagem de erro. Por outro lado, se a transmissão dos dados foi efetuada corretamente,

então uma mensagem de confirmação (ACK-acknowledge) pode igualmente ser enviada.

Garantindo, portanto confiabilidade na troca de mensagens.

4.1.1.2 Arquitetura Física do Sistema

Quanto a arquitetura física do sistema definida pelo padrão HL7 tem-se:

• O sistema computacional pode estar organizado de uma forma central ou

distribuído;

23

• A totalidade das especificações definidas na norma HL7 não necessita

obrigatoriamente ser implementada.

• A troca de informação pode ser efetuada com base em diversos sistemas

operacionais ou linguagens de programação.

• O padrão HL7 é independente do meio físico e protocolo de comunicação,

podendo, por exemplo, ser usado o protocolo TCP/IP.

4.1.1.3 Interoperabilidade

Como um dos objetivos principais do padrão é ser o mais abrangente possível, o HL7

não assume qualquer arquitetura particular para o sistema de comunicação, pelo contrário,

pretende servir de suporte à comunicação entre diversas aplicações distintas permitindo seu

uso inclusive em sistemas heterogêneos.

Devido, a complexidade de informações existentes num sistema hospitalar e a

inexistência de um vocabulário comum, levou-se a adoção de uma abordagem onde é

atribuída liberdade ao utilizador de implementar as suas próprias mensagens. Porém, esta

abertura, apresenta resultados indesejáveis, por exemplo, muitas vezes é necessário que uma

grande quantidade de analistas para priorizar a construção e implementação do padrão, ou

seja, campos e/ou segmentos opcionais, ambíguos e talvez até mesmo inconsistentes,

requerem o estabelecimento de uma interpretação única e objetiva por parte dos projetistas

dos sistemas participantes. Em outras palavras, devido à flexibilidade do padrão HL7, embora

a estrutura sintática das mensagens esteja claramente definida, a semântica é demasiadamente

livre para acomodar qualquer possibilidade essencial na formação do modelo.

Já que é responsabilidade da aplicação proceder à adaptação das suas estruturas de

dados às normas definidas pelas mensagens HL7, a implementação desta última não é, um

procedimento trivial. Isto porque é necessário considerar um esforço inicial de

desenvolvimento e a sua implementação é uma tarefa trabalhosa. Sendo assim, o problema foi

reconhecido, tanto pela instituição HL7 como por aqueles que desenvolvem ferramentas

computacionais. Com a finalidade de facilitar esta tarefa inicial, têm surgido diversas

aplicações comerciais capazes de automatizar o processo de implementação prática do padrão.

A correta implementação do padrão HL7 permite:

24

• Interoperabilidade - Fornece formatos e protocolos para a troca de informação

entre diversos sistemas computacionais na área da saúde, permitindo desta forma

integrar equipamentos distintos;

• Flexibilidade - Pode ser implementada computacionalmente utilizando uma grande

variedade de softwares;

• Tornar possível a unificação de interfaces distintas, uma vez normalizados os

vários formatos existentes;

• Minimizar o número e o tempo necessários à implementação de interfaces;

• Melhorar os meios de suporte à decisão pela capacidade de integrar informação

clínica entre os vários setores do hospital.

4.1.2 Versões Publicadas

4.1.2.1 HL7 Versão 1

A primeira versão, 1.0, foi apresentada em 8 de outubro de 1987 e definia o âmbito e o

formato das mensagens. Apesar de várias funcionalidades terem sido sugeridas muitas delas

não foram, contudo implementadas, por exemplo, as relativas aos dados contabilísticos do

paciente.

4.1.2.2 HL7 Versões 2.x

A versão 2.0 surgiu em setembro de 1988 e depois desta uma série de atualizações

foram realizadas. A versão 2.1, surgida em junho de 1990, constituiu a primeira versão a ser

reconhecida e efetivamente adotada (nos Estados Unidos). Em junho de 1994 a HL7 torna-se

membro certificado pela ANSI e em dezembro desse mesmo ano surge à versão 2.2, e a sua

aplicação começa na prática a ser amplamente implementada. Em março de 1997, são

proporcionadas funcionalidades (já bem estabelecidas) para a troca de informação relativa à

gestão do paciente (admissão, transferências e saídas), contabilidade, observações clínicas,

gestão da informação médica, entre outras. Apesar de em 1998 ter sido introduzida a versão

2.3.1 e em 2000 a versão 2.4. A versão 2.3 continua a ser a mais utilizada na prática, sendo

atualmente apenas válidas as versões 2.3 ou superiores. (HENRIQUES, CARVALHO, 2005).

De fato, referem-se como aspectos negativos das versões 2.x os seguintes:

• Processo de integração é complexo e moroso;

• Algumas especificações permitem interpretações distintas;

25

• Demasiadas opções;

• Falta de suporte a novas tecnologias, tais como:

o Web

o Orientadas a objetos

o XML

o Segurança.

4.1.2.3 HL7 Versão 3

Desde 1996 a organização HL7 está trabalhando no desenvolvimento da versão 3, fato

motivado principalmente pelas limitações das versões 2.x. Assim, a versão 3 é radicalmente

distinta da versão 2 em vários aspectos. A versão 3 recebeu certificação da ANSI no dia 05

maio de 2005. (HL7, 2005).

Em primeiro lugar, o padrão terá por base um modelo orientado a objetos RIM

(Reference Information Model) que proporciona uma visão coerente dos dados a serem

trocados assim como das relações entre os diferentes tipos de dados. Assegurando assim, que

as mensagens sejam consistentes e que na prática sejam verdadeiramente utilizáveis pelas

aplicações comunicantes. Esta abordagem produz um número maior de eventos e de formatos

de mensagens, mas permite a obtenção de mensagens mais precisas, isto é, com muito poucas

opcionalidades.

Em segundo lugar, as mensagens serão desenvolvidas seguindo a metodologia MDF

(Message Development Framework). Este processo envolve o desenvolvimento de diversos

modelos, incluindo o RIM já referido e o PRA (Patient Record Architecture). O objetivo

principal dessa abordagem será produzir objetos consistentes e a sua representação através de

mensagens. A versão 3 também permite a extensão para diferentes formatos de troca de

informação. A versão 2.x permite apenas um formato baseado em caracteres ASCII. A versão

3 suporta XML, ActiveX e Corba. Para proporcionar a interoperabilidade, a versão 3 tira

proveito das funcionalidades do XML, desenvolvendo uma arquitetura baseada em XML, a

CDA (Clinical Document Architecture), que proporciona um modelo de trocas com diversos

níveis de complexidade e que permite a criação de documentos XML que incorporam

mensagens HL7.

26

4.1.3 Potencialidades do HL7

A adoção do padrão HL7 é considerada importante para o ambiente hospitalar pelos seguintes motivos:

• Aceitação: a norma encontra-se em uso por um número significativo de países,

Estados Unidos, Japão, Canadá, Inglaterra, França, são alguns exemplos. No caso

dos Estados Unidos registra-se o uso do padrão HL7 em 90% das instituições

hospitalares, o que por si só justifica a sua utilização;

• Versatilidade: permite satisfazer necessidades tanto no nível de instituições (entre

hospitais) quanto no nível dos setores de um hospital (farmácia, laboratórios,

enfermarias);

• Sistema aberto: tem por base padrões não proprietários, que resultam da

cooperação entre diversas entidades, por exemplo, utilizadores, fornecedores,

engenheiros de sistemas;

• Reconhecimento: por ser formada a partir da cooperação entre diversas

instituições hospitalares a instituição HL7 é certificada pela ANSI e pela ISO;

• Ativa: a instituição incentiva e promove a cooperação entre os principais

interessados na área da saúde para assegurar que as normas produzidas atendam às

necessidades dos interessados;

• Flexibilidade: permite um grau de liberdade para suprir as necessidades especificas

de um utilizador, além de possuir uma grande variedade de mensagens pré-

definidas.

4.1.4 Utilizações das versões 2.x

A utilização da versão 2.3 (e mais recentes) nos sistemas de informação na área de

saúde deve-se a grande quantidade de equipamentos em atividade que usam efetivamente esta

norma e consequentemente condicionam a evolução da norma. Por outro lado, como ainda

existem incertezas a respeito da versão 3, torna-se claro que a maioria dos fabricantes

continuará a suportar a norma HL7 2.x, o que virá ainda mais a reforçar o seu potencial.

(HENRIQUES, CARVALHO, 2005).

Dessa forma, mesmo que os equipamentos venham a suportar versão 3, ainda assim,

terão que manter a compatibilidade com a versão 2.x, e a transição não será nunca um

27

processo instantâneo. Como recentemente a certificação da ANSI foi recebida, calcula-se que

a utilização efetiva da versão 3 será a partir de 2006.( HENRIQUES, CARVALHO, 2005).

A instituição HL7 afirmou que futuras revisões na norma 2.x serão mínimas ou mesmo

inexistentes. Uma das exceções, e que constitui uma área recentemente desenvolvida,

relaciona-se com mecanismos capazes de codificar a norma 2.x para XML, seguindo um

algoritmo formal, o que veio reforçar ainda mais o potencial da versão 2.x. (HENRIQUES,

CARVALHO, 2005).

4.1.5 Especificação da Versão 2.3

Uma vez que a comunicação entre duas aplicações é realizada através do envio de

mensagens, tudo se inicia quando ocorre algum tipo de evento. Como primeiro exemplo de

evento temos quando o emissor envia uma mensagem ao receptor a fim de repassar alguma

informação como a admissão de paciente, ou seja, a mensagem não solicitada. Um outro tipo

de evento pode ser desencadeado quando o emissor solicita alguma informação ao receptor.

Portanto, seja qual for à situação, uma mensagem surge sempre de uma de duas razões: de

uma consulta ou de um evento que desencadeia uma mensagem (não solicitada).

Em resposta as mensagens, podem ser solicitadas informações de confirmação de

recebimento. A figura 2 mostra o envio de uma mensagem através do evento admissão de

paciente(ADT ^ A01) que exige confirmação de recebimento. Neste caso, as aplicações

receptoras enviam uma mensagem de confirmação de recebimento para o emissor.

Figura 2 – O evento "admissão de paciente" origina o envio automático de informação

28

4.1.5.1 Composição da Mensagem

4.1.5.1.1 Mensagens No padrão HL7 uma mensagem é a menor unidade de dados que pode ser transferida

entre dois intervenientes. É constituída por segmentos e é delimitada por um inicio de bloco,

caractere Hex0b, e por um fim de bloco, o caractere Hex1c seguido de Hex0d (carriage return

<cr>). A figura 3 representa uma mensagem HL7.

Figura 3 – Formato de uma mensagem HL7

4.1.5.1.2 Segmentos Um segmento é cada uma das partes que constituem uma mensagem, disponibilizando um

meio de agrupar informação de uma forma lógica. Os segmentos são representados por um

conjunto de três caracteres (bytes), por essa razão são designados como identificadores do

segmento. A presença de um segmento numa determinada mensagem pode ser obrigatória (R-

required), opcional (0-optional) ou então pode ocorrer mais que uma vez, isto é, pode ser

repetida. Quando for opcional utilizam-se colchetes [ ] para indicar o fato, por exemplo, a

notação [AL1] significa que o segmento relacionado com alergias é opcional nessa

mensagem. De forma análoga, a notação { } permite especificar a repetição de um segmento,

assim {AL1} indica que o segmento das alergias pode ser repetido se for necessário. As

notações anteriores podem ser combinadas, [{AL1}] significando que o segmento das alergias

é opcional e que, além disso, pode ser repetido.

4.1.5.1.3 Campos O conteúdo semântico da mensagem, como os detalhes relativos do paciente, está

definido nos campos que constituem cada um dos segmentos. Os campos têm comprimento

variável e encontram-se separados entre si pelo caractere “|”.

Os campos por sua vez são constituídos por cadeias de caracteres sendo cada um deles

pertencente a um dado tipo, como por exemplo, o tipo ST representa uma string. Para cada um

dos tipos de dados poderá ainda ter associado um valor obtido a partir de uma tabela. Por

exemplo, o tipo de dados sexo (do tipo String), será definido pelos seguintes valores (F-

Feminino, M-Masculino, H–Hermafrodita, T-Transexual, U-Desconhecido).

<Hex 0b> <HL7 Message segments> <cr> <Hex 1c><cr>

29

Os campos ainda podem ter uma estrutura bem definida, de que é exemplo o tipo de

dados DT-date, definido por YYYYMMDD. Desta forma o dia 28 de Maio de 2005 define-se

por 20050528.

Caso o campo transmitido contenha uma cadeia de caracteres vazia (|””|), então isso

significa que o campo está vazio, ou seja, o receptor deverá eliminar os valores representados.

4.1.5.1.4 Componentes e sub-Componentes Alguns campos podem conter vários componentes, sendo neste caso delimitados pelo

separador “^”. Estes campos são usualmente designados por campos compostos, de que o

campo nome do paciente é um exemplo, uma vez que pode conter vários componentes, por

exemplo, nome próprio e apelido.

Concluindo, uma mensagem é constituída por segmentos, que por sua vez são

constituídos por campos, subdivididos em componentes. A figura 4 representa a constituição

de uma mensagem.

Figura 4 – Constituição de uma mensagem de identificação de paciente(A01)

4.1.5.2 Construção de Mensagens

O padrão HL7 distingue diversos tipos de mensagens. Por exemplo, na figura 5

mostra-se o exemplo de uma mensagem relativa à admissão de um paciente (ADT^A01),

composta pelos segmentos MSH, EVN, PID.

Figura 5 – Mensagem HL7 para admissão de paciente

MSH|^~\&|ADT1|CADPACIENTE|LABADT|CADPACIENTE|20052242048||ADT^A01|MSGADT1200522420485|P|2.3<cr> EVN|A01|20052242048<cr> PID|||PATID1234 5 M11||Silva^Marcelo^Loyola^II^Dr.|Maria Ferreira|19451227|M||A|Rua Minas Gerais 55||(48)9833-8956|(48)398-6665|Português|S|lutheran |989896632|96556|98989^055^65||U|São Paulo|0|3|Brasileiro||Brasileiro||<cr>

30

Podemos considerar os principais tipos básicos de mensagens:

• Gestão de pacientes ou ADT - relativas à gestão da estada do paciente no hospital,

admissão, transferência e saídas de pacientes por esta razão também conhecidas

por mensagens ADT-admissions, discharges, transfers. São desencadeadas sem

uma consulta prévia explícita (unsolicited messages);

• Pedidos/Querys – utilizadas para requisição (consulta) de informação. Uma

situação típica ocorre quando um dos setores (farmácia, laboratório) consulta o

sistema de admissão com respeito à informação de um paciente;

• Resultados/Observações – Resulta como resposta a uma mensagem do tipo

(pedido/query) e a sua função é permitir a transmissão de observações clínicas, por

exemplo;

• Outras - relativas à informação contabilística e financeira, experiências clínicas,

bases de dados, etc.

Todas as mensagens têm uma estrutura semelhante, por exemplo, o primeiro segmento

é sempre o cabeçalho (MSH) contendo informação sobre a mensagem e seu conteúdo.

Seguem-se depois os demais segmentos, específicos de cada uma das mensagens. A figura 6

exibe os principais tipos de mensagens do padrão HL7.

Figura 6 – Alguns tipos de mensagens

4.1.5.2.1 Mensagens Relativas a Gestão de Pacientes (ADT)

É utilizado para transmitir informação relativa à admissão, transferência e saída de um

paciente no hospital. Dependendo do tipo de evento (trigger event) é possível distinguir vários

31

tipos de mensagens. O evento que origina a mensagem é a admissão do paciente (A01), sendo

uma mensagem para a qual não houve um pedido explicito (unsolicited). Como regra geral

esta informação deve ser difundida para os vários setores (enfermarias, laboratórios, etc). A

figura 7 mostra os segmentos de uma mensagem de admissão de paciente.

Figura 7 – Admissão de Paciente – Mensagem ADT-A01

Para cada um dos eventos, se distinguem vários tipos de mensagens. A figura 8 mostra

alguns desses eventos.

Figura 8 – Exemplos de eventos da mensagem ADT

4.1.5.2.2 Pedidos/Query

Um dos exemplos típicos de uma mensagem de consulta de informação é a mensagem

RQI – Request for Patient Information como ilustrado na figura 9.

Figura 9 – Segmentos da mensagem de solicitação de informação de paciente

32

A mensagem representada na figura 10 mostra o pedido de informação (RQP^A19)

sobre o paciente cujo identificador é TR54.

Figura 10 – Mensagem HL7 para solicitação de informação de paciente

4.1.5.2.3 Resultados/Observações

A mensagem mais simples de resposta é a mensagem de confirmação (ACK Message).

A sua constituição é mostrada na figura 11, onde o segmento MSA permite especificar num

dos seus campos a confirmação/erro gerada como um dos seguintes valores: AA-Application

Accepted, AE-Application Error, AR-Application Rejected.

Figura 11 – Segmento resposta Confirmação

A figura 12 representa uma mensagem de confirmação de uma mensagem de admissão

no formato HL7.

Figura 12 – Mensagem HL7 ACK

Em resposta a uma mensagem RQI-Request for Patient Information (pedido), pode ser

enviada uma mensagem de resposta RPI- Response for Patient Information, cujos segmentos

podem ser observados na figura 13.

MSH|^~\&|GerenciaExames|150.162.67.45|CadastroPaciente||20051003091521||RQP^A19|IDMSH20051003 091521|P|2.3<cr> QRD|20051003 09:15:21|T|I|TR54|||2000|TR54|DEM|GE||T<cr> QRF|GerenciaExames|||||ANY|ANY|ALL|0800<cr>

MSH|^~\&|CadastroPaciente|ADT|CadastroPaciente|ADT|20051003 091411||ACK^|IDMSH20051003 091411|P|2.3<cr> MSA|AA|IDMSH20051003 091411<cr>

33

Figura 13 – Segmentos da resposta à solicitação de informação de paciente

A mensagem representada na figura 14 mostra o envio de uma mensagem RPI como

resposta a uma consulta. A mensagem deverá indicar que o paciente sofre de uma atrial

fibrillation.

Figura 14 – Mensagem HL7 resposta à solicitação de informação de paciente

Para a exemplicar a atualização de dados de paciente, como no recebimento de

resultado de um exame, é utilizada a mensagem do tipo PIN ^A08, como mostra a figura 15.

Figura 15 – Mensagem de atualização dados do paciente

São apresentados na figura 16 exemplos de segmentos que compõem o padrão HL7.

Embora seja fundamental a representação dos campos de cada segmento para a

implementação de uma interface que utilize o HL7, não é escopo deste trabalho detalhá-los.

MSH|^~\&|GerenciaExames|150.162.67.45|ProntuarioEletronico|IPConfirmacao|20051003 09:15:28|27013|PIN^A08|IDMSH20051003 09:15:28|P|2.3<cr> QRD|20051003 09:15:28|T|I|TR54|||2000|TR54|RES |GE||T<cr> DSP||Hemograma Completo (Leucocitos:[3] Eritrocitos:[2] Hematocitos:[1] Hemoglobina:[4] Colesterol:[5] Glicose:[6] Creatina:[7] Sodio:[8] Potassio:[9] Calcio:[1] Fosforo:[3])|<cr> DSP||Urina (PH:[1] Densidade:[2] Hemacias:[3] Proteinas:[4] Glicose:[5] Bacterioscopia:[44])|<cr>

MSH|^~\&|EKG||CDB||||RPI^R04|X981672|P<cr> MSA|AA|CDB22222<cr> QRD|198904180943|R|I|Q4412|||10|PATID5239|0123456-1|RES<cr> OBR||||93000^EKG REPORT|||198801111330<cr> OBX|1|CE|8601-7^EKG IMPRESSION:^LN|1|^ATRIAL FIBRILATION||||||F<cr>

34

Figura 16 – Principais segmentos do padrão HL7

4.1.6 Quem utiliza HL7?

A adoção de padrões, principalmente aqueles reconhecidos internacionalmente cria a

possibilidade de integração de sistemas em diversos níveis como municipal, estadual, federal

e entre instituições prestadoras de serviço.

Como o padrão HL7 é submetido a aprovação de uma organização internacional

(ANSI), a aceitação e o interesse dos países pelo HL7 vem aumentado constantemente.

35

Acredita-se que esse fato ocorra e tende a crescer devido à necessidade da melhoria dos

serviços clínicos e hospitalares a um baixo custo oferecido pelo HL7.

No Brasil, entre os centros de saúde que contam com o sistema HL7, encontra-se o

Hospital Italiano (Grajaú/RJ) e algumas companhias pré-pagas que já estão trabalhando com

parte do padrão HL7 para o envio de mensagens, onde podemos citar algumas fornecedoras

de planos de saúde (MARCH, 2002) que operam em São Paulo e outras cidades do Brasil

como: Omint, Marítima Seguro Saúde, Central Nacional Unimed - Cooperativa Central, Sul

América Aetna Saúde Seguros S/A, Porto Seguro Saúde S/A. (SALUTIA, 2005). Ainda é

possível citar centros de pesquisa brasileiros, interessados nas funcionalidades fornecidas pelo

protocolo HL7 assim como o projeto SIDI da Universidade Federal do Rio Grande do Sul em

parceria com a Escola Paulista de Medicina.

A nível internacional, pode-se observar:

• Alta implantação: Estados Unidos, Alemanha, Reino Unido, Holanda, Japão,

Canadá, Austrália, México, Índia e Argentina;

• Iniciativas regionais: Finlândia, Croácia, Lituânia, Suíça, Dinamarca e Coréia;

• Pequenos desenvolvimentos: Espanha, Itália, França, Grécia e Venezuela.

4.2 MIDDLEWARE �

O termo middleware é utilizado em uma série de situações, nos mais diversos

contextos e com os mais diversos objetivos. Inicialmente era visto como uma camada de

tradução ou comunicação, localizada entre as aplicações e o sistema operacional, atualmente

abrange a concepção de uma biblioteca de suporte a execuções de chamadas remotas.

(MACÊDO, 2004).

“Na Enciclopédia de Computação Distribuída, Bakken define middleware como uma classe de tecnologia de software projetada para gerenciar a complexidade e a heterogeneidade inerente aos sistemas distribuídos. Talarian Corporation caracteriza middleware como o software que é usado para mover informação de um programa para um ou mais programas, protegendo o desenvolvedor de dependências do protocolo de comunicação, sistemas operacionais e hardware. Campbell, por sua vez, afirma que middleware é qualquer camada de software que se situa acima da infra-estrutura de sistemas distribuídos e abaixo da camada da aplicação”. (COSTA, 2004).

36

Assim, de modo geral, conclui-se que o middleware é uma camada de software que

possui como finalidade disponibilizar serviços que facilitem o trabalho do desenvolvedor.

Esses serviços podem estar relacionados a diversos requisitos de aplicações: distribuição,

armazenamento, tolerância a falhas, balanceamento de carga, dentre outras. (MACÊDO,

2004).

Uma camada de software disponibilizada pelo middleware realiza todo o

procedimento de empacotamento, envio e desempacotamento de requisições via canal de

comunicação utilizando serviços como troca de mensagens, isto é, o middleware fornece um

nível de abstração intermediário entre o ambiente de execução e a aplicação, tornando

transparente ao desenvolvedor da aplicação detalhes do ambiente, como de localização de

serviços, linguagens de programação, heterogeneidade de plataformas e hardware usados, etc.

(MACÊDO, 2004).

Um tipo de middleware freqüentemente utilizado é o orientado a mensagens (Message

Oriented Middleware - MOM). Neste contexto, a função do middleware se aproxima ao

trabalho de um repositório, onde mensagens podem ser armazenadas e recuperadas,

fornecendo assim, um mecanismo para comunicação assíncrona entre aplicações, utilizando

para isso APIs como os sockets. Os principais produtos que seguem a linha dos MOM’s são o

MQSeries da IBM, o MSMQ da Microsoft e o SmartSockets da Talarian. (MACÊDO, 2004).

A chamada de procedimentos remotos (Remote Procedure Call - RPC), desenvolvida

pela Sun Microsystems, em 1982, foi uma das primeiras tentativas de definição de um

middleware para oferecer mecanismos de abstração a fim de gerenciar a complexidade do

desenvolvimento de sistemas distribuídos. Esse tipo de middleware apresenta uma série de

ferramentas e definições que possibilitam a execução de procedimentos remotos com a

mesma simplicidade e facilidade da execução de procedimentos locais. (MACÊDO, 2004).

A evolução do middleware baseado em RPC foi o desenvolvimento do ORB (Object

Request Broker), acrescentando as vantagens da orientação a objetos na chamada de

execuções remotas. Neste, além das questões de comunicação em rede, também são

disponibilizados serviços como segurança, controle de acesso, transações distribuídas e

balanceamento de carga. São exemplos, deste tipo de middleware, o CORBA da OMG,

DCOM da Microsoft, EJB da Sun, e o TAO (The Ace ORB). (MACÊDO, 2004).

Apesar do baixo nível de abstração e da necessidade de se conhecer aspectos de redes

de computadores como portas e números IPs (GUEDES, 2004), utilizamos um middleware

37

orientado a mensagens para a construção do middleware HL7. Este tipo de middleware foi

selecionado visto que o uso de sockets é permitido na maioria das linguagens de programação

existentes, e também porque o cliente desenvolvido deverá executar em uma máquina local.

O uso de middleware é adequado quando é buscado um padrão para

interoperabilidade, escalabilidade e gerência da complexidade através da utilização de

abstrações e serviços. Assim, a finalidade do projeto de middleware é terceirizar a construção

de serviços, tratar a heterogeneidade e ocultar complexidade. Proporcionando, dessa forma, o

desenvolvimento de aplicações flexíveis, modulares e confiáveis. Este é o objetivo central do

middleware desenvolvido neste trabalho.

4.3 PROGRAMAÇÃO PARALELA E DISTRIBUÍDA

Um programa paralelo é um programa que define ações que podem ser executadas

simultaneamente, ou seja, contém dois ou mais processos que trabalham juntos para executar

uma determinada tarefa, onde cada processo é um programa seqüencial. (MONGELLI, 2003).

Os processos em um programa paralelo trabalham juntos comunicando-se entre si. A

comunicação pode ser feita através de variáveis compartilhadas ou por troca de mensagens.

Mas, independente da forma de comunicação os processos precisam sincronizar-se, seja

através de exclusão mútua (região critica) ou sincronização condicional. Para a exclusão

mútua existe um mecanismo denominado mutex que permite o acesso único aos dados e ou

recursos, criando filas quando os mesmos estiverem bloqueados. (MONGELLI, 2003).

Já um programa distribuído é aquele em que um conjunto de processos seqüenciais

executa em paralelo e, comunicam-se através de passagem de mensagens (primitivas send e

receive) em uma rede de computadores. No entanto, um programa distribuído também pode

ser executado em um sistema de multiprocessadores com memória compartilhada, ou até

mesmo em um sistema monoprocessador. (MAZZUCO, 1999).

A computação distribuída propõe o modelo de um sistema utilizando o paradigma

cliente-servidor, onde a aplicação que assume o papel de servidor aguarda mensagens,

executa serviços e retorna resultados, enquanto que a aplicação cliente, é aquela que

estabelece a conexão, envia mensagens para o servidor e aguarda mensagens de

resposta.(WIKIPEDIA).

38

Para que a transmissão de mensagens possa ser efetuada, vários fatores devem ser

considerados, por exemplo, quando se envia uma mensagem é fundamental saber quem está

enviando (emissor), para quem está sendo enviada (destino) e o que está sendo enviado (tipo).

Além disso, pode-se ter garantia, de que a mensagem chegou ao seu destino, que a mesma

seja aceita pelo receptor remoto, que haja alguma forma de confirmação, que haja algum

tratamento de exceção, entre outros. Já para o recebimento de uma mensagem, é necessário

saber para qual, ou quais processos a mensagem que acaba de chegar é destinada, se deve ser

criado um processo especial para a manipulação dessa mensagem, se a mensagem é enviada a

um processo existente e que está ocupado, será ela enfileirada ou simplesmente descartada.

(MAZZUCO, 1999).

Para promover a transmissão de mensagens é recomendado o uso de API (Application

Programming Interface) de comunicação. As APIs fornecem primitivas de comunicação que

podem ser chamadas a partir do código, para que o acesso aos serviços de comunicação possa

ser utilizado pelas aplicações. As principais APIs de comunicação são: (SIQUEIRA)

• Sockets: portas de comunicação locais ou de rede (versão segura SSL);

• Suportes de RPC (Remote Procedure Call): permitem chamar métodos remotamente

(exemplos: Java RMI, Sun RPC, ...);

• Canais de eventos: permitem notificar threads e processos dos eventos ocorridos no

sistema (exemplos: JMS, CORBA Notification Service, …).

O socket é uma abstração desenvolvida pela Universidade Berkeley proposta

originalmente para o sistema operacional Unix BSD (por isso, também conhecidos como

sockets Berkeley), que estabelece um conjunto de interfaces para uma aplicação acessar os

protocolos da camada de transporte do modelo OSI (vide figura 1). Muitos fabricantes de

computadores e sistemas operacionais como SUN, COMPAQ, Tektronic, adotaram a interface

sockets Berkeley. A Microsoft também optou pelo socket projetando uma interface

denominada winsock. Basicamente, a API sockets é constituída por constantes, estruturas e

funções que são chamadas em uma seqüência adequada definindo algoritmos genéricos para

aplicações cliente-servidor. (GUEDES, 2001).

Os sockets representam uma porta de um canal de comunicação associada a uma

aplicação. São identificados por um inteiro de 16 bits (0 a 65535), onde os valores de 0 a 1024

39

são reservados para os serviços padronizados pela rede, os demais valores podem ser

utilizados livremente pelos desenvolvedores. (SIQUEIRA).

Os sockets podem ser classificados segundo o tipo de protocolo de transporte

empregado durante a transmissão de mensagens:

• Sockets Stream: utilizam o protocolo TCP (transporte confiável, isto é, verifica se os

dados são enviados de forma correta, na seqüência apropriada e sem erros; e em modo

orientado à conexão, ou seja, a aplicação envia um pedido de conexão para o destino e

usa esta conexão para transferir dados);

• Sockets Datagrama: utilizam o protocolo UDP (transporte não confiável, ou seja, não

garantem que os dados chegaram ao destino corretamente, e em modo não orientado à

conexão);

• Sockets Multicast: envio simultâneo de uma mensagem a um grupo de destinatários

sem estabelecimento de conexão.

4.3.1 C++

A linguagem de programação C++ é, na verdade um superconjunto da linguagem de

programação C. A linguagem C foi desenvolvida em 1972, por Dennis Ritchie e Ken

Thompson criaram a Linguagem C para aumentar o poder de sua antecessora a linguagem B.

O C demorou a se popularizar e apenas em 1978 com a publicação do livro “The C

Programming Language” de Bjarne Stroustrup pelos criadores de C e o lançamento do IBM

PC, em 1981, é que houve maior interesse por parte dos desenvolvedores. Assim que o

número de PC’s aumentava, também aumentava o número de programas desenvolvidos em C.

(MACIEL, 2004).

A tarefa de manutenção e compreensão do código fonte gerado tornou-se importante e

altamente complexa, visto que C utiliza programação estruturada, permitindo assim a total

liberdade aos desenvolvedores durante a implementação. Deste modo, cada desenvolvedor

implementava de forma diferenciada seus aplicativos, assim quando outro desenvolvedor via

a necessidade de manutenção havia grandes dificuldades para a compreensão do código.

A solução para este problema seria o uso da programação orientada a objetos, assim

surgiu a linguagem C++, projetada por Bjarne Stroustrup, inspirado em parte por outras

40

linguagens, como o Simula67 e Smalltalk, consideradas como algumas das mais puras

linguagens Orientadas a Objetos. (MACIEL, 2004).

No início da década de 80 não havia documentação de projeto de C++ e nem comitê

para aprovação dos padrões C++. Já em 1987, com a alta aceitação de C++ pelos usuários,

viu-se a necessidade de uma padronização formal da linguagem. Somente em 1995, foi

divulgado um projeto de padrão inicial para revisão pública e em 1998 um padrão

internacional formalmente aprovado para C++. (MACIEL, 2004).

4.3.1.1 Por que usar C++?

Optou-se pelo uso de C++: pela sua compatibilidade com os sistemas operacionais

Windows e Unix, pelo fato de ser uma linguagem de programação gratuita, por apresentar

maior velocidade de execução quando comparado a outras linguagens como Java e, por

último, ao contrário ao C, porque C++ é uma linguagem orientada a objetos.

Podemos descrever como principais vantagens do C++:

• Abstração de Dados: combina os dados e as funções usadas para manipulá-los,

de tal forma que os detalhes da implementação fiquem ocultos para outros

desenvolvedores, possibilitando o desenvolvimento de programas mais fáceis

de manter e de aprimorar;

• Orientada a Objeto: permite tornar um código existente facilmente

modificável sem, na realidade, alterar fisicamente o código;

• Programação Genérica: refere-se a um tipo de abstração no processo de

desenvolvimento de software, voltado para a construção de algoritmos que

independem de um determinado tipo ou estrutura de dados e que, no entanto,

sejam tão eficientes quanto se construídos acoplados a uma determinada

estrutura. A biblioteca STL ( Standard Template Library) de C++ utiliza a

programação genérica. (ARNAUT).

4.4 G.A.L.S.

O G.A.L.S.(Gerador de Analisadores Léxicos e Sintáticos) é um ambiente de

desenvolvimento destinado à geração de analisadores léxicos e sintáticos de uma gramática.

41

Foi desenvolvido em 2002 por Carlos Eduardo Gesser como trabalho de conclusão de curso

de Ciências da Computação, da Universidade Federal de Santa Catarina. (GESSER, 2002).

Um analisador léxico pode ser definido como um processo usado para analisar a

entrada de linha de caracteres, produzindo assim uma seqüência de símbolos chamados tokens

que podem ser manipulados mais facilmente por um leitor de saída, o parser.

Para facilitar o entendimento cita-se como exemplo, a análise de uma palavra, onde se

verifica, através da análise léxica, se existe ou não algum caractere que faz parte do alfabeto

da língua portuguesa. Assim, através da análise léxica da palavra “casa” pode-se afirmar que

não há caracteres na sentença que não pertençam ao nosso alfabeto, o mesmo não ocorre, por

exemplo, com a sentença ca$a, pois o símbolo “$” não pertence ao nosso alfabeto.

Partindo deste princípio pode-se construir um alfabeto e através da análise léxica,

testar se um token apresentado como entrada faz parte deste alfabeto.

Já o analisador sintático verifica recursivamente se uma combinação de tokens

pertence à gramática, utilizando para isto, um conjunto de regras previamente estabelecidas.

O GALS permite configurar aspectos dos analisadores (léxico e sintático) gerando

assim o Analisador Léxico, Analisador Sintático e ainda um Analisador Semântico vazio, para

a implementação do usuário. O GALS também permite a seleção da linguagem em que os

analisadores deverão ser gerados como Java, C++ e Delphi.

A figura 17 mostra a interface do aplicativo utilizado para a construção dos

analisadores léxicos e sintáticos.

Figura 17 – Geração dos analisadores léxico e sintático

42

Existem diversas ferramentas para a geração de analisadores léxico e sintático, como

por exemplo, LEX, GALEX, GAS e LISA. Uma ferramenta semelhante ao GALS e que

também executa as mesmas funcionalidades, é a ferramenta LISA. Ambas utilizam

convenções do padrão BNF(Backus Normal Form): os símbolos não-terminais são escritos em

letras maiúsculas. Os demais símbolos são terminais, com exceção dos meta símbolos: | . [ ] {

} < > . Se o terminal definido contiver qualquer meta símbolo, este deverá estar entre <>. O

terminal * é representado com < >. (GUIMARÃES).

43

5 SISTEMAS MODELOS

Com o objetivo de proporcionar o intercâmbio de informações entre sistemas clínicos

e hospitalares utilizando padrão de comunicação HL7, foram desenvolvidos dois modelos

com arquiteturas distintas, porém com a mesma meta: permitir a interoperabilidade entre

sistemas heterogêneos na área de saúde.

O primeiro modelo desenvolvido será aqui chamado de modelo especializado, devido

sua arquitetura cliente-servidor ser mais dependente da aplicação. O segundo modelo a ser

implementado será identificado como modelo Genérico pelo fato deste, contrário ao modelo

anterior, não apresentar dependência quanto à aplicação.

Para um melhor entendimento das estruturas e seus relacionamentos nos modelos aqui

propostos, primeiramente será necessário conhecer a gramática gerada para o

desenvolvimento dos sistemas modelos, bem como seus requisitos, arquiteturas e

funcionalidades.

5.1 GRAMÁTICA

Antes de descrevermos a gramática usada para a geração dos modelos desenvolvidos,

torna-se necessário conhecimento de alguns conceitos, utilizados para a geração da gramática,

como autômatos e linguagem.

O autômato ou autômato finito é um modelo matemático de um sistema, com entradas

e saídas discretas cujo principal interesse é sua capacidade de especificar finitamente

linguagens (ou procedimentos) infinitos. Sendo assim, autômato finito sempre poderá

determinar um conjunto de strings, considerando parte do conjunto as seqüências de entrada

que levarão o autômato a um estado de aceitação e rejeitando todas as outras. (GULIATO,

CARNIELLI, ZUFFO).

Existem vários motivos para se estudar a teoria dos autômatos. Em muitos casos eles

constituem um modelo útil para muitos elementos importantes de hardware e software. Como

exemplo de sua importância podemos citar dois exemplos de seu emprego:

44

• Procura e reconhecimento de padrões simbólicos: análise de grandes corpos de

textos, como coleções de páginas da web, a fim de encontrar ocorrências de

palavras, frases ou outros padrões;

• Analisador léxico: divisão do texto de entrada em unidades lógicas, como

identificadores, palavras-chave e pontuação. (ARAÚJO, et al.)

O segundo exemplo foi utilizado para o desenvolvimento dos sistemas modelos afim

de que haja o reconhecimento dos caracteres que compõem uma determinada string

(mensagem), seguindo assim as normas de especificação do HL7. Através da figura 18 é

possível observar os tokens (caracteres) aceitos pela análise léxica em uma mensagem no

formato HL7.

Uma gramática serve para definir qual o subconjunto de sentenças que faz parte de

uma determinada linguagem. Ela é um dispositivo formal para especificar uma linguagem

potencialmente infinita de uma forma finita. Pode-se dizer ainda que uma gramática é um

conjunto de leis de formação de uma cadeia, isto é, dada uma gramática é possível aplicarmos

suas leis de formação até que determinada string seja obtida ou derivada da gramática.

(MELLO, LACERDA,2001).

45

Figu

ra 1

8 –

Tab

ela

da A

nális

e L

éxic

a

46

As gramáticas foram divididas em quatro classes, capazes de gerar classes

correspondentes de linguagens, de acordo com a Hierarquia de Chomsky:

• GEF (gramática com estrutura de frase ou Tipo 0): não apresenta restrições

afora as próprias condições descritas para a existência de uma gramática;

• GSC (gramática sensíveis a contexto ou Tipo 1): possui uma restrição com

relação as leis de formação: dada uma lei de formação a�B, o tamanho de “a”

deve ser menor ou igual ao tamanho de B;

• GLC (gramática livre de contexto ou Tipo 2): uma gramática livre de contexto

é uma gramática sensível a contexto com uma restrição a mais: as produções

devem ser da forma A�a, onde A é um elemento não terminal, ou seja, o lado

esquerdo das produções devem conter sempre um, e apenas um, elemento não

terminal. Outra forma de se representar gramáticas livres de contexto é através

da forma normal de Backus (BNF). Neste caso, o símbolo � é substituído por

::= e os símbolos não terminais são representados entre <>;

• GR (gramática regular ou Tipo 3): uma gramática regular também é uma

gramática livre de contexto com restrições a mais: as produções devem

obedecer a forma A�aB ou A�b, onde A e B são símbolos não terminais, “a”

é um símbolo terminal e “b” é um símbolo terminal ou cadeia vazia. Assim,

pode-se resumir que, em todas as produções a cadeia da direita deve conter até

dois símbolos e nunca um símbolo terminal deve proceder a um terminal.

Uma vez compreendido o significado de cada termo da especificação do padrão HL7,

o passo seguinte envolveu a construção da gramática que represente a troca de mensagens no

padrão HL7. Devido à familiaridade e eficiência, foi utilizado o aplicativo G.A.L.S. (Gerador

de Analisadores Léxicos e Sintáticos), para a geração da gramática.

Já que a implementação estava baseada na versão 2.3 do HL7, onde existem diversas

flexibilidades, foi decidido especificar a gramática seguindo a especificação proposta pela

versão, ou seja, os campos de cada seguimento foram especificados na totalidade, mesmo que

mais tarde se constate que não poderão ser preenchidos pela aplicação.

O tipo de gramática desenvolvida na implementação dos modelos foi à gramática livre

de contexto recomendada para este tipo de aplicação: reconhecimento de tokens. Na figura 19,

é possível ser observado a especificação do campo MSH, especificado pelo HL7, utilizado nas

47

composições das mensagens. Além do MSH também foram utilizadas as especificações dos

seguintes campos nos respectivos modelos:

• Modelo especializado: MSH, MSA, PID, EVN;

• Modelo genérico: MSH, MSA, PID, EVN, QAK, DSP, QRD, QRF.

Figura 19 – Gramática referente ao campo MSH

A implementação dos demais campos poderá ser observada no Anexo 2.

Como a gramática do padrão HL7 pode ser representada através de uma gramática

livre de contexto, a classe do analisador escolhido para a implementação foi do tipo preditivo

(LL1), utilizando o modelo descendente (top-down), por isso, para a gramática gerar um

autômato determinístico, foi necessário o cumprimento de três requisitos:

1) Não poderá possuir recursão à esquerda;

2) Deverá estar fatorada;

3) Não poderá ser ambígua.

48

5.2 ARQUITETURA

5.2.1 Modelo Especializado

O primeiro modelo desenvolvido, caracterizado por apresentar uma arquitetura mais

simples, porém dependente da aplicação, ou seja, trata de uma arquitetura cliente-servidor em

que a aplicação deverá ser responsável pela implementação do padrão HL7. Na figura 20 é

possível a análise de sua estrutura.

Figura 20 – Arquitetura do Modelo Especializado

As aplicações (Aplicação A e Aplicação B) dizem respeito aos softwares presentes em

um ambiente clínico e/ou hospitalar. Ao nível de teste foram desenvolvidas duas aplicações

responsáveis pelo registro de dados demográficos de pacientes (admissão de pacientes) em

que a comunicação entre elas envolvia troca de mensagens referentes a uma inclusão de

paciente.

O sistema Servidor, representado na figura 21, é responsável pelo encaminhamento de

mensagens, e apresenta em sua estrutura, três tabelas com as seguintes especificações:

Figura 21 – Estrutura do servidor (tabelas base de dados)

49

• Configurações: tabela responsável pelo registro das aplicações presentes na

rede. Apresenta dados como: porta, IP e nome da aplicação, como mostrado na

figura 22.

Figura 22 – Tabela de Configurações do servidor

• Caixa de Saída: tabela que contém informações das mensagens que por algum

motivo não foram encaminhadas aos seus destinatários com sucesso. A figura

23 mostra esta tabela, que é composta pelos campos: IP da aplicação destino,

IP da aplicação origem, porta da aplicação, mensagem, ID da Mensagem, data

da mensagem.

Figura 23 – Tabela de Caixa de Saída

• Erros: tabela responsável pelo armazenamento dos erros ocorridos durante a

transmissão de mensagens. Campos: Tipo erro (contém a mensagem de erro

retornada), data. A figura 24 mostra a Tabela de Erros, contendo uma

mensagem que excedeu o tempo de tentativas de envio.

Figura 24 – Tabela de Erros

Vale ressaltar que neste modelo, todas as trocas de mensagem deverão estar no

formato do padrão de comunicação HL7.

5.2.2 Modelo Genérico

Após a implementação do Modelo Especializado, verificou-se a possibilidade de

integrar aplicações sem a necessidade de estas implementarem o padrão HL7, o que acabou

50

levando a geração de um novo modelo que possibilitasse a comunicação entre variadas

aplicações sem muita alteração em sua estrutura, sendo apenas necessário que estas sejam

capazes de enviar streams ou arquivos XML seguindo uma estrutura mais simples que a

proposta pelo HL7.

O Modelo Genérico apresenta comportamento semelhante de um middleware, uma

vez que este modelo nada mais é que uma camada de software que possui como finalidade

disponibilizar serviços que facilitem o trabalho do desenvolvedor.

Através da figura 25 é possível compreender a estrutura deste modelo:

Figura 25 – Arquitetura do Modelo Genérico

As aplicações GE, CP e PEP tratam respectivamente de aplicações referentes à

gerência de exames laboratoriais, cadastro de pacientes e prontuário eletrônico de paciente.

Vale lembrar que tais aplicações foram desenvolvidas apenas ao nível de teste possibilitando a

análise da execução do modelo construído. A seguir, segue as especificações das aplicações

desenvolvidas a fim de que seja possível a compreensão do sistema como um todo:

• GE (Gerência de Exames): aplicação responsável pelo cadastro e consulta de

exames. Quando um novo registro de exame é armazenado na base de dados

desta aplicação, deverá ser verificado se o paciente responsável pelo novo

exame encontra-se registrado na base de dados da aplicação referente a

cadastro de pacientes (aplicação CP). Caso esteja, os dados do novo exame

deverão ser enviados para o aplicação Prontuário Eletrônico do Paciente (PEP);

• CP (Cadastro de Pacientes): aplicação responsável pela admissão de novos

pacientes no sistema. Sempre que houver um novo cadastro de paciente, esta

51

aplicação encaminhará os dados demográficos do novo paciente para as

aplicações cujos dados de paciente são relevantes. No nosso exemplo, os

aplicações interessados são as aplicações GE e PEP;

• PEP (Prontuário Eletrônico de Paciente): aplicação responsável pelo histórico e

evolução do paciente. A base de dados desta aplicação é alimentada pelas

aplicações GE e CP.

Para garantir a afirmação de que o modelo desenvolvido apresenta independência de

linguagem, ou seja, é possível permitir a comunicação entre as aplicações independentes da

linguagem em que foram desenvolvidas, as aplicações PEP e CP foram implementadas em

Delphi enquanto que o GE foi implementado em C++.

A estrutura do servidor é a mesma apresentada pelo Modelo Especializado, formado

portanto, pelas tabelas Configurações, Caixa de Saída e Erros.

A troca de mensagens entre as aplicações e o sistema cliente deverá estar especificada

em um formato pré-estabelecido, em uma estrutura simples, diferente do HL7. Já a troca de

mensagens entre os sistemas cliente e servidor devem ser geradas seguindo a estrutura

proposta pelo padrão de comunicação HL7.

5.3 FUNCIONALIDADES

5.3.1 Modelo Especializado

Para uma maior compreensão das funcionalidades deste modelo, suponha que a

Aplicação A, responsável pelo cadastro de pacientes, deseja informar às demais aplicações

sobre uma nova admissão. Para isso a Aplicação A deverá construir uma mensagem de

admissão no formato HL7, contendo os dados demográficos do paciente e encaminhar a

mensagem ao servidor. O servidor ao receber uma nova mensagem verifica o tipo desta (ADT

ou ACK), sendo que caso seja uma mensagem do tipo ADT (admissão de paciente), a

mensagem recebida deverá então ser encaminhada a todos as aplicações registrados na tabela

de Configurações, porém caso tipo de mensagem seja ACK (confirmação), servidor

encaminha mensagem apenas ao destinatário registrado na mensagem.

52

Se destinatário não estiver registrado na tabela de Configurações do servidor, o

servidor encaminha a mensagem de erro ao remetente da mensagem e armazena os dados em

sua tabela de Erros.

Caso, por algum motivo, não seja possível enviar mensagem ao seu destinatário, o

servidor armazena a mensagem na tabela referente a Caixa de Saída para posteriormente

tentar reenviar a mensagem.

A aplicação destino ao receber uma nova mensagem, também deverá verificar o tipo

de mensagem, uma vez que caso a mensagem seja de admissão, a aplicação deverá armazenar

as informações do novo paciente em sua base de dados e enviar uma mensagem de

confirmação ao remetente através do servidor.

Para que todos os procedimentos descritos a cima ocorram com sucesso, algumas

observações deverão ser levadas em consideração:

• As mensagens devem ser construídas corretamente em função da gramática

desenvolvida;

• As mensagens recebidas devem ser analisadas se foram construídas

corretamente;

• O envio de mensagens deverá ocorrer via socket através de uma conexão

TCP/IP;

• Todas as aplicações do sistema devem estar registradas na tabela de

Configurações do Servidor e apresentarem dados consistentes;

• De tempos em tempos servidor verifica se há mensagens em sua caixa de saída,

caso tenha, deverá ser verificado se a mensagem não se encontra expirada

(armazenada, por exemplo, na caixa de saída a mais de 24 horas) e em caso

afirmativo, a mensagem expirada deverá ser incluída na tabela de Erros do

servidor e excluída da tabela caixa de saída.

5.3.2 Modelo Genérico

Para proporcionar a compreensão das funcionalidades presentes neste modelo, será

demonstrado o processo de inclusão de paciente e de exames.

53

5.3.2.1 Inclusão de Pacientes

O processo de admissão de pacientes inicia a partir do aplicação Cadastro de Paciente,

sendo também de interesse às aplicações Gerência de Exames e Prontuário Eletrônico de

Paciente. Sabendo que o formato das mensagens trocadas entre as aplicações e seus

respectivos clientes difere do formato das mensagens trocadas entre os sistemas Cliente e

Servidor, foi preciso adotar uma estrutura de mensagem muito mais simples que o HL7, o que

acaba garantindo desta forma a independência do sistema com relação às aplicações.

Caso a aplicação CP deseje enviar mensagem de admissão para as aplicações GE e

PEP, ela deverá enviar as informações demográficas do novo paciente, bem como o nome da

aplicação destino e o tipo de mensagem. A informação referente à aplicação destino é válida

apenas nos casos em que o tipo de mensagem a ser enviada é uma confirmação, solicitação

de busca ou resultado de busca, nos casos em que o tipo de mensagem é referente a uma

admissão, tal informação deverá ser preenchida apenas de forma representativa, uma vez que

este tipo de mensagem é encaminhada pelo servidor para todas as aplicações registradas em

sua base de dados.

As informações enviadas pela aplicação ao seu respectivo cliente deverão estar

separadas por um símbolo pré-definido, em nosso exemplo utilizamos o símbolo “|” como

separador.

A partir do momento que o cliente receber a mensagem da aplicação, esta deverá ser

reconstruída seguindo as normas de especificação do padrão HL7. Na figura 26, pode-se

verificar uma mensagem referente a admissão de paciente enviada pela aplicação para seu

cliente.

Figura 26 – Mensagens Trocadas Entre Aplicação e Cliente

A figura 27 representa uma mensagem de admissão de paciente que foi construída com

os dados recebidos pela aplicação e será enviada para o servidor conforme o padrão HL7.

54

Figura 27 – Mensagens Trocadas Entre Cliente x Servidor

Os passos seguintes são semelhantes aos passos descritos no modelo anterior, porém

quando da chegada da mensagem ao servidor, este adiciona na mensagem a ser encaminhada

a informação referente à porta da aplicação destino. Com esta informação o sistema cliente da

aplicação destino saberá a qual aplicação a mensagem deverá ser encaminhada, lembrando

ainda que o formato da mensagem encaminhada para a aplicação terá uma estrutura diferente

da estrutura proposta pelo HL7.

5.3.2.1 Inclusão de Exames

O processo de envio de mensagens e as suas estruturas são as mesmas especificadas no

processo de inclusão de paciente. O que difere uma ação da outra é que o processo de inclusão

de exames também envolve mensagens do tipo busca e resultado de busca.

Quando ocorre uma inclusão de exames pela aplicação GE, a mesma verifica se o

paciente responsável pelo exame já se encontra registrado na aplicação Cadastro Paciente

através da flag tem_cadastro_paciente na tabela Paciente de GE. Caso a flag esteja setada com

“S”, o sistema encaminha uma mensagem de atualização dos dados do paciente, informando o

novo exame à aplicação Prontuário Eletrônico do Paciente. Caso a flag esteja setada com “N”,

a aplicação GE encaminha uma mensagem de busca à aplicação CP e armazena os dados da

busca em sua tabela Busca, para caso hajam mais exames cadastrados para o mesmo paciente,

o sistema não tenha que encaminhar nova mensagem de busca por paciente, uma vez que esta

já foi recebida pela aplicação GE para o mesmo paciente.

Cadastro Paciente ao receber uma mensagem de busca, retorna ao remetente a

mensagem contendo o resultado da busca solicitada, nesta mesma mensagem também deverá

conter o status do resultado da busca, que deverá ser identificada pela string “NF” caso não

haja nenhum registro referente a busca ou “OK”, caso haja registro para a busca solicitada.

55

GE ao receber mensagem contendo resultado da busca de um determinado paciente

verifica o status da busca e caso este contenha o valor “OK”, a aplicação GE exclui a busca de

sua tabela Busca, seta a flag tem_cadastro_paciente da tabela paciente para “S” e encaminha

ao PEP uma mensagem referente à atualização do paciente contendo o novo exame realizado.

A figura 28 mostra uma mensagem no formato HL7 para a solicitação de dados do

paciente cujo ID é 1113.

Figura 28 – Mensagem de solicitação de dados de paciente

A figura 29 representa a mensagem HL7 que retorna os dados referentes a uma

solicitação de busca, neste caso, a mensagem será enviada ao solicitante (GerenciaExames) os

dados cadastrais do paciente que lhe foi solicitado (1113).

Figura 29 – Mensagem de resposta à solicitação de dados de paciente

5.4 MODELO ESPECIALIZADO X MODELO GENÉRICO

A vantagem do Modelo Genérico com relação ao Modelo Especializado é a

possibilidade de integração de sistemas sem que as aplicações sofram grandes alterações em

sua estrutura. Recomenda-se a implementação o protocolo HL7 junto às aplicações, ou seja,

toda a aplicação deve implementar o padrão HL7, porém quando já se faz uso de aplicações e

deseja-se a comunicação entre as mesmas? Sabe-se que para este caso, dependendo da

aplicação, a implementação do padrão HL7 poderia vir a ser inviável e sem falar do alto

investimento necessário para sua implantação. Assim através do Modelo Genérico as

56

aplicações não necessitam implementar o padrão de comunicação HL7, sendo assim apenas

necessário que estas apresentem estruturas que suportem sockets com conexão TCP/IP.

Já a desvantagem do Modelo Genérico está em seu desempenho que poderá sofrer uma

queda quando comparado ao Modelo Especializado, visto que agora o Modelo Genérico

deverá primeiramente repassar as informações necessárias para o cliente para então a

mensagem no formato do padrão HL7 ser gerada.

57

6 CONCLUSÃO Compreendida a necessidade da informatização na área de saúde, onde disponibilizar

informações de pacientes de forma eletrônica, facilita seu gerenciamento, permite melhor

atendimento médico, maior qualidade de serviços e, ainda possibilita redução de custos.

Porém, para estas informações possam ser acessadas, verificou-se que é imprescindível o uso

de padrões de comunicação como o HL7, que permite uma integração entre sistemas de forma

flexível e transparente.

A construção da arquitetura cliente-servidor no primeiro modelo mostrou-se muito

mais complicada do que se esperava, pois como partimos do princípio de utilizar um ambiente

de desenvolvimento gratuito, e que contemplasse multiplataforma, a tecnologia não permitia

flexibilidade quanto ao uso de sockets e threads, como é comum em outras linguagens.

Outra dificuldade observada, foi devido à especificação um tanto complexa da

gramática, ocasionando maior tempo de implementação e teste para o uso correto da estrutura

proposta pelo HL7. Provavelmente este problema será evitado quando usada a versão 3 do

padrão HL7.

Como a tarefa de implementação do padrão HL7 se mostrou demasiadamente

exaustiva, sentimos a necessidade do desenvolvimento de um middleware para facilitar o

trabalho do desenvolvedor. Dessa forma, o desenvolvedor poderia integrar seus sistemas, sem

tomar conhecimento da complexidade que envolve a implementação das especificações do

padrão HL7.

Ao final deste projeto, construimos modelos de sistemas que podem ser empregados

para a solução de problemas distintos: o Modelo Especializado repassa ao desenvolvedor, a

estrutura necessária para o desenvolvimento de novas aplicações capacitadas a efetuar troca

de informações com o uso do padrão HL7; enquanto que o Modelo Genérico, através de um

middleware HL7, atende a necessidade de se obter integração com aplicações já existentes.

Depois de superados todos os obstáculos, verificamos que o esforço necessário para o

desenvolvimento destes modelos foi compensador. Os benefícios oferecidos pelo padrão HL7

foram alcançados, promovendo desta forma a distribuição das informações ditas essenciais

em um ambiente de saúde.

58

7 TRABALHOS FUTUROS

• A estrutura das mensagens trocadas entre aplicações e clientes poderia ser implementada

utilizando o padrão XML.A utilização do XML permitiria maior facilidade de integração

do padrão HL7 quando utilizada sua nova versão( HL7 versão 3).

• Criação de uma API evitaria que o desenvolvedor da aplicação distribuída tivesse que

implementar uma grande parte dos serviços não-funcionais de que necessita. Utilizando

uma API, tudo que o desenvolvedor teria que fazer seria escolher que serviços ele iria

utilizar.

• Uso do middleware desenvolvido em aplicações reais.

59

REFERÊNCIAS ARAÚJO, et al. Automatas, Introdução. Disponível em: <http://www.ele.ita.br/~nogueira/ introducao.htm>. Acesso em: 20 set. 2005. ARNAUT, Dagoberto Haele. Entendendo C++. Disponível em: <http://www.arnaut.eti.br/op /CPPAI01.htm>. Acesso em: 20 set. 2005.

BRASIL, Comitê Executivo de Governo Eletrônico. e PING - Padrões de Interoperabilidade de Governo Eletrônico. Documento de Referência. Versão 1.0. Julho de 2005. Disponível em: <http://www.governoeletronico.gov.br/governoeletronico/publicacao/ down_anexo.wsp?tmp.arquivo=E15_241e-PING%20v1.0%2013%2007%202005.pdf>. Acesso em: 14 jul. 2005. COSTA, Cláudio Giulliano Alves da. Desenvolvimento e Avaliação Tecnológica de um Sistema de Prontuário Eletrônico do Paciente, Baseado nos Paradigmas da World Wide Web e da Engenharia de Software. Campinas, 2001. Disponível em: <http://www.medsolution.com.br/claudio/dissertacao/Dissertacao_Claudio_Giulliano_PEP.pdf> . Acesso em: 07 jun. 2005.

COSTA, Marcos André da Silva. Um Modelo de Middleware Adaptativo. Recife,2004. Disponível em: <http://www.cin.ufpe.br/~nsr/DIS_MASC.doc>.Acesso em: 02 out. 2005.

FERNANDES, Rodrigo A. B., et al. O que é Health Level 7 (HL7)?. São Paulo,1999. Disponível em: <http://www.virtual.epm.br/material/tis/curr-med/temas/med5/med5t21999/estrutura/ hl7.htm>. Acesso em: 18 dez. 2004. FRICK, Oscar Osvaldo; LORO, Letícia. O Setor de Software para Saúde no Brasil. Economia e Tecnologia. Maio/Julho 2004. Disponível em:<http://www.iees.org.br/Download /revista.PDF>. Acesso em: 15 maio 2005. GESSER, Carlos Eduardo. GALS Gerador de Analisadores Léxicos e Sintáticos. 2002. Disponível em: <http://gals.sourceforge.net/help.html#Intro>. Acesso em: 25 set. 2005. GUEDES, Luiz Affonso. Objetos Distribuídos - Programação Distribuída Orientado a Objetos. Rio Grande do Norte, 2004. Disponível em: <http://www.dca.ufrn.br/~affonso/ DCA2401/2004_1/aulas/objetos_distribuidos.pdf>.Acesso em: 04 out. 2005. GUEDES, Ulisses T.V. Redes e Comunicação de Dados – Redes Programação TCP/ IP. Rio de Janeiro, 2001. Disponível em: <http://www.aedb.br/faculdades/eng/ /disciplinas/ano5/downloads/redes_3_1.pdf>. Acesso: 30 set. 2005. GUIMARÃES, Vinicius. LISA - Uma ferramenta para geração automática de linguagem. Disponível em: < http://atlas.ucpel.tche.br/~barbosa/consico/consico2/artigos/a3.pdf > Acesso em: 30 set. 2005.

60

GULIATO, Denise; CARNIELLI, Walter; ZUFFO, João Antônio. Integração de Crescimento de Região e Detecção de Arestas através de Operadores de Agregação. Disponível em http://mirror.impa.br/sibgrapi97/anais/pdf/art11.pdf . Acesso em: 02 out. 2005. HENRIQUES, Jorge; CARVALHO, Paulo de. HL7 Health Level Seven. 2005. Disponível em: <https://www.dei.uc.pt/weboncampus/course/LEI/2004-2005/hl7V23 Aulas.pdf>. Acesso em: 11 ago. 2005. HL7. HL7 Receives ANSI Approval of Three Version 3 Specifications Including CDA, Release 2 . Disponível em:<http://www.hl7.org/Press/20050505.pdf>. Acesso em:29 maio 2005. MACÊDO, Raimundo, et al. Tratando a Previsibilidade em Sistemas de Tempo-Real Distribuídos: Especificação, Linguagens, Middleware e Mecanismos Básicos. Disponível em:< http://www.lasid.ufba.br/public/artigos/tempoReal2004.pdf>. Acesso em: 01 out. 2005. MACIEL, Fabiano. O que é C++. Iniciando em C++. Fevereiro de 2004. Disponível em: <http://www.dotnetraptors.com.br/start/artigos/artigos_cpp/1294.aspx>. Acesso em: 20 set. 2005. MARCH, Alan. HL7, o Modelo. 2002. Disponível em: <http://www.salutia.com/pdf/Boletin _Salutia_maio_junho_2002.pdf >. Acesso em: 15 jun. 2005. MAZZUCO Jr, José. Uma Abordagem Híbrida do Problema da Programação da Produção através dos Algoritmos Simulated Annealing e Genético. Florianópolis, 1999. Disponível em: <http://www.eps.ufsc.br/teses99/mazzucco/cap4.html>. Acesso em: 30 set. 2005. MELLO Fabrízio de Royes; LACERDA, Guilherme Silva de. Aspectos Formais Sobre Linguagens de Programação. Março de 2001. Disponível em: <http://www.urcamp.tche.br/ ccei/revista7.pdf>. Acesso em: 20 out. 2005. MONGELLI, Henrique. Programação Distribuída. 2003. Disponível em: <http://www. dct.ufms.br/~mongelli/disciplinas/graduacao/progdistr2003/aula1.pdf>.Acesso em: 28 set. 2005. RODRIGUES, Denise, et al. Avanço da Informática Médica. São Paulo, 2000. Disponível em: <http://www.virtual.epm.br/material/tis/curr-med/temas/med5/med5t32000/grupo5/ avanco.htm>. Acesso em: 22 abr. 2005. SALUTIA. Salutia Tecnologia e Saúde. São Paulo, 2005. Disponível em: <http://www.salutia.com/home/home.php?idioma=br&id0=financiadores&id1=clientes> Acesso em: 12 dez. 2005.

SAÚDE TOTAL. Informática Médica uma nova disciplina. Disponível em: <http://www.saudetotal.com/infosb/infmed.htm>. Acesso em: 12 dez. 2005.

61

SILVA, Murilo F. , et al. Tipos de Sistemas de Informação em Saúde no Ambiente Hospitalar. São Paulo, 1999. Disponível em: <http://www.virtual.epm.br/material/tis/curr-med/temas/med5/med5t41999/sis/sub5.htm.> Acesso em: 30 abr. 2005. SIQUEIRA, Frank Augusto. Sistemas Distribuídos. Disponível em : <http://www.inf.ufsc.br/ ~frank/unileste/Sistemas%20Distribuidos%20-%20Parte%20II.pdf >. Acesso em: 30 set. 2005. VASCONCELLOS Neto, José Augusto. Tendências da Informática em Saúde no Brasil. Economia e Tecnologia. Maio/Julho 2004. Disponível em: <http://www.iees.org.br/ Download/revista.PDF>. Acesso em: 15 jun. 2005. WIKIPEDIA. Cliente-servidor. Disponível em: <http://pt.wikipedia.org/wiki/Cliente-servidor> Acesso em: 01 out. 2005.

62

ANEXO 1 – ANÁLISE DE REQUISITOS Caso de Uso Estendido - Modelo Especializado Caso de Uso: Envio de mensagens Ator: usuário da aplicação, aplicação. Finalidade: envio de mensagens para as aplicações interessadas. Tipo: primário e essencial. <pré-condição> mensagem deve estar semanticamente correta. <pós-condição> mensagem é enviada ao servidor. Visão Geral: usuário ou aplicação envia mensagem no formato HL7 ao servidor para ser encaminhado posteriormente ao seu(s) destinatário(s).

Seqüência Típica de Eventos Ação do Ator Resposta do Sistema 1) Este caso de uso inicia a partir do momento em que o usuário informa à aplicação uma admissão de paciente ou ainda quando o sistema deseja enviar uma confirmação ao remetente referente a mensagem recebida.

2) Sistema busca endereço IP do servidor. 3) Solicita conexão com o servidor. 4) Sistema envia mensagem (HL7) ao

servidor 5) Fecha conexão com o servidor Seqüência Alternativa *3.a. Caso não seja possível estabelecer conexão com o servidor, sistema alerta ao usuário a indisponibilidade do mesmo. Caso de Uso: Receber mensagem Ator: Sistema Servidor, Sistema Cliente. Finalidade: receber mensagens. Tipo: primário e essencial. <pré-condição> mensagem enviada deve estar semanticamente correta. Visão Geral: sistema aguarda por novas solicitações de conexão para recebimento de mensagem.

63

Seqüência Típica de Eventos Ação do Ator Resposta do Sistema 1) Este caso de uso começa quando servidor ou aplicação cliente solicita conexão para o envio de mensagem.

2) Aceita nova conexão 3) Recebe mensagem no formato HL7 4) Faz verificação semântica da mensagem

recebida. 5) Armazena dados recebidos em sua base

de dados. 6) Encaminhar mensagem recebida ao

destinatário. Seqüência Alternativa *4.a. Se a mensagem estiver semanticamente incorreta, sistema encerra execução. *4.b Caso o ator seja o servidor, o passo 5 deverá ser ignorado e seguir seqüência de execução a partir do passo 6. *4.c Caso o ator seja o aplicação cliente, a execução deverá ser encerrada no passo 5.

*4.c.a Se tipo da mensagem recebida for de admissão de paciente, a aplicação encaminha ao servidor uma mensagem de confirmação.

*4.c.b Se tipo de mensagem recebida for de confirmação, o passo 5 não será executado. Caso de Uso: Encaminhar mensagem ao destinatário Ator: Servidor Finalidade: encaminhar mensagens recebidas aos seus respectivos destinatários. Tipo: primário e essencial. <pré-condição> destino deverá estar registrado na base. <pós-condição> mensagem enviada ao destino. Visão Geral: servidor analisa mensagem e localiza destino em sua base para então encaminhar mensagem ao destino.

Seqüência Típica de Eventos Ação do Ator Resposta do Sistema 1) Este caso de uso inicia a partir do momento em que uma nova mensagem é recebida pelo servidor.

2) Verifica a existência do destino 3) Estabelece conexão com destinatário 4) Envia mensagem HL7 para destino 5) Fecha conexão com o cliente Seqüência Alternativa *2.a. Caso destino da mensagem não esteja registrado no servidor, envia mensagem de erro para remetente.

64

*3.a. Caso não seja possível estabelecer conexão com o cliente destino, mensagem deverá ser armazenada em sua caixa de saída. Caso de Uso: Verifica Caixa de Saída Ator: Sistema Servidor Finalidade: enviar mensagem que se encontra na caixa de saída e excluir da caixa de saída as mensagens expiradas. Tipo: primário <pré-condição> dados recuperados corretamente da base de dados. <pós-condição> mensagens encaminhadas deverão ser retiradas da caixa de saída. Visão Geral: de tempo em tempo servidor tenta enviar mensagens que se encontram na caixa de saída e verificar se não há mensagens expiradas.

Seqüência Típica de Eventos Ação do Ator Resposta do Sistema 1) Este caso de uso começa quando servidor verifica que há mensagens armazenadas em sua caixa de saída.

2) Verifica se mensagem HL7 da caixa de saída não se encontra expirada.

3) Estabelece conexão com o destino. 4) Mensagem da caixa de saída é enviada 5) Encerra conexão com o destino 6) Exclui mensagem da caixa de saída. Seqüência Alternativa *2.a. Caso destino da mensagem não seja mais válido, servidor retorna mensagem de aviso para o emissor da mensagem e executa o passo 6. *2.b. Se a mensagem estiver expirada (estiver 4 horas ou mais presente na caixa de saída), a mensagem será armazenada na base de dados como mensagem de erro e executa-se o passo 6. *3.a.Caso não seja possível estabelecer conexão com o destinatário, os passos seguintes não serão executados. Casos de Uso Estendido - Modelo Genérico Casos de Uso: Envio de mensagens do Cliente Ator: aplicação cliente. Finalidade: envio de mensagens para as aplicações interessadas. Tipo: primário . <pré-condição> mensagem deve estar semanticamente correta. <pós-condição> mensagem é enviada. Visão Geral: usuário ou aplicação envia mensagem no formato HL7 ao servidor para ser encaminhado posteriormente ao seu(s) destinatário(s).

65

Seqüência Típica de Eventos Ação do Ator Resposta do Sistema 1) Este caso de uso inicia a partir do momento em que a aplicação cliente envia mensagem no formato pré-estabelecido para o cliente.

2) Sistema busca endereço IP do servidor. 3) Solicita conexão com o servidor. 4) Sistema envia mensagem (HL7) ao

servidor 5) Fecha conexão com o servidor Seqüência Alternativa *3.a. Caso não seja possível estabelecer conexão com o servidor, sistema alerta ao usuário a indisponibilidade do mesmo. Caso de Uso: Receber mensagem Ator: Servidor, Cliente. Finalidade: receber mensagens. Tipo: primário e essencial. <pré-condição> mensagem enviada deve estar semanticamente correta. Visão Geral: sistema aguarda por novas solicitações de conexão para recebimento de mensagem.

Seqüência Típica de Eventos Ação do Ator Resposta do Sistema 1) Este caso de uso começa quando servidor ou aplicação cliente solicita conexão para o envio de mensagem.

2) Aceita nova conexão 3) Recebe mensagem 4) Faz verificação semântica da mensagem

recebida. 5) Encaminhar mensagem recebida ao

destinatário. Seqüência Alternativa *4.a. Se a mensagem estiver semanticamente incorreta, sistema encerra execução. Caso de Uso: Encaminhar mensagem do Cliente Ator: Servidor Finalidade: encaminhar mensagens recebidas aos seus respectivos destinatários. Tipo: primário e essencial. <pré-condição> destino deverá estar registrado na base de dados. <pós-condição> mensagem enviada ao destino.

66

Visão Geral: servidor analisa mensagem e localiza destino em sua base para então encaminhar mensagem ao destino.

Seqüência Típica de Eventos Ação do Ator Resposta do Sistema 1) Este caso de uso inicia a partir do momento em que uma nova mensagem é recebida pelo servidor.

2) Verifica a existência do destino 3) Adiciona na mensagem HL7 a porta

referente à aplicação destino. 4) Estabelece conexão com destinatário 5) Envia mensagem para destino 6) Fecha conexão com o cliente Seqüência Alternativa *2.a. Caso destino da mensagem não esteja registrado no servidor, envia mensagem de erro para remetente. *4.a. Caso não seja possível estabelecer conexão com o cliente destino, mensagem deverá ser armazenada em sua caixa de saída Caso de Uso: Encaminhar mensagem do Servidor Ator: Cliente Finalidade: encaminhar mensagens recebidas do servidor as suas respectivas aplicações (destinatários). Tipo: primário e essencial. <pós-condição> mensagem enviada ao destino. Visão Geral: servidor analisa mensagem e verifica em qual porta a aplicação destino deverá estar aguardando para então encaminhar a mensagem à aplicação em um formato pré-estabelecido diferente de HL7.

Seqüência Típica de Eventos

Ação do Ator Resposta do Sistema 1) Este caso de uso inicia a partir do momento em que uma nova mensagem é recebida pelo cliente.

2) Verifica na mensagem a porta em que a mensagem deverá ser encaminhada

3) extrai da mensagem as informações úteis para a aplicação destino.

4) Gerar mensagem em um formato diferente do padrão HL7

5) Estabelece conexão com a aplicação destinatário

6) Envia mensagem para aplicação 7) Encerra conexão com a aplicação

67

Seqüência Alternativa *5.a Dependendo do tipo de mensagem será necessário o envio de mensagem ao remetente da mensagem confirmando o recebimento. Caso de Uso: Receber mensagem Ator: Cliente Finalidade: receber mensagens vindas do Cliente. Tipo: primário e essencial. <pré-condição> mensagem enviada deve ter sido construída corretamente de acordo com o formato pré-estabelecido. Visão Geral: aplicação aguarda por novas solicitações de conexão para recebimento de mensagem.

Seqüência Típica de Eventos Ação do Ator Resposta do Sistema 1) Este caso de uso começa quando cliente solicita conexão para o envio de mensagem.

2) Aceita nova conexão 3) Recebe mensagem 4)Verifica tipo da mensagem 5) Armazena dados recebidos em sua base

de dados. Seqüência Alternativa *4.a Se tipo de mensagem recebida for diferente de inserção, o passo 5 não será executado *4.a.b Caso tipo de mensagem seja de busca, aplicação deverá encaminhar ao cliente uma mensagem contendo resultado da busca. .Caso de Uso: Verificar Caixa de Saída Ator: Sistema Servidor Finalidade: enviar mensagem que se encontra na caixa de saída e excluir da caixa de saída as mensagens expiradas. Tipo: primário <pré-condição> dados recuperados corretamente da base de dados. <pós-condição> mensagens encaminhadas deverão ser retiradas da caixa de saída. Visão Geral: de tempo em tempo servidor tenta enviar mensagens que se encontram na caixa de saída e verificar se não há mensagens expiradas.

68

Seqüência Típica de Eventos Ação do Ator Resposta do Sistema 1) Este caso de uso começa quando servidor verifica que há mensagens armazenadas em sua caixa de saída.

2) Verifica se mensagem da caixa de saída não se encontra expirada.

3) Estabelece conexão com o destino. 4) Mensagem da caixa de saída é enviada 5) Encerra conexão com o destino 6) Exclui mensagem da caixa de saída. Seqüência Alternativa *2.a. Caso destino da mensagem não seja mais válido, servidor retorna mensagem de aviso para o emissor da mensagem e executa o passo 6. *2.b. Se a mensagem estiver expirada (estiver 4 horas ou mais presente na caixa de saída), a mensagem será armazenada na base de dados como mensagem de erro e executa-se o passo 6. *3.a.Caso não seja possível estabelecer conexão com o destinatário, os passos seguintes não serão executados. Requisitos Apresentamos os requisitos básicos dos modelos que foram elaborados inicialmente. Requisitos Funcionais

R1 – Os modelos deverão ser capazes de encaminhar as mensagens somente às aplicações interessadas.

R2 – Os modelos deverão permitir o envio de mensagens. R3 – Os modelos deverão permitir a recepção de mensagens. R4 – Deverão ser capazes de construir mensagens semanticamente corretas.

R5 – Deverá ser possível o reenvio de mensagens que não foram encaminhadas aos destinos com sucesso.

R6 – Deve ser informado ao sistema emissor a recepção de mensagens efetuadas com sucesso através de mensagens de confirmação. R7 – Permitir que Cliente dê suporte a todas as aplicações registradas em uma máquina.

69

Requisitos Não Funcionais RN1 – Tempo de resposta: é necessário que o sistema tenha um tempo de resposta minimizado para que haja consistência dos dados. RN2 – Independência do Sistema Operacional: os modelos deverão ser independentes do sistema operacional, sendo executados tanto em ambiente Linux como em ambiente Windows. RN3 – Independência da Linguagem: os modelos devem estabelecer comunicação entre as aplicações, independente da linguagem. Requisitos para Utilização do Sistema A utilização do middleware HL7, exige o cumprimento de determinadas regras e instalação e/ou configuração certas ferramentas. Requisitos de Software para Usuário Final Para o correto funcionamento do sistema, é necessário que esteja disponível a DLL denominada PThreadGC tanto no cliente HL7 como no servidor HL7. Para a utilização do servidor é necessário o uso do banco de dados PostgreSQL e criação das respectivas tabelas. Cliente HL7 pThreadGC.dll Servidor HL7 pThreadGC.dll PostgreSQL Base de dados: HL7 Tabela: caixasaida Campos: "ipDestino" varchar(20) NOT NULL, "ipOrigem" varchar(20) NOT NULL, porta int2 NOT NULL, mensagem text, "idMsg" varchar(25) NOT NULL, "dataHora" timestamp Chave primária: ("ipDestino", porta, "idMsg") Tabela: configuracoes Campos :

ip varchar(20) NOT NULL, porta varchar(20) NOT NULL, aplicacao varchar(30) NOT NULL Chave primária: (ip, porta, aplicacao) Tabela: erros Campos: "tipoErro" text,

data varchar(30)

70

O arquivo ConfigServidorHL7.txt é utilizado pelo servidor HL7 para armazenar as configurações da base de dados HL7, assim, deverá ser informado o IP do servidor, porta, nome banco, usuário e senha, onde os campos deverão estar separados por “#” como no exemplo a seguir:

localhost#5432#HL7#postgres#12345 Todos os clientes HL7 deverão preencher no arquivo ConfigServidor.txt, o endereço IP do servidor HL7. Requisitos de Desenvolvimento Para que o middleware possa ser utilizado, os seguintes requisitos devem ser cumpridos: Servidor HL7

• Disponibilizar a porta 27015 • IP fixo • Sincronização do relógio do sistema • Cadastro das aplicações (tabela configuracoes)

Cliente HL7

• Nome Aplicação • IP fixo • Conhecer IP do servidor (arquivo de configuração) • Sincronização do relógio do sistema • Disponibilizar a porta 27014

Aplicação

• Utilização de Sockets • Possibilidade uso de threads • Extrair token

A seguir é mostrada a estrutura das mensagens recebidas e/ou enviadas. Note que, os campos são separados por “|” e quando se tratar de um recebimento de mensagem, após o caractere “¨” estará a mensagem HL7 que foi enviada.

Cadastro de Paciente (Interação cliente-aplicação) 1. Enviar Mensagens

o Mensagem de Admissão: � Nome da Aplicação= “CadastroPaciente” + ”|” � Tipo da mensagem= “CadastroPaciente-Inclusao” + “|” � Informar dados demográficos do paciente(ver campos do PID) + “|”

o Mensagem de Resposta Busca: � Nome da Aplicação = “CadastroPaciente” + ”|” � Tipo da mensagem= CadastroPaciente-Resposta + ”|” � Aplicação Origem Localizar paciente através de ID:

71

• SE encontrado = “OK” + ”|” o Retornar os dados demográficos do paciente(PID) + ”|”

• SENÃO encontrado = “NF” + ”|”

o Retornar (PID) + ”|”

2. Receber Mensagens o ACK (mensagem de confirmação)

� Idmensagem +”|” � Tipo mensagem = RQP +”|” � Aplicação Origem + “|” � DataHoraMensagem + “|” � Mensagem: “¨”

o RQP (mensagem de busca) � Idmensagem + ”|” � Tipo mensagem = RQP + ”|” � Aplicação Origem + ”|” � DataHoraMensagem + “|” � ID paciente + ”|” � Tabela= DEM + ”|” � Mensagem: “¨”

Gerência Exames (Interação cliente-aplicação)

1. Enviar Mensagens o Nome da Aplicação = “GerenciaExames” + “|” o Informar Tipo da mensagem= “GerenciaExames-ResultadoExames”+”|”

� Informar ID do paciente +”|” � Tabela = “RES” + “|” � Total de resultados +”|” � Resultado de Exames Efetuados +”|”

o Informar Tipo da mensagem= “GerenciaExames-Busca” + “|” � Informar ID do paciente +”|” � Tabela = “DEM” + “|”

2. Receber Mensagens o ACK (mensagem de confirmação)

� Idmensagem +”|” � Tipo mensagem = RQP +”|” � Aplicação Origem + “|” � DataHoraMensagem + “|” � Mensagem: “¨”

o ADT (mensagem de admissão) � ID mensagem + ”|” � Tipo mensagem =ADT + ”|” � Aplicação Origem + ”|” � Data hora mensagem +”|” � PID + ”|” � Mensagem: “¨”

72

o QRI (mensagem de resposta busca)

� ID mensagem + ”|” � Tipo mensagem =QRI +”|” � Aplicação Origem + ”|” � Data hora mensagem +”|” � Encontrado = “OK” +”|” ou Encontrado = “NF” +”|” � PID +”|” � Mensagem: “¨”

Prontuário Eletrônico (Interação cliente-aplicação) Receber Mensagens

o ACK (mensagem de confirmação) � Idmensagem +”|” � Tipo mensagem = RQP +”|” � Aplicação Origem + “|” � DataHoraMensagem + “|” � Mensagem: “¨”

o ADT (mensagem de admissão) � ID mensagem + ”|” � Tipo mensagem =ADT + ”|” � Aplicação Origem +”|” � Data hora mensagem + ”|” � PID + ”|” � Mensagem: “¨”

o PIN (mensagem de atualização prontuário) � ID mensagem +”|” � Tipo mensagem =QRI + ”|” � Aplicação Origem + ”|” � Data hora mensagem + ”|” � idPaciente + “|” � Tabela + “|” � QuantExames +”|” � Exames + ”|” � Mensagem: “¨”

Campos do PID (Identificação de Paciente) Set_ID – identificador paciente Patient_ID_External - identificador paciente Patient_ID_Internal – identificador paciente (obrigatório) Alternate_Patient_ID – identificador paciente Patient_Name – nome completo Mother_Maiden_Name – nome de solteiro da mãe Date_Time_of_Birth – Data de nascimento (AnoMesDia HoraMinutos)

73

Sex – Sexo (F - feminino, M - masculino, O - outro, T - desconhecido) Patient_Alias - Race - Raça Patient_Address - Endereço Phone_Number_Home – Telefone Residencial Phone_Number_Business – Telefone Comercial Primary_Language - Idioma Marital_Status – Estado civil (A - separado, D-divorciado, M - casado, S- solteiro, W – viúvo) Religion – Religião Patient_Account_Number - Número da conta SSN_Number – Número de seguridade social Driver_License_Number – Carteira de Habilitação Mother_Identifier – Identificador Ethnic_Group – Grupo Étnico Birth_Place – Naturalidade Multiple_Birth_Indicator – Indicador de nascimento múltiplo (Y/N) Birth_Order – Ordem de nascimento múltiplo Citizenship - Cidadania Veterans_Military_Status – Status militar Nationality - Nacionalidade Patient_Death_Date_and_Time – Data e horário Falecimento(AnoMesDia HoraMinutos) Patient_Death_Indicator – Indicador de Falecimento

74

D

iagr

ama

de C

lass

es

75

Telas do Sistema Aplicação Cadastro Paciente

Nas figuras 30 e 31 são mostradas as telas da aplicação Cadastro Paciente.

Figura 30 – Cadastro de Paciente

Figura 31 – Recebimento de mensagem

76

Aplicação Prontuário Eletrônico Nas figuras 32,33 e 34 são mostradas as telas da aplicação prontuário

Figura 32 – Prontuário Eletrônico - Recebimento de Cadastro de Paciente

Figura 33 – Prontuário Eletrônico - Recebimento de resultado de exames

Figura 34 – Prontuário Eletrônico - Mensagem de recebimento de cadastro

77

Aplicação Gerência de Exames Nas figuras 35, 36, 37, 38 são mostradas as telas da aplicação Gerência de Exames.

Figura 35 – Gerência de Exames - Cadastro Exame

Figura 36 – Gerência Exames - Buscar Paciente

78

Figura 37 – Gerência Exames - Resultado Exame

Figura 38 – Gerência Exames - Mensagens Recebidas

79

Servidor HL7 A figura 39 mostra o recebimento de uma mensagem de admissão de paciente, onde o servidor irá encaminhar a mensagem para todos os clientes HL7 que possuem aplicações interessadas neste tipo de mensagem.

Figura 39 – Servidor HL7 - Recebimento de mensagem admissão de paciente

Cliente HL7 A figura 40 mostra o recebimento de uma mensagem no formato HL7 e o envio desta mesma mensagem para o formato que a aplicação conhece.

Figura 40 – Cliente HL7 - Recebimento de mensagem

80

ANEXO 2 – GRAMÁTICA IMPLEMENTADA <MSH> ::= MSH #1<Field_Separator>; <Field_Separator>::= "|"<Encoding_Caracters>; <Encoding_Caracters> ::= "^~\&"#3 "|"<Sending_application>; <Sending_application>::= <componente_Sending_application> "|"<Sending_Facility>; <componente_Sending_application>::= id#4<componente_Sending_application>| "^"#4<componente_Sending_application>|"&"#4<componente_Sending_application>|î; <Sending_Facility> ::= "|"<Receiving_application>|id#5 "|"<Receiving_application>; <Receiving_application> ::= id#6 "|"<Receiving_Facility>|"|"<Receiving_Facility>; <Receiving_Facility> ::= "|"<Date_Time_Message> |id#7 "|"<Date_Time_Message>; <Date_Time_Message> ::= id#8"|"<Security>|"|"<Security>; <Security> ::= "|"#9<Message_Type_Event>|id#9"|"<Message_Type_Event>; <Message_Type_Event>::= id #10 "^" <Message_Type_Segment>; <Message_Type_Segment>::= "|"<Message_Control_ID>| id #1010"|" <Message_Control_ID>; <Message_Control_ID>::= "|"|id#11"|"<Processing_ID>; <Processing_ID>::= id#12"|"<Version_ID>|"|"<Version_ID>; <Version_ID>::= id#13 Fim_Linha#14<pos_MSH>; <pos_MSH>::=<PID>|<EVN>|<MSA>|<QRD>|<EQL>|<OBX>|<ORC>|<AL1>|<QAK>|î; <PID> ::= PID#15"|" <Patient_ID_1>; <Patient_ID_1> ::="|"<Patient_ID_2>| id #16 "|"<Patient_ID_2>; <Patient_ID_2> ::= <componente_Patient_ID_2>"|"<Patient_ID_3>; <componente_Patient_ID_2>::= id#17<componente_Patient_ID_2>|"^"

#17<componente_Patient_ID_2>|"&"#17<componente_Patient_ID_2>|î;

81

<Patient_ID_3>::= <componente_Patient_ID_3>"|"<Alternate_ID_4>; <componente_Patient_ID_3>::= id#18<componente_Patient_ID_3>|"^"#18

<componente_Patient_ID_3>|"&"#18<componente_Patient_ID_3>|î; <Alternate_ID_4>::= "|"<Patient_name>|id #19"|"<Patient_name>; <Patient_name> ::= <componente_Patient_name>"|"<Mother_Maiden_Name>; <componente_Patient_name>::= id#20<componente_Patient_name>|"^"#20

<componente_Patient_name>|"&"#20<componente_Patient_name>|î; <Mother_Maiden_Name> ::="|"<Date_Time_of_Birth>|id #21 "|"<Date_Time_of_Birth>; <Date_Time_of_Birth> ::="|"<Sex>|id #22"|"<Sex>; <Sex> ::= "|"<Patient_Alias>|id#23"|"<Patient_Alias>; <Patient_Alias>::="|"<Race>|id #24"|"<Race>; <Race> ::= "|"<Patient_Address>|id #25 "|" <Patient_Address>; <Patient_Address>::=<componente_Patient_Address>"|"<County_Code>; <componente_Patient_Address>::= id#26<componente_Patient_Address>|"^"#26

<componente_Patient_Address>|"&"#26<componente_Patient_Address>|î; <County_Code>::="|"#27<Phone_Number_Home>; <Phone_Number_Home>::=<componente_Phone_Number_Home>"|"<Phone_Number_Business>; <componente_Phone_Number_Home>::= id#28<componente_Phone_Number_Home>

|"^"#28<componente_Phone_Number_Home>|"&"#28 <componente_Phone_Number_Home>|î;

<Phone_Number_Business>::=<componente_Phone_Number_Business>"|"

<Primary_Language>; <componente_Phone_Number_Business>::= id#29<componente_Phone_Number_Business> |"^"#29<componente_Phone_Number_Business>|"&"#29

<componente_Phone_Number_Business>|î; <Primary_Language>::="|"<Marital_Status>|id #30"|"<Marital_Status>; <Marital_Status>::="|"<Religion>|id#31"|"<Religion>; <Religion>::= "|"<Patient_Account_Number>|id#32"|"<Patient_Account_Number>; <Patient_Account_Number>::=<componente_Patient_Account_Number>

82

<fim_Patient_Account_Number>; <componente_Patient_Account_Number>::= id#33 <componente_Patient_Account_Number>|"^"#33 <componente_Patient_Account_Number>|"&"#33 <componente_Patient_Account_Number>|î;

<fim_Patient_Account_Number>::= "|" <Social_Security_Number>|<fim_PID>; <Social_Security_Number>::= id#34 <fim_Social_Security_Number> |<fim_Social_Security_Number>; <fim_Social_Security_Number>::= "|"<Driver_License_Number>|<fim_PID>; <Driver_License_Number>::=id#35"^"#35id#35"^"#35id#35 <fim_Driver_License_Number>|<fim_Driver_License_Number>; <fim_Driver_License_Number>::= <fim_PID>|"|"<Mother_Identifier>; <Mother_Identifier>::=<componente_Mother_Identifier><fim_Mother_Identifier>; <componente_Mother_Identifier>::= id#36<componente_Mother_Identifier> |"^"#36<componente_Mother_Identifier>|"&"#36<componente_Mother_Identifier>|î; <fim_Mother_Identifier>::= <fim_PID>|"|"<Ethnic_Group>; <Ethnic_Group>::=<fim_Ethinic_Group>|id#37 <fim_Ethinic_Group>; <fim_Ethinic_Group>::= <fim_PID>|"|"<Birth_Place>; <Birth_Place>::= <fim_Birth_Place>|id#38 <fim_Birth_Place>; <fim_Birth_Place>::= <fim_PID>|"|"<Multiple_Birth_Indicator>; <Multiple_Birth_Indicator>::= <fim_Multiple_Birth_Indicator>|id#39 <fim_Multiple_Birth_Indicator>; <fim_Multiple_Birth_Indicator>::= <fim_PID>|"|"<Birth_Order>; <Birth_Order>::= <fim_Birth_Order>|id#40 <fim_Birth_Order>; <fim_Birth_Order>::= <fim_PID>|"|"<Citizenship>; <Citizenship>::=<fim_Citizenship>|id#41<fim_Citizenship>; <fim_Citizenship>::= <fim_PID>|"|"<Veterans_Military_Status>; <Veterans_Military_Status>::=<fim_Veterans_Military_Status>|id#42 <fim_Veterans_Military_Status>; <fim_Veterans_Military_Status>::= <fim_PID>|"|"<Nationality>; <Nationality>::=<fim_Nationality>|id#43 <fim_Nationality>; <fim_Nationality>::= <fim_PID>|"|"<Patient_Death_Date_Time>; <Patient_Death_Date_Time>::=<fim_Patient_Death_Date_Time>|id#44 <fim_Patient_Death_Date_Time>; <fim_Patient_Death_Date_Time>::= <fim_PID>|"|"<Patient_Death_Indicator>;

83

<Patient_Death_Indicator>::=<fim_PID>|id#45 <fim_PID>; <fim_PID>::= Fim_Linha#46 <pos_PID>; <pos_PID>::=<ORC>|<OBR>|<PRB>|<PV1>|<AL1>|î; <EVN>::= EVN #47 "|" <Event_Type_Code>; <Event_Type_Code>::= id #48"|"<Recorded_Date_Time>; <Recorded_Date_Time>::= id#49 <fim_Recorded_Date_Time>| <fim_Recorded_Date_Time>; <fim_Recorded_Date_Time>::= <fim_EVN>|"|"<Date_Time_Planned_Event>; <Date_Time_Planned_Event>::=id#50 <fim_Date_Time_Planned_Event>|<fim_Date_Time_Planned_Event>; <fim_Date_Time_Planned_Event>::=<fim_EVN>|"|" <Event_Reason_Code>; <Event_Reason_Code>::=id #51<fim_Event_Reason_Code>| <fim_Event_Reason_Code>; <fim_Event_Reason_Code>::=<fim_EVN>|"|"<Operator_ID>; <Operator_ID>::= id #52<fim_Operator_ID>| <fim_Operator_ID>; <fim_Operator_ID>::=<fim_EVN>|"|"<Event_Occurred>; <Event_Occurred>::=id#53 <fim_EVN> |<fim_EVN>; <fim_EVN>::= Fim_Linha#54 <pos_evento>; <pos_evento>::= î|<PID>|<MSA>; <MSA>::= MSA#55 "|" <Acknowledgment_Code>; <Acknowledgment_Code>::=id#56"|" <Message_Control_ID_MSA>; <Message_Control_ID_MSA>::=id#57 <fim_Message_Control_ID_MSA>| <fim_Message_Control_ID_MSA>; <fim_Message_Control_ID_MSA>::= <fim_MSA>|"|"<Text_Message>; <Text_Message>::= id#58 "|"<Expected_Sequence_Number>|"|" <Expected_Sequence_Number>|<fim_MSA>; <Expected_Sequence_Number>::= id #59"|"<Delayed_Acknowledgment_Type> | "|"<Delayed_Acknowledgment_Type>|<fim_MSA>;

84

<Delayed_Acknowledgment_Type>::= id #60"|"<Error_Condition>|"|"<Error_Condition>|<fim_MSA>; <Error_Condition>::= id#61 <fim_MSA>|<fim_MSA>; <fim_MSA>::= Fim_Linha#62 <pos_MSA>; <pos_MSA>::= <PID>|<EVN>|<QAK>|<ORC>|<QRD>|î; <QRD>::= QRD #114"|"<Query_date_time>; <Query_date_time>::= id #115"|" <Query_format_code>; <Query_format_code>::= id#116 "|"<Query_priority>; <Query_priority>::= id#117 "|" <Query_ID>; <Query_ID>::= id#118 "|" <Deferred_response_type>; <Deferred_response_type>::= "|" <Deferred_response_date_time> | id#119 "|" <Deferred_response_date_time>; <Deferred_response_date_time>::= "|" <Quantity_limited_request>| id#120 "|"<Quantity_limited_request>; <Quantity_limited_request>::= id #121"|" <Who_subject_filter>; <Who_subject_filter>::=<componente_Who_subject_filter>"|"<What_subject_filter>; <componente_Who_subject_filter>::= id #122<componente_Who_subject_filter> |"^"#122<componente_Who_subject_filter>|"&"#122<componente_Who_subject_filter>|î; <What_subject_filter>::= <componente_What_subject_filter>"|" <What_department_data_code>; <componente_What_subject_filter>::= id #123<componente_What_subject_filter>| "^"#123<componente_What_subject_filter>|î; <What_department_data_code>::= <componente_What_department_data_code>"|" <What_data_code_value_qualifier>; <componente_What_department_data_code>::= id #124<componente_What_department_data_code>|"^"#124 <componente_What_department_data_code>|î; <What_data_code_value_qualifier>::= "|"<Query_results_level>| id #125"|" <Query_results_level>;

85

<Query_results_level>::= <fim_QRD>|id#126 <fim_QRD>; <fim_QRD>::= Fim_Linha#127 <pos_QRD>; <pos_QRD>::= <QRF>|<DSP>|î; <QRF>::= QRF#128 "|"<Where_Subject_Filter>; <Where_Subject_Filter>::= id #129<fim_Where_Subject_Filter> |<fim_Where_Subject_Filter>; <fim_Where_Subject_Filter>::= <fim_QRF>|"|"<When_Data_Start_Date_Time>; <When_Data_Start_Date_Time>::= id #130<fim_When_Data_Start_Date_Time> |<fim_When_Data_Start_Date_Time>; <fim_When_Data_Start_Date_Time>::= <fim_QRF>|"|"<When_Data_End_Date_Time>; <When_Data_End_Date_Time>::= id #131<fim_When_Data_End_Date_Time>| <fim_When_Data_End_Date_Time>; <fim_When_Data_End_Date_Time>::= <fim_QRF>|"|"<What_User_Qualifier>; <What_User_Qualifier>::= id #132<fim_What_User_Qualifier> |<fim_What_User_Qualifier>; <fim_What_User_Qualifier>::= <fim_QRF>|"|"<Other_QRY_Subject_Filter>; <Other_QRY_Subject_Filter>::= id#133 <fim_Other_QRY_Subject_Filter>| <fim_Other_QRY_Subject_Filter>; <fim_Other_QRY_Subject_Filter>::= <fim_QRF>|"|"<Which_Date_Time_Qualifier>; <Which_Date_Time_Qualifier>::=id#134 <fim_Which_Date_Time_Qualifier> |<fim_Which_Date_Time_Qualifier>; <fim_Which_Date_Time_Qualifier>::= <fim_QRF>|"|" <Which_Date_Time_Status_Qualifier>; <Which_Date_Time_Status_Qualifier>::=id#135 <fim_Which_Date_Time_Status_Qualifier>|<fim_Which_Date_Time_Status_Qualifier>; <fim_Which_Date_Time_Status_Qualifier>::= <fim_QRF>|"|" <Date_Time_Selection_Qualifier>; <Date_Time_Selection_Qualifier>::= id#136 <fim_Date_Time_Selection_Qualifier> |<fim_Date_Time_Selection_Qualifier>; <fim_Date_Time_Selection_Qualifier>::= <fim_QRF>|"|" <When_Quantity_Timing_Qualifier>; <When_Quantity_Timing_Qualifier>::= <componente_When_Quantity_Timing_Qualifier><fim_QRF>;

86

<componente_When_Quantity_Timing_Qualifier>::= id #137 <componente_When_Quantity_Timing_Qualifier>| "^"#137<componente_When_Quantity_Timing_Qualifier>|î; <fim_QRF>::= Fim_Linha #138<pos_QRF>; <pos_QRF>::= î; <DSP>::= DSP#160"|"<Display_Level>; <Display_Level>::= id#161 "|" <Data_Line>| "|"<Data_Line>; <Data_Line>::= id #162<fim_Data_Line> | <fim_Data_Line>; <fim_Data_Line>::= "|"<Logical_Break_Point>|<fim_DSP>; <Logical_Break_Point>::= id#163 <fim_Logical_Break_Point>| <fim_Logical_Break_Point>; <fim_Logical_Break_Point>::= "|"<Result_ID>|<fim_DSP>; <Result_ID>::= id#164 <fim_DSP>; <fim_DSP>::= Fim_Linha #165<pos_DSP>; <pos_DSP>::= <DSP>| î; <QAK>::= QAK #173"|" <Query_Tag_QAK>; <Query_Tag_QAK>::= id#174 "|" <Query_Response_Status> |"|" <Query_Response_Status>; <Query_Response_Status>::= id#175 Fim_Linha#176 <pos_QAK>| Fim_Linha#176<pos_QAK>; <pos_QAK>::= <DSP>|<QRD>|<EVN>|<RDF>|<PID>|î;

87

ANEXO 3 – ARTIGO

Modelo de Interoperabilidade de Sistemas Hospitalares Utilizando o Padrão HL7

KARINE PETRY

PAULA MARIEN ALBRECHT LOPES

Universidade Federal de Santa Catarina Departamento de Informática e Estatística

[email protected] [email protected]

______________________________________________________________ Resumo Este artigo descreve um modelo de interoperabilidade de sistemas de saúde através do desenvolvimento de um middleware projetado segundo as especificações do padrão HL7. Palavras-chave: interoperabilidade, saúde, HL7, middleware. _________________________________________________________________________

Introdução Em virtude da disparidade existente entre os sistemas projetados para o mundo dos negócios e aqueles que englobam a área da saúde, tornou-se necessário à elaboração de mecanismos que facilitem as transações num meio constituído por diversas peculiaridades como é o serviço de saúde em qualquer lugar do globo.

O ambiente de saúde merece uma atenção especial, pois os registros de informações de saúde de um paciente como laudos, sinais vitais, exames laboratoriais, e imagens médicas, não devem ser armazenados exclusivamente em papel, e sim, em meio eletrônico, para então proporcionar uma disponibilidade agilizada, de modo confiável, com integridade garantida, admitindo redução de custos e ainda com uma independência física do local de armazenamento. Dessa forma, surgiu o Prontuário Eletrônico de Pacientes (PEP), com a finalidade de

permitir a integração e armazenamento da informação clínica e administrativa de pacientes de forma individual.

O emprego do prontuário eletrônico trouxe como conseqüência imediata à necessidade de uma padronização para garantir a transmissão das informações clínicas de um paciente, entre os mais diversos sistemas de informação que englobam um ambiente de saúde. Assim, com este propósito, foram projetados alguns padrões, destacando-se o padrão HL7 a nível internacional. Visão Geral do HL7 Em 1987, foi fundada uma organização sem fins lucrativos denominada HL7( Health Level Seven), [2] com a responsabilidade de produzir normas para a área de saúde, relacionados com a informação clínica e administrativa.

O padrão especifica quais as mensagens a serem trocadas entre os

88

diversos setores do hospital. Dentre os vários tipos de mensagens definidos pelo HL7 podem ser citadas: gestão de pacientes ao nível de admissão, transferências e saídas, pedidos, resultados, observações clínicas e contabilidade.

A unidade básica de informação, a ser trocada entre os vários intervenientes, é designada no padrão HL7 por mensagem. O padrão especifica além das características principais da troca de mensagens entre sistemas distintos, os vários tipos de mensagem e respectiva constituição. Genericamente uma mensagem é constituída por segmentos, que por sua vez são constituídos por campos, sendo estes últimos organizados em componentes.

Assim, o padrão HL7 define o formato das mensagens, ou seja, descreve como os dados devem ser representados, o seu tipo e quais os caracteres usados para delimitar os vários segmentos numa mensagem. Também especifica as circunstâncias em que as mensagens devem ocorrer, regras como conseqüência de eventos (trigger event). Por exemplo, se for definido que os dados pessoais de um paciente devem ser disponibilizados, então quando houver uma admissão de paciente, automaticamente deve ser desencadeada uma mensagem que transmita a informação a todos os interessados (consulta não solicitada – unsolicited message).

O padrão HL7 também define os procedimentos que devem ser realizados na ocorrência de certos erros entre as aplicações. Por exemplo, caso uma aplicação não receba os dados que esperava, esta pode comunicar o fato para a aplicação emissora através de uma mensagem de erro. Por outro lado, se a transmissão dos dados foi efetuada

corretamente, então uma mensagem de confirmação (ACK-acknowledge) pode igualmente ser enviada. Garantindo, portanto confiabilidade na troca de mensagens.

Podemos considerar os principais tipos básicos de mensagens:

• Gestão de pacientes ou ADT - relativas à gestão da estada do paciente no hospital, admissão, transferência e saídas de pacientes por esta razão também conhecidas por mensagens ADT - admissions, discharges, transfers. São desencadeadas sem uma consulta prévia explícita (unsolicited messages).

• Pedidos/Querys – utilizadas para requisição (consulta) de informação. Uma situação típica ocorre quando um dos setores (farmácia, laboratório) consulta o sistema de admissão com respeito à informação de um paciente;

• Resultados/Observações – Resulta como resposta a uma mensagem do tipo (pedido/query) e a sua função é permitir a transmissão de observações clínicas, por exemplo;

• Outras - relativas à informação contabilística e financeira, experiências clínicas, bases de dados, etc.[1]

Na figura 1, é mostrado um

exemplo de mensagem de admissão de paciente (ADT^A01) composta pelos segmentos MSH, EVN, PID.

89

Figura 1 – Mensagem de admissão de paciente O HL7 não restringe o sistema

operacional, nem a linguagem de programação a ser utilizada para a troca de informação. Além disso, o HL7 é independente de meio físico e de protocolo de comunicação. O padrão HL7 permite ao implementador definir suas próprias mensagens, o que mais uma vez, torna-o flexível.

Modelo Desenvolvido Considerando que a implementação do padrão HL7 é uma tarefa árdua (mencionada em bibliografias pesquisadas), e realmente constatada na prática, cogitou-se então, o desenvolvimento de um middleware para servir como uma camada de apoio ao desenvolvedor de sistemas legados. Assim, com este objetivo, solucionou-se a integração de aplicações sem a necessidade de estas implementarem o padrão HL7, sendo apenas necessário que as mesmas sejam capazes de enviar streams seguindo uma estrutura mais simples que a proposta pelo HL7. Para isto, foi desenvolvido um modelo de sistema que apresentasse comportamento semelhante de um middleware, para disponibilizar os serviços oferecidos pelo HL7 utilizando um servidor, clientes e aplicações permitindo dessa forma a interoperabilidade de sistemas hospitalares.

Através da figura 2 é possível compreender a estrutura deste modelo.

Figura 2 – Mensagem de admissão de paciente

As aplicações GE, CP e PEP representadas na figura 2, tratam de aplicações referentes respectivamente a gerência de exames laboratoriais, cadastro de pacientes e prontuário eletrônico de pacientes. Vale lembrar que tais aplicações foram desenvolvidas apenas ao nível de teste possibilitando a análise da execução do modelo construído.

A troca de mensagens entre as aplicações e o sistema cliente utiliza uma estrutura simples, diferente do HL7. As informações enviadas pela aplicação ao seu respectivo cliente deverão estar separadas por um símbolo pré-definido, em nosso exemplo, utilizamos o símbolo “|” como separador. Já a troca de mensagens entre os sistemas cliente e servidor devem ser geradas seguindo a estrutura proposta pelo protocolo de comunicação HL7. Assim, caso a aplicação CP deseje enviar mensagem de admissão para as aplicações GE e PEP, ela deverá enviar as informações demográficas do novo paciente, bem como a aplicação destino e o tipo de mensagem. A informação referente à aplicação destino é válida apenas nos casos em que o tipo de mensagem a ser enviada é uma confirmação, solicitação de busca ou resultado de busca, nos casos em que o tipo de mensagem é referente a uma admissão, tal informação deverá ser preenchida apenas de forma representativa,

MSH|^~\&|ADT1|CadPaciente|GerenciaExames|CadPaciente |20051003091411||ADT^A01| IDMSH20051003 09:14:11|P|2.3<cr> EVN|A01|20051003 09:14:11<cr> PID| | |TR54| |Silva^Marcelo^Loyola^II^Dr |Maria Ferreira|194510100000|M||Asiatica|Rua Minas Gerais 55||(48)9833-8956|(48)398-6665|Portugues|Solteiro|Adventista |989896632|96556 |98989^055^65||Desconhecido|Treze Tilias|Sim|3|Brasileiro||Brasileiro|1900121200 | <cr>

90

uma vez que este tipo de mensagem é encaminhada pelo servidor a todos os aplicativos registrados em sua base de dados. A partir do momento que o cliente receber a mensagem da aplicação, esta deverá ser reconstruída seguindo as normas de especificação do padrão HL7. Nas figuras 3 e 4 podemos verificar a mensagem enviada pela aplicação e a mesma mensagem sendo então encaminhada pelo cliente ao servidor.

Figura 3 - Mensagens Trocadas entre Aplicação e Cliente

Figura 4 - Mensagens Trocadas entre Cliente e Servidor

Conclusão Como a tarefa de implementação do padrão HL7 se mostrou demasiadamente exaustiva, percebeu-se a necessidade do desenvolvimento de um middleware para facilitar o trabalho do desenvolvedor, que então poderia integrar seus sistemas, sem tomar conhecimento da complexidade que envolve a implementação das especificações do padrão HL7. Constatou-se que o esforço necessário para o desenvolvimento deste middleware foi compensador, visto que objetivo principal do padrão HL7 - a interoperabilidade de sistemas hospitalares - é realmente alcançado. Referências

[1] HENRIQUES, J.; CARVALHO, P. HL7 Health Level Seven. https://www.dei.uc.pt/weboncampus/course/LEI/2004-2005/hl7V23Aulas.pdf. (11/08/2005) [2] HL7 USA Central Web Pages. http://www.hl7.org. (18/08/2005).

91

ANEXO 4 – CÓDIGO FONTE ----------------------Classe MainInterface.cpp (Aplicação Gerência de Exames)----------------- #include "MainInterface.h" #include <glib.h> #include <gtk/gtksignal.h> #include <gtk/gtk.h> #include <pthread.h> #include <stdio.h> #ifndef unix #include <io.h> #endif #include <iostream> #include <fstream> #include <exception> #include <iomanip> using namespace std; PGconn *conn; //Cria um ponteiro para uma estrutura GladeXML GladeXML * xmlJP,*xmlJRE,*xmlJCE; GtkWidget* w, *entry; GtkWidget *janelaConsultaExame, *janelaResultadoExame; gchar *id_etiqueta_ResulExame; char *tem_cad_paciente; //corpo principal do Programa int main(int argc,char *argv[]) { g_thread_init (NULL); gdk_threads_init (); gdk_threads_enter ();/*iniciaiza a thread para q o sistema possa ouvir e rodar a interface ao mesmo tempo*/ gtk_init(&argc,&argv); //Inicializa o GTK glade_init();//Inicializa o Glade–opcional //Lê o arquivo com a estrutura XML da sua aplicação xmlJP = glade_xml_new("interface/interface.glade","JanelaPrincipal",NULL); //inicializar eventos(signals) da Janela Principal w = glade_xml_get_widget (xmlJP, "buttonBuscar"); gtk_signal_connect(GTK_OBJECT(w), "clicked", GTK_SIGNAL_FUNC(buscarExame), NULL); w = glade_xml_get_widget (xmlJP, "buttonNovo"); gtk_signal_connect(GTK_OBJECT(w),"clicked",GTK_SIGNAL_FUNC(novoExame),NULL);

92

w = glade_xml_get_widget (xmlJP, "buttonSair"); gtk_signal_connect(GTK_OBJECT(w),"clicked", GTK_SIGNAL_FUNC(sair), NULL); w = glade_xml_get_widget (xmlJP, "buttonSalvar"); gtk_signal_connect(GTK_OBJECT(w), "clicked", GTK_SIGNAL_FUNC(salvarExame), NULL); w = glade_xml_get_widget (xmlJP, "buttonSelecionaExame"); gtk_signal_connect(GTK_OBJECT(w),"clicked", GTK_SIGNAL_FUNC(buscarTipoExame), NULL); w = glade_xml_get_widget (xmlJP, "buttonOKBusca"); gtk_signal_connect(GTK_OBJECT(w),"clicked", GTK_SIGNAL_FUNC(buscarExamesCadastrados), NULL); w = glade_xml_get_widget (xmlJP, "buttonResultado"); gtk_signal_connect(GTK_OBJECT(w),"clicked", GTK_SIGNAL_FUNC(verResultadoExame), NULL); w = glade_xml_get_widget (xmlJP, "entryIDInterno"); gtk_signal_connect(GTK_OBJECT(w),"focus_out_event", GTK_SIGNAL_FUNC(buscarDadosPaciente), NULL); w = glade_xml_get_widget (xmlJP, "notebook1"); gtk_signal_connect(GTK_OBJECT(w),"switch_page", GTK_SIGNAL_FUNC(alteraEnabledBotoes), NULL); w = glade_xml_get_widget (xmlJP, "tabelaExames"); gtk_signal_connect(GTK_OBJECT(w),"select_row", GTK_SIGNAL_FUNC(selecionaDadosTabelaExame), NULL); //permitir que o edit fique desabilitado w = glade_xml_get_widget(xmlJRE,"entryEtiqueta"); gtk_widget_set(w,"editable",false); //permitir que o botão fique desabilitado w = glade_xml_get_widget(xmlJP,"buttonNovo"); gtk_widget_set(w,"sensitive",false); pthread_t threadOuvir; int status; int i =0; int rc = pthread_create(&threadOuvir, NULL, ouvirCliente, (void *)i) ; if (rc){ printf("ERRO no retorno função pthread_create() %d\n", rc); exit(-1); }//if gtk_main(); // O Loop de eventos do GTK gdk_threads_leave(); return 0; } //encerra conexão com banco de dados e a aplicação void exit_nicely(){

93

PQfinish(conn); exit(1); } char* getEndIPLocal(){ #ifndef unix WORD wVersionRequested; WSADATA wsaData; PHOSTENT hostinfo; wVersionRequested = MAKEWORD( 1, 1 ); #endif #ifdef unix struct hostent *hostinfo; #endif char name[255]; char *ip; #ifndef unix if ( WSAStartup( wVersionRequested, &wsaData ) == 0 ) #endif if( gethostname ( name, sizeof(name)) == 0) { if((hostinfo = gethostbyname(name)) != NULL) { int nCount = 0; #ifndef unix while(hostinfo->h_addr_list[nCount]){ ip = inet_ntoa(*(struct in_addr *)hostinfo->h_addr_list[nCount]); nCount++; } #endif #ifdef unix ip = inet_ntoa(*((struct in_addr *)hostinfo->h_addr)); #endif } } return ip; } #ifndef unix void enviarMensagem(SOCKET s, string msg){ int bytesSent; const char* sendbuf = msg.c_str(); bytesSent = send( s, sendbuf, strlen(sendbuf), 0 ); closesocket(s); } #endif #ifdef unix void enviarMensagemUnix(int s, string msg){ int bytesSent; const char* sendbuf = msg.c_str();

94

bytesSent = send( s, sendbuf, strlen(sendbuf), 0 ); close(s); } #endif void enviarParaCliente(string msg){ #ifndef unix WSADATA wsaData; int iResult = WSAStartup( MAKEWORD(2,2), &wsaData ); if ( iResult != NO_ERROR ) printf("Erro no WSAStartup()\n"); SOCKET m_socketEnvio; #endif #ifdef unix int m_socketEnvio; #endif m_socketEnvio = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ); #ifndef unix if ( m_socketEnvio == INVALID_SOCKET ) { WSACleanup(); } #endif #ifdef unix if ( m_socketEnvio == -1 ) { } #endif sockaddr_in clientService; clientService.sin_family = AF_INET; clientService.sin_addr.s_addr = inet_addr( getEndIPLocal()); clientService.sin_port = htons( 27014 ); #ifndef unix if ( connect( m_socketEnvio, (SOCKADDR*) &clientService, sizeof(clientService) ) == SOCKET_ERROR) { WSACleanup(); MessageBox(NULL,"Não foi possível estabelecer conexão com o cliente", "GE HL7",MB_ICONSTOP|MB_OK); }//if #endif #ifdef unix if ( connect( m_socketEnvio, (struct sockaddr*) &clientService, sizeof(clientService) ) == -1) { printf( "Falha na conexao...%s[%d]\n", strerror(errno),errno); }//if #endif else{ #ifndef unix enviarMensagem(m_socketEnvio, msg); #endif

95

#ifdef unix enviarMensagemUnix(m_socketEnvio,msg); #endif }//else } void updatePaciente(string id_paciente, string flag){ string sql = "UPDATE paciente SET tem_cad_paciente = '"+ flag+"' WHERE id_paciente_interno = '"+id_paciente+"'"; PGresult *res = PQexec(conn, sql.c_str()); if (PQresultStatus(res) == PGRES_FATAL_ERROR){ fprintf(stderr, "Erro durante update da tabela paciente!\n", PQerrorMessage(conn)); PQclear(res); exit_nicely(); }//if } bool pacienteJaTemCadastro(string id_paciente){ if (conn == NULL) conectarBanco(); string sql = "Select id_paciente_interno from paciente where id_paciente_interno = '"+id_paciente+"'"; PGresult *res = PQexec(conn, sql.c_str()); if (PQresultStatus(res) != PGRES_TUPLES_OK){ fprintf(stderr,"Erro durante a selecao tipo_exame para salvar resultado!\n", PQerrorMessage(conn)); PQclear(res); exit_nicely(); }//if //se existe paciente então devo setar o campo ja_tem_cadastro para "S" if (PQntuples(res)>0){ updatePaciente(id_paciente,"S"); return true; } else return false; } string criarBuscaParaCadastroPaciente(string id_paciente){ return "GerenciaExames|BuscaPaciente|CadastroPaciente|"+id_paciente+"|DEM|"; } string criarResultadoParaProntuario(string id_paciente,string flag, string cod_exame){ if (conn == NULL) conectarBanco(); string sql; if (flag=="N") { sql = "Select resultado.*, tipo_exame.nome_exame from tipo_exame,exame inner join resultado on(resultado.cod_etiqueta = exame.id_etiqueta) where id_paciente_interno = '"+ id_paciente+"' and exame.cod_tipo_exame = tipo_exame.cod_exame"; }//if else {

96

sql = "Select resultado.*, tipo_exame.nome_exame from tipo_exame,exame inner join resultado on(resultado.cod_etiqueta = exame.id_etiqueta) where id_paciente_interno = '"+ id_paciente+"' and exame.cod_tipo_exame = cod_exame and resultado.cod_etiqueta = '"+cod_exame+"'"; } PGresult *res = PQexec(conn, sql.c_str()); if (PQresultStatus(res) != PGRES_TUPLES_OK){ fprintf(stderr, "Erro durante a selecao ddos dados para criar msg PEP\n", PQerrorMessage(conn)); PQclear(res); exit_nicely(); }//if da exceção sql char quant[4]; itoa(PQntuples(res),quant,10); string msgPEP = "GerenciaExames|ResultadoExame|ProntuarioEletronico|"+ id_paciente+"|RES |"+(string) quant+"|"; int leucocitos_fnum = PQfnumber(res, "leucocitos"); int eritrocitos_fnum = PQfnumber(res, "eritrocitos"); int hematocitos_fnum = PQfnumber(res, "hematocitos"); int hemoglobina_fnum = PQfnumber(res, "hemoglobina"); int colesterol_fnum = PQfnumber(res, "colesterol"); int glicose_fnum = PQfnumber(res, "glicose"); int creatina_fnum = PQfnumber(res, "creatina"); int sodio_fnum = PQfnumber(res, "sodio"); int potassio_fnum = PQfnumber(res, "potassio"); int calcio_fnum = PQfnumber(res, "calcio"); int magnesio_fnum = PQfnumber(res, "magnesio"); int fosforo_fnum = PQfnumber(res, "fosforo"); int ph_fnum = PQfnumber(res, "ph"); int densidade_fnum = PQfnumber(res, "densidade"); int hemacias_fnum = PQfnumber(res, "hemacias"); int proteinas_fnum = PQfnumber(res, "proteinas"); int bacterioscopia_fnum = PQfnumber(res, "bacterioscopia"); int ldl_fnum = PQfnumber(res, "colesterol_ldl"); int hdl_fnum = PQfnumber(res, "colesterol_hdl"); int vldl_fnum = PQfnumber(res, "colesterol_vldl"); int exame_fnum = PQfnumber(res, "nome_exame"); char *nome_exame, *colesterol_vldl, *colesterol_hdl, *colesterol_ldl, *bacterioscopia, *proteinas, *hemacias,*densidade, *ph, *fosforo, *magnesio, *calcio, *potassio, *sodio, *creatina, *glicose, *colesterol, *hemoglobina, *hematocitos, *eritrocitos, *leucocitos; //percorre todas as linhas e verifica o tipo de exame antes de gerar string //contendo resultado for (int i = 0; i < PQntuples(res);i++) { nome_exame = PQgetvalue(res, i, exame_fnum); string tipo_exame = (string)nome_exame; if (tipo_exame == "Hemograma Completo") { leucocitos = PQgetvalue(res, i, leucocitos_fnum); eritrocitos = PQgetvalue(res, i, eritrocitos_fnum); hematocitos = PQgetvalue(res, i, hematocitos_fnum); hemoglobina = PQgetvalue(res, i, hemoglobina_fnum);

97

colesterol = PQgetvalue(res, i, colesterol_fnum); glicose = PQgetvalue(res, i, glicose_fnum); creatina = PQgetvalue(res, i, creatina_fnum); sodio = PQgetvalue(res, i,sodio_fnum); potassio = PQgetvalue(res, i, potassio_fnum); calcio = PQgetvalue(res, i, calcio_fnum); magnesio = PQgetvalue(res, i, magnesio_fnum); fosforo = PQgetvalue(res, i, fosforo_fnum); string dados = "Leucocitos:["+(string)leucocitos+"] Eritrocitos:["+ (string)eritrocitos+"] Hematocitos:["+ (string)hematocitos+"] Hemoglobina:["+ (string)hemoglobina+"] Colesterol:["+ (string)colesterol+"] Glicose:["+ (string)glicose+"] Creatina:["+ (string)creatina+"] Sodio:["+ (string)sodio+"] Potassio:["+ (string)potassio+"] Calcio:["+ (string)calcio+"] Magnesio:["+ (string)magnesio+"] Fosforo:["+ (string)fosforo+"])|"; msgPEP = msgPEP+"Hemograma Completo ("+dados; }//if if (tipo_exame == "Urina") { ph = PQgetvalue(res, i, ph_fnum); densidade = PQgetvalue(res, i, densidade_fnum); hemacias = PQgetvalue(res, i, hemacias_fnum); proteinas = PQgetvalue(res, i, proteinas_fnum); bacterioscopia = PQgetvalue(res, i, bacterioscopia_fnum); glicose = PQgetvalue(res, i, glicose_fnum); string dados = "PH:["+(string)ph+"] Densidade:["+ (string)densidade+"] Hemacias:["+ (string)hemacias+"] Proteinas:["+ (string)proteinas+"] Glicose:["+ (string)glicose+"] Bacterioscopia:["+ (string)bacterioscopia+"])|"; msgPEP = msgPEP+"Urina ("+dados; }//if if(tipo_exame == "Colesterol"){ colesterol_ldl = PQgetvalue(res, i, ldl_fnum); colesterol_hdl = PQgetvalue(res, i, hdl_fnum); colesterol_vldl = PQgetvalue(res, i, vldl_fnum); string dados = "Colesterol LDL:["+ (string)colesterol_ldl+"] Colesterol HDL:["+ (string)colesterol_hdl+"] Colesterol VLDL:["+ (string)colesterol_vldl+"])|"; msgPEP = msgPEP+"Colesterol ("+dados; }//if }//for return msgPEP; } void excluirDaBusca(string id_paciente){ string sql = "Delete from busca where id_paciente = '"+id_paciente+"'"; PGresult *res = PQexec(conn, sql.c_str()); if (PQresultStatus(res) == PGRES_FATAL_ERROR)

98

{ fprintf(stderr, "Erro durante a exclusao de busca!\n",PQerrorMessage(conn)); PQclear(res); exit_nicely(); }//if } string alterarFormatoDataNascimento(string nascimento){ string ano = nascimento.substr(0,4); string mes = nascimento.substr(4,2); string dia = nascimento.substr(6,2); string hora = nascimento.substr(8,2); string min = nascimento.substr(10,2); return dia+"/"+mes+"/"+ano+" "+hora+":"+min; } void *receberMensagem(void *s){ #ifndef unix SOCKET soc = (SOCKET) s; #endif #ifdef unix int soc = (int) s; #endif int bytesRecv = -1; char recvbuf[750] = ""; bytesRecv = recv( soc, recvbuf, 750, 0 ); if (bytesRecv > 0) { char * msg = recvbuf; string primeiroCampo = strtok(msg,"|"); string token = strtok(NULL,"|"); if (token == "ADT") {//recebida mensagem de inclusao de Paciente token = strtok(NULL,"|");//pula dataHoraMsg token = strtok(NULL,"|");//pula aplicRemetente string id_paciente_interno = strtok(NULL,"|"); //se jah estah cadastrado entao tem_cadastro = S, se naum vou //incluir na base if (pacienteJaTemCadastro(id_paciente_interno)==false) { string nome_paciente = strtok(NULL,"|"); string nascimento = strtok(NULL,"|"); string data_nascimento=alterarFormatoDataNascimento(nascimento); string sexo = strtok(NULL,"|"); inserirDadosTabelaPaciente(id_paciente_interno,nome_paciente, data_nascimento,sexo,"S"); }//if }//if if (token== "ACK") {//recebida mensagem de confirmação MessageBox(NULL,"Recebeu confirmacao","Gerencia Exames HL7", MB_ICONINFORMATION|MB_OK); }//if if (token== "RPI") {//mensagem recebida é resultado de uma busca

99

token = strtok(NULL,"|");//pula dataHoraMsg token = strtok(NULL,"|");//pula aplicRemetente token = strtok(NULL,"|"); string id_paciente_interno = token; token = strtok(NULL,"|"); /*campo referente ao status da consulta, se for NF é porque p paciente não se encontra cadastrado na base do aplicativo Cadastropaciente, se não, retorna OK*/ if (token != "NF") { updatePaciente(id_paciente_interno, "S"); string msgem = criarResultadoParaProntuario(id_paciente_interno,"N","0"); enviarParaCliente(msgem); }//if excluirDaBusca(id_paciente_interno); }//if token = strtok(NULL,"¨"); //encontrar msgRecebida e adiciona-la no textView da aba Receber token = strtok(NULL,"¨"); string msgRecebida = token; GtkWidget *textview = glade_xml_get_widget(xmlJP,"tvMsgsRecebidas"); GtkTextIter start, end; GtkTextBuffer *buffer= gtk_text_buffer_new(NULL); buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview)); gtk_text_buffer_get_bounds(buffer, &start, &end); char * msgTextView = gtk_text_buffer_get_text(buffer, &start, &end, FALSE); string teste = (string)msgTextView+"\n"+ msgRecebida+"\n************************************"; gtk_text_buffer_set_text(buffer,teste.c_str(), -1); gtk_text_view_set_buffer(GTK_TEXT_VIEW(textview),buffer); }//if } void *ouvirCliente(void * i){ #ifndef unix // Inicializa Winsock. WSADATA wsaData; //inicia o socket, o MAKEWORD(2,2) encontra versão do winsocket int iResult = WSAStartup( MAKEWORD(2,2), &wsaData ); if ( iResult != NO_ERROR ){} SOCKET m_socket; #endif #ifdef unix int m_socket; #endif // Cria socket m_socket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ); /*primeiro parametro é a familia, segundo é o tipo(TCP ou UDP e o terceiro é o protocolo associado a familia)*/ #ifndef unix if ( m_socket == INVALID_SOCKET ) {

100

WSACleanup(); printf("socket invalido!\n"); } #endif #ifdef unix if ( m_socket == -1) {} #endif sockaddr_in service; service.sin_family = AF_INET; service.sin_addr.s_addr = inet_addr(getEndIPLocal()); service.sin_port = htons(27010);//porta em que o aplicativo estará "ouvindo" //bind associa o socket ao endereço #ifndef unix if (bind(m_socket,(SOCKADDR*)&service, sizeof(service) ) == SOCKET_ERROR ) { closesocket(m_socket); printf("erro no bind!\n"); } #endif #ifdef unix if ( bind( m_socket, (struct sockaddr*)&service, sizeof(service) ) == -1 ) { close(m_socket); } #endif //lista o numero max de conexões aceitas pelo servidor if ( listen( m_socket, 1 ) == -1 ){} #ifndef unix SOCKET AcceptSocket; #endif #ifdef unix int AcceptSocket; #endif pthread_t threadCliente; int status; while (true) { //Aguarda por novas conexões AcceptSocket = accept( m_socket, NULL, NULL ); if (AcceptSocket != -1) { int rc = pthread_create(&threadCliente, NULL, receberMensagem, (void *)AcceptSocket) ; rc = pthread_join(threadCliente, (void **)&status); if (rc){ exit(-1); }//if #ifndef unix closesocket(AcceptSocket); #endif #ifdef unix close(AcceptSocket); #endif }//if

101

}//while } bool jaFezBuscaEmCadastroPaciente(string id_paciente){ string sql = "Select * from busca where id_paciente = '"+id_paciente+"'"; PGresult *res = PQexec(conn, sql.c_str()); if (PQresultStatus(res) != PGRES_TUPLES_OK) { fprintf(stderr,"Erro durante selecao de dados em busca\n", PQerrorMessage(conn)); PQclear(res); exit_nicely(); }//if if (PQntuples(res)>0) { return true; }//if else { return false; }//else } void armazenarNaBusca(string id,string cod_exame){ string sql = "Insert into busca (id_paciente, cod_etiqueta_exame) values ('"+id+"', '"+cod_exame+"')"; PGresult *res = PQexec(conn, sql.c_str()); if (PQresultStatus(res) == PGRES_FATAL_ERROR){ fprintf(stderr, "Erro durante inserção de dados em busca!\n", PQerrorMessage(conn)); PQclear(res); exit_nicely(); }//if } void salvarResultadoExame(){ PGresult *res ; string sql; w = glade_xml_get_widget(xmlJRE,"entryTipoExameJRE"); string nome_exame = gtk_entry_get_text(GTK_ENTRY(w)); sql = "Select cod_exame from tipo_exame,paciente where nome_exame = '"+ nome_exame+"'"; res = PQexec(conn, sql.c_str()); if (PQresultStatus(res) != PGRES_TUPLES_OK){ fprintf(stderr,"Erro durante selecao tipo_exame para salvar resultado!\n", PQerrorMessage(conn)); PQclear(res); exit_nicely(); }//if int cod_exame_fnum = PQfnumber(res, "cod_exame"); char* cod_exame = PQgetvalue(res, 0, cod_exame_fnum); w = glade_xml_get_widget(xmlJRE,"entryCodEtiquetaJRE"); string cod_etiqueta = gtk_entry_get_text(GTK_ENTRY(w)); if (nome_exame=="Hemograma Completo")

102

{ w = glade_xml_get_widget(xmlJRE,"entryHematocitos"); string hematocitos = gtk_entry_get_text(GTK_ENTRY(w)); w = glade_xml_get_widget(xmlJRE,"entryEritrocitos"); string eritrocitos = gtk_entry_get_text(GTK_ENTRY(w)); w = glade_xml_get_widget(xmlJRE,"entryLeucocitos"); string leucocitos = gtk_entry_get_text(GTK_ENTRY(w)); w = glade_xml_get_widget(xmlJRE,"entryHemoglobina"); string hemoglobina = gtk_entry_get_text(GTK_ENTRY(w)); w = glade_xml_get_widget(xmlJRE,"entryColesterol"); string colesterol = gtk_entry_get_text(GTK_ENTRY(w)); w = glade_xml_get_widget(xmlJRE,"entryGlicose"); string glicose = gtk_entry_get_text(GTK_ENTRY(w)); w = glade_xml_get_widget(xmlJRE,"entryCreatina"); string creatina = gtk_entry_get_text(GTK_ENTRY(w)); w = glade_xml_get_widget(xmlJRE,"entrySodio"); string sodio = gtk_entry_get_text(GTK_ENTRY(w)); w = glade_xml_get_widget(xmlJRE,"entryPotassio"); string potassio = gtk_entry_get_text(GTK_ENTRY(w)); w = glade_xml_get_widget(xmlJRE,"entryCalcio"); string calcio = gtk_entry_get_text(GTK_ENTRY(w)); w = glade_xml_get_widget(xmlJRE,"entryMagnesio"); string magnesio = gtk_entry_get_text(GTK_ENTRY(w)); w = glade_xml_get_widget(xmlJRE,"entryFosforo"); string fosforo = gtk_entry_get_text(GTK_ENTRY(w)); sql = "Insert into resultado (cod_etiqueta, hematocitos, eritrocitos, leucocitos, hemoglobina, colesterol, glicose, creatina, sodio, potassio, calcio, magnesio, fosforo) values ('"+ cod_etiqueta+"', '"+hematocitos+"', '"+ eritrocitos+"', '"+leucocitos+"', '"+ hemoglobina+"', '"+colesterol+"', '"+ glicose+"', '"+creatina+"', '"+sodio+"', '"+ potassio+"', '"+calcio+"', '"+ magnesio+"', '"+fosforo+"')"; }//hemograma if (nome_exame=="Urina") { w = glade_xml_get_widget(xmlJRE,"entryPH"); string ph = gtk_entry_get_text(GTK_ENTRY(w)); w = glade_xml_get_widget(xmlJRE,"entryDensidade"); string densidade = gtk_entry_get_text(GTK_ENTRY(w)); w = glade_xml_get_widget(xmlJRE,"entryHemacias"); string hemacias = gtk_entry_get_text(GTK_ENTRY(w)); w = glade_xml_get_widget(xmlJRE,"entryProteinas"); string proteinas = gtk_entry_get_text(GTK_ENTRY(w)); w = glade_xml_get_widget(xmlJRE,"entryGlicoseUrina"); string glicose = gtk_entry_get_text(GTK_ENTRY(w)); w = glade_xml_get_widget(xmlJRE,"tvBacterioscopia"); GtkTextIter start, end; GtkTextBuffer *buffer= gtk_text_buffer_new(NULL); buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(w)); gtk_text_buffer_get_bounds(buffer, &start, &end); char * result = gtk_text_buffer_get_text(buffer, &start, &end, FALSE); string bacterioscopia = result; sql = "Insert into resultado (cod_etiqueta, ph, densidade, hemacias, proteinas, glicose, bacterioscopia) values ('"+ cod_etiqueta+"', '"+ph+"', '"+densidade+"', '"+hemacias+"', '"+

103

proteinas+"', '"+glicose+"', '"+bacterioscopia+"')"; }//urina if(nome_exame=="Colesterol"){ w = glade_xml_get_widget(xmlJRE,"entryLDL"); string ldl = gtk_entry_get_text(GTK_ENTRY(w)); w = glade_xml_get_widget(xmlJRE,"entryHDL"); string hdl = gtk_entry_get_text(GTK_ENTRY(w)); w = glade_xml_get_widget(xmlJRE,"entryVLDL"); string vldl = gtk_entry_get_text(GTK_ENTRY(w)); sql = "Insert into resultado (cod_etiqueta, colesterol_ldl, colesterol_hdl, colesterol_vldl) values ('"+ cod_etiqueta+"', '"+ldl+"', '"+hdl+"', '"+vldl+"')"; }//colesterol res = PQexec(conn, sql.c_str()); if (PQresultStatus(res) == PGRES_FATAL_ERROR) { fprintf(stderr, "Erro durante a inserção dos dados na tabela paciente!\n", PQerrorMessage(conn)); PQclear(res); exit_nicely(); }//if w = glade_xml_get_widget(xmlJP,"entryIdInternoBusca"); string id = gtk_entry_get_text(GTK_ENTRY(w)); sql = "Select tem_cad_paciente from paciente where id_paciente_interno = '" +id+"'"; res = PQexec(conn, sql.c_str()); if (PQresultStatus(res) != PGRES_TUPLES_OK) { fprintf(stderr, "Erro durante a selecao tem_cad_paciente!\n", PQerrorMessage(conn)); PQclear(res); exit_nicely(); }//if int tem_cad_fnum = PQfnumber(res, "tem_cad_paciente"); char* tem_cad_paciente = PQgetvalue(res, 0, tem_cad_fnum); string cadPaciente = (string)tem_cad_paciente; if (cadPaciente == "S") { string mensagem = criarResultadoParaProntuario(id,"S",cod_etiqueta); enviarParaCliente(mensagem); } else { if (jaFezBuscaEmCadastroPaciente(id)==false) { armazenarNaBusca(id,string(cod_exame)); string mensagem = criarBuscaParaCadastroPaciente(id); enviarParaCliente(mensagem); } } fecharJanelaRE(); } void limparCamposResultadoExame(int page){ if (page == 0) { w = glade_xml_get_widget(xmlJRE,"entryLeucocitos");

104

gtk_entry_set_text(GTK_ENTRY(w),""); w = glade_xml_get_widget(xmlJRE,"entryEritrocitos"); gtk_entry_set_text(GTK_ENTRY(w),""); w = glade_xml_get_widget(xmlJRE,"entryHematocitos"); gtk_entry_set_text(GTK_ENTRY(w),""); w = glade_xml_get_widget(xmlJRE,"entryHemoglobina"); gtk_entry_set_text(GTK_ENTRY(w),""); w = glade_xml_get_widget(xmlJRE,"entryColesterol"); gtk_entry_set_text(GTK_ENTRY(w),""); w = glade_xml_get_widget(xmlJRE,"entryGlicose"); gtk_entry_set_text(GTK_ENTRY(w),""); w = glade_xml_get_widget(xmlJRE,"entryCreatina"); gtk_entry_set_text(GTK_ENTRY(w),""); w = glade_xml_get_widget(xmlJRE,"entrySodio"); gtk_entry_set_text(GTK_ENTRY(w),""); w = glade_xml_get_widget(xmlJRE,"entryPotassio"); gtk_entry_set_text(GTK_ENTRY(w),""); w = glade_xml_get_widget(xmlJRE,"entryCalcio"); gtk_entry_set_text(GTK_ENTRY(w),""); w = glade_xml_get_widget(xmlJRE,"entryMagnesio"); gtk_entry_set_text(GTK_ENTRY(w),""); w = glade_xml_get_widget(xmlJRE,"entryFosforo"); gtk_entry_set_text(GTK_ENTRY(w),""); //desabilitar as tabs <> de tipoExame w = glade_xml_get_widget(xmlJRE,"hpanedHemograma"); gtk_widget_set(w,"visible",true); w = glade_xml_get_widget(xmlJRE,"hpanedUrina"); gtk_widget_set(w,"visible",false); w = glade_xml_get_widget(xmlJRE,"hpanedColesterol"); gtk_widget_set(w,"visible",false); }//if if (page==1) { w = glade_xml_get_widget(xmlJRE,"entryPH"); gtk_entry_set_text(GTK_ENTRY(w),""); w = glade_xml_get_widget(xmlJRE,"entryDensidade"); gtk_entry_set_text(GTK_ENTRY(w),""); w = glade_xml_get_widget(xmlJRE,"entryHemacias"); gtk_entry_set_text(GTK_ENTRY(w),""); w = glade_xml_get_widget(xmlJRE,"entryProteinas"); gtk_entry_set_text(GTK_ENTRY(w),""); w = glade_xml_get_widget(xmlJRE,"entryGlicoseUrina"); gtk_entry_set_text(GTK_ENTRY(w),""); w = glade_xml_get_widget(xmlJRE,"tvBacterioscopia"); //para limpar o textview GtkTextIter start, end; GtkTextBuffer *buffer= gtk_text_buffer_new(NULL); buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(w)); gtk_text_buffer_get_bounds(buffer, &start, &end); gtk_text_buffer_set_text(buffer,"", -1); gtk_text_view_set_buffer(GTK_TEXT_VIEW(w),buffer); //desabilitar as tabs <> de tipoExame w = glade_xml_get_widget(xmlJRE,"hpanedHemograma"); gtk_widget_set(w,"visible",false); w = glade_xml_get_widget(xmlJRE,"hpanedUrina"); gtk_widget_set(w,"visible",true);

105

w = glade_xml_get_widget(xmlJRE,"hpanedColesterol"); gtk_widget_set(w,"visible",false); }//if if (page==2) { w = glade_xml_get_widget(xmlJRE,"entryLDL"); gtk_entry_set_text(GTK_ENTRY(w),""); w = glade_xml_get_widget(xmlJRE,"entryHDL"); gtk_entry_set_text(GTK_ENTRY(w),""); w = glade_xml_get_widget(xmlJRE,"entryVLDL"); gtk_entry_set_text(GTK_ENTRY(w),""); //desabilitar as tabs <> de tipoExame w = glade_xml_get_widget(xmlJRE,"hpanedHemograma"); gtk_widget_set(w,"visible",false); w = glade_xml_get_widget(xmlJRE,"hpanedUrina"); gtk_widget_set(w,"visible",false); w = glade_xml_get_widget(xmlJRE,"hpanedColesterol"); gtk_widget_set(w,"visible",true); }//if } void preencherDadosResultadoHemograma(PGresult *res){ int leucocitos_fnum = PQfnumber(res, "leucocitos"); int eritrocitos_fnum = PQfnumber(res, "eritrocitos"); int hematocitos_fnum = PQfnumber(res, "hematocitos"); int hemoglobina_fnum = PQfnumber(res, "hemoglobina"); int colesterol_fnum = PQfnumber(res, "colesterol"); int glicose_fnum = PQfnumber(res, "glicose"); int creatina_fnum = PQfnumber(res, "creatina"); int sodio_fnum = PQfnumber(res, "sodio"); int potassio_fnum = PQfnumber(res, "potassio"); int calcio_fnum = PQfnumber(res, "calcio"); int magnesio_fnum = PQfnumber(res, "magnesio"); int fosforo_fnum = PQfnumber(res, "fosforo"); char *leucocitos, *eritrocitos, *hematocitos, *hemoglobina, *colesterol, *glicose, *creatina, *sodio,*potassio, *calcio, *magnesio, *fosforo; leucocitos = PQgetvalue(res, 0, leucocitos_fnum); eritrocitos = PQgetvalue(res, 0, eritrocitos_fnum); hematocitos = PQgetvalue(res, 0, hematocitos_fnum); hemoglobina = PQgetvalue(res, 0, hemoglobina_fnum); colesterol = PQgetvalue(res, 0, colesterol_fnum); glicose = PQgetvalue(res, 0, glicose_fnum); creatina = PQgetvalue(res, 0, creatina_fnum); sodio = PQgetvalue(res, 0, sodio_fnum); potassio = PQgetvalue(res, 0, potassio_fnum); calcio = PQgetvalue(res, 0, calcio_fnum); magnesio = PQgetvalue(res, 0, magnesio_fnum); fosforo = PQgetvalue(res, 0, fosforo_fnum); w = glade_xml_get_widget(xmlJRE,"entryLeucocitos"); gtk_entry_set_text(GTK_ENTRY(w),leucocitos); gtk_widget_set(w,"editable",false); w = glade_xml_get_widget(xmlJRE,"entryEritrocitos"); gtk_entry_set_text(GTK_ENTRY(w),eritrocitos); gtk_widget_set(w,"editable",false); w = glade_xml_get_widget(xmlJRE,"entryHematocitos"); gtk_entry_set_text(GTK_ENTRY(w),hematocitos);

106

gtk_widget_set(w,"editable",false); w = glade_xml_get_widget(xmlJRE,"entryHemoglobina"); gtk_entry_set_text(GTK_ENTRY(w),hemoglobina); gtk_widget_set(w,"editable",false); w = glade_xml_get_widget(xmlJRE,"entryColesterol"); gtk_entry_set_text(GTK_ENTRY(w),colesterol); gtk_widget_set(w,"editable",false); w = glade_xml_get_widget(xmlJRE,"entryGlicose"); gtk_entry_set_text(GTK_ENTRY(w),glicose); gtk_widget_set(w,"editable",false); w = glade_xml_get_widget(xmlJRE,"entryCreatina"); gtk_entry_set_text(GTK_ENTRY(w),creatina); gtk_widget_set(w,"editable",false); w = glade_xml_get_widget(xmlJRE,"entrySodio"); gtk_entry_set_text(GTK_ENTRY(w),sodio); gtk_widget_set(w,"editable",false); w = glade_xml_get_widget(xmlJRE,"entryPotassio"); gtk_entry_set_text(GTK_ENTRY(w),potassio); gtk_widget_set(w,"editable",false); w = glade_xml_get_widget(xmlJRE,"entryCalcio"); gtk_entry_set_text(GTK_ENTRY(w),calcio); gtk_widget_set(w,"editable",false); w = glade_xml_get_widget(xmlJRE,"entryMagnesio"); gtk_entry_set_text(GTK_ENTRY(w),magnesio); gtk_widget_set(w,"editable",false); w = glade_xml_get_widget(xmlJRE,"entryFosforo"); gtk_entry_set_text(GTK_ENTRY(w),fosforo); gtk_widget_set(w,"editable",false); } void preencherDadosResultadoUrina(PGresult *res){ int ph_fnum = PQfnumber(res, "ph"); int densidade_fnum = PQfnumber(res, "densidade"); int hemacias_fnum = PQfnumber(res, "hemacias"); int proteinas_fnum = PQfnumber(res, "proteinas"); int glicose_fnum = PQfnumber(res, "glicose"); int bacterioscopia_fnum = PQfnumber(res, "bacterioscopia"); char* ph,*densidade, *hemacias, *proteinas, *glicose, *bacterioscopia; ph = PQgetvalue(res, 0, ph_fnum); densidade = PQgetvalue(res, 0, densidade_fnum); hemacias = PQgetvalue(res, 0, hemacias_fnum); proteinas = PQgetvalue(res, 0, proteinas_fnum); glicose = PQgetvalue(res, 0, glicose_fnum); bacterioscopia = PQgetvalue(res, 0, bacterioscopia_fnum); w = glade_xml_get_widget(xmlJRE,"entryPH"); gtk_entry_set_text(GTK_ENTRY(w),ph); gtk_widget_set(w,"editable",false); w = glade_xml_get_widget(xmlJRE,"entryDensidade"); gtk_entry_set_text(GTK_ENTRY(w),densidade); gtk_widget_set(w,"editable",false); w = glade_xml_get_widget(xmlJRE,"entryHemacias"); gtk_entry_set_text(GTK_ENTRY(w),hemacias); gtk_widget_set(w,"editable",false); w = glade_xml_get_widget(xmlJRE,"entryProteinas"); gtk_entry_set_text(GTK_ENTRY(w),proteinas); gtk_widget_set(w,"editable",false);

107

w = glade_xml_get_widget(xmlJRE,"entryGlicoseUrina"); gtk_entry_set_text(GTK_ENTRY(w),glicose); gtk_widget_set(w,"editable",false); w = glade_xml_get_widget(xmlJRE,"tvBacterioscopia"); GtkTextBuffer *buffer= gtk_text_buffer_new(NULL); buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(w)); gtk_text_buffer_set_text(buffer,bacterioscopia, -1); gtk_text_view_set_buffer(GTK_TEXT_VIEW(w),buffer); gtk_widget_set(w,"editable",false); } void preencherDadosResultadoColesterol(PGresult *res){ int ldl_fnum = PQfnumber(res, "colesterol_ldl"); int hdl_fnum = PQfnumber(res, "colesterol_hdl"); int vldl_fnum = PQfnumber(res, "colesterol_vldl"); char *ldl,*hdl, *vldl; ldl = PQgetvalue(res, 0, ldl_fnum); hdl = PQgetvalue(res, 0, hdl_fnum); vldl = PQgetvalue(res, 0, vldl_fnum); w = glade_xml_get_widget(xmlJRE,"entryLDL"); gtk_entry_set_text(GTK_ENTRY(w),ldl); gtk_widget_set(w,"editable",false); w = glade_xml_get_widget(xmlJRE,"entryHDL"); gtk_entry_set_text(GTK_ENTRY(w),hdl); gtk_widget_set(w,"editable",false); w = glade_xml_get_widget(xmlJRE,"entryVLDL"); gtk_entry_set_text(GTK_ENTRY(w),vldl); gtk_widget_set(w,"editable",false); } void selecionarDadosResultado(){ PGresult *res; string sql="SELECT * FROM exame, resultado,tipo_exame WHERE id_etiqueta = '"+ (string)id_etiqueta_ResulExame+"' and id_etiqueta = cod_etiqueta and cod_tipo_exame = cod_exame"; res = PQexec(conn, sql.c_str()); if (PQresultStatus(res) != PGRES_TUPLES_OK) { fprintf(stderr, "Erro durante a seleçao de exameXresultado!\n", PQerrorMessage(conn)); PQclear(res); exit_nicely(); }//if if (PQntuples(res)>0) { int dtColeta_fnum = PQfnumber(res, "data_coleta"); int etiqueta_fnum = PQfnumber(res, "id_etiqueta"); int exame_fnum = PQfnumber(res, "nome_exame"); char* nome_exame,*id_etiqueta, *data_coleta; nome_exame = PQgetvalue(res, 0, exame_fnum); id_etiqueta = PQgetvalue(res, 0, etiqueta_fnum); data_coleta = PQgetvalue(res, 0, dtColeta_fnum); w = glade_xml_get_widget(xmlJRE,"entryTipoExameJRE"); gtk_entry_set_text(GTK_ENTRY(w),nome_exame); w = glade_xml_get_widget(xmlJRE,"entryCodEtiquetaJRE");

108

gtk_entry_set_text(GTK_ENTRY(w),id_etiqueta); w = glade_xml_get_widget(xmlJRE,"entryDataColetaJRE"); gtk_entry_set_text(GTK_ENTRY(w),data_coleta); string exame = nome_exame; /* verifica o tipo de exame do resultado e limpa os campos e habilita page do referente ao tipo de exame*/ if (exame == "Hemograma Completo") { limparCamposResultadoExame(0); preencherDadosResultadoHemograma(res); }//hemograma if(exame == "Urina") { limparCamposResultadoExame(1); preencherDadosResultadoUrina(res); }//urina if(exame == "Colesterol") { limparCamposResultadoExame(2); preencherDadosResultadoColesterol(res); }//colesterol }//if else { sql = "SELECT * FROM exame,tipo_exame where id_etiqueta = '"+( string)id_etiqueta_ResulExame+"' and cod_tipo_exame=cod_exame"; res = PQexec(conn, sql.c_str()); if (PQresultStatus(res) != PGRES_TUPLES_OK) { fprintf(stderr,"Erro durante seleçao exame ao compor novo resultado!\n", PQerrorMessage(conn)); PQclear(res); exit_nicely(); } //if int dtColeta_fnum = PQfnumber(res, "data_coleta"); int etiqueta_fnum = PQfnumber(res, "id_etiqueta"); int exame_fnum = PQfnumber(res, "nome_exame"); char* nome_exame,*id_etiqueta, *data_coleta; nome_exame = PQgetvalue(res, 0, exame_fnum); id_etiqueta = PQgetvalue(res, 0, etiqueta_fnum); data_coleta = PQgetvalue(res, 0, dtColeta_fnum); w = glade_xml_get_widget(xmlJRE,"entryTipoExameJRE"); gtk_entry_set_text(GTK_ENTRY(w),nome_exame); w = glade_xml_get_widget(xmlJRE,"entryCodEtiquetaJRE"); gtk_entry_set_text(GTK_ENTRY(w),id_etiqueta); w = glade_xml_get_widget(xmlJRE,"entryDataColetaJRE"); gtk_entry_set_text(GTK_ENTRY(w),data_coleta); string exame = nome_exame; if (exame == "Hemograma Completo") limparCamposResultadoExame(0); if (exame == "Urina") limparCamposResultadoExame(1); if (exame == "Colesterol") limparCamposResultadoExame(2); } //else

109

} void fecharJanelaRE(){ gtk_widget_hide(janelaResultadoExame); } void verResultadoExame(){ if ((id_etiqueta_ResulExame == " " )or(id_etiqueta_ResulExame == NULL)) { printf("Voce deve selecionar um exame para a visualização do resultado!\n"); }//if else { if (janelaResultadoExame == NULL) { xmlJRE = glade_xml_new("interface/interface.glade", "JanelaResultadoExame",NULL); w = glade_xml_get_widget (xmlJRE, "buttonSalvarResultado"); gtk_signal_connect(GTK_OBJECT(w),"clicked", GTK_SIGNAL_FUNC(salvarResultadoExame), NULL); janelaResultadoExame = glade_xml_get_widget(xmlJRE, "JanelaResultadoExame"); w = glade_xml_get_widget (xmlJRE, "buttonSairResultadoExame"); gtk_signal_connect(GTK_OBJECT(w),"clicked", GTK_SIGNAL_FUNC(fecharJanelaRE),NULL); gtk_signal_connect(GTK_OBJECT(janelaResultadoExame),"destroy", GTK_SIGNAL_FUNC(fecharJanela),janelaResultadoExame); }//if selecionarDadosResultado(); gtk_widget_show(janelaResultadoExame); }//else } void selecionaDadosTabelaExame(GtkWidget *clist, gint row, gint column, GdkEventButton *event, gpointer data){ gtk_clist_get_text(GTK_CLIST(clist), row, 0, &id_etiqueta_ResulExame); } void buscarExamesCadastrados(){ GtkWidget* tabela = glade_xml_get_widget (xmlJP, "tabelaExames"); gtk_clist_clear(GTK_CLIST(tabela)); ; if (conn == NULL) conectarBanco(); PGresult *res; w = glade_xml_get_widget(xmlJP,"entryIdInternoBusca"); string idInterno = gtk_entry_get_text(GTK_ENTRY(w)); string sql = "SELECT id_etiqueta, data_coleta,nome_exame,urgencia FROM exame, tipo_exame WHERE id_paciente_interno = '"+idInterno+"' and cod_tipo_exame = cod_exame"; res = PQexec(conn, sql.c_str()); if (PQresultStatus(res) != PGRES_TUPLES_OK) { fprintf(stderr, "Erro durante a seleçao de exameXtipo_exame!\n", PQerrorMessage(conn)); PQclear(res); exit_nicely(); }//if

110

int etiqueta_fnum = PQfnumber(res, "id_etiqueta"); int coleta_fnum = PQfnumber(res, "data_coleta"); int exame_fnum = PQfnumber(res, "nome_exame"); int urgencia_fnum = PQfnumber(res, "urgencia"); char *id_etiqueta, *data_coleta, *nome_exame, *urgencia; int linha = PQntuples(res); if (linha > 0) { gchar* dados[linha][4]; for (int i = 0; i < linha;i++) { id_etiqueta = PQgetvalue(res, i, etiqueta_fnum); data_coleta = PQgetvalue(res, i, coleta_fnum); nome_exame = PQgetvalue(res, i, exame_fnum); urgencia = PQgetvalue(res, i, urgencia_fnum); dados[i][0] = id_etiqueta; dados[i][1]= data_coleta; dados[i][2] = nome_exame; dados[i][3]= urgencia; gint row = gtk_clist_append( GTK_CLIST (tabela), dados[i]); }//for }//if else { printf("Nenhum exame foi cadastrado para este paciente\n"); }//else } void alteraEnabledBotoes(GtkNotebook *notebook, GtkNotebookPage *page, gint page_num, gpointer user_data){ if (page_num == 0) { w = glade_xml_get_widget(xmlJP,"buttonNovo"); gtk_widget_set(w,"sensitive",false); w = glade_xml_get_widget(xmlJP,"buttonBuscar"); gtk_widget_set(w,"sensitive",true); }//if if (page_num==1) { w = glade_xml_get_widget(xmlJP,"buttonNovo"); gtk_widget_set(w,"sensitive",true); w = glade_xml_get_widget(xmlJP,"buttonBuscar"); gtk_widget_set(w,"sensitive",false); }//if if(page_num==2) { w = glade_xml_get_widget(xmlJP,"buttonNovo"); gtk_widget_set(w,"sensitive",true); w = glade_xml_get_widget(xmlJP,"buttonBuscar"); gtk_widget_set(w,"sensitive",true); } } static gboolean buscarDadosPaciente(){ w = glade_xml_get_widget(xmlJP,"entryIDInterno"); string idInterno = gtk_entry_get_text(GTK_ENTRY(w));

111

if (conn == NULL) conectarBanco(); PGresult *res; string sql = "SELECT nome_completo,sexo,data_nascimento,tem_cad_paciente FROM paciente WHERE id_paciente_interno = '"+idInterno+"'"; res = PQexec(conn, sql.c_str()); if (PQresultStatus(res) != PGRES_TUPLES_OK) { fprintf(stderr, "Erro durante a seleçao dos dados da tabela exames!\n", PQerrorMessage(conn)); PQclear(res); exit_nicely(); }//if if (PQntuples(res)>0) { int nome_completo_fnum = PQfnumber(res, "nome_completo"); int sexo_fnum = PQfnumber(res, "sexo"); int data_nascimento_fnum = PQfnumber(res, "data_nascimento"); int tem_cad_paciente_fnum = PQfnumber(res, "tem_cad_paciente"); char *nome_completo, *sexo, *data_nascimento; nome_completo = PQgetvalue(res, 0, nome_completo_fnum); sexo = PQgetvalue(res, 0, sexo_fnum); data_nascimento = PQgetvalue(res, 0, data_nascimento_fnum); tem_cad_paciente = PQgetvalue(res, 0, tem_cad_paciente_fnum); w = glade_xml_get_widget(xmlJP,"entryNome"); gtk_entry_set_text(GTK_ENTRY(w),nome_completo); GtkComboBox *combo = GTK_COMBO_BOX (glade_xml_get_widget(xmlJP,"cbSexo")); if (sexo == "F") { gtk_combo_box_set_active (GTK_COMBO_BOX (combo),0); }//if else { gtk_combo_box_set_active (GTK_COMBO_BOX (combo),1); }//else string token = strtok(data_nascimento,"/"); w = glade_xml_get_widget(xmlJP,"entryDiaN"); gtk_entry_set_text(GTK_ENTRY(w),token.c_str()); token = strtok(NULL,"/"); w = glade_xml_get_widget(xmlJP,"entryMesN"); gtk_entry_set_text(GTK_ENTRY(w),token.c_str()); token = strtok(NULL," "); w = glade_xml_get_widget(xmlJP,"entryAnoN"); gtk_entry_set_text(GTK_ENTRY(w),token.c_str()); token = strtok(NULL,":"); w = glade_xml_get_widget(xmlJP,"entryHoraN"); gtk_entry_set_text(GTK_ENTRY(w),token.c_str()); token = strtok(NULL," "); w = glade_xml_get_widget(xmlJP,"entryMinN"); gtk_entry_set_text(GTK_ENTRY(w),token.c_str()); }//if return FALSE; } void consultaExame(){ if (conn == NULL)

112

conectarBanco(); w = glade_xml_get_widget(xmlJCE,"entryConsultaExame"); string exame = gtk_entry_get_text(GTK_ENTRY(w)); PGresult* res = selectTipoExame(exame); colocaDadosTabelaTipoExame(res); } void fecharJanela(GtkWidget* janela){ gtk_widget_hide(janela); } void conectarBanco(){ conn = PQsetdbLogin("localhost", "5432", NULL, NULL, "CadastroExame", "postgres", "phigres*"); if (PQstatus(conn) != CONNECTION_OK) { fprintf(stderr, "Conexao com database falhou: %s",PQerrorMessage(conn)); exit_nicely(); } } PGresult* selectTipoExame(string tipoExame){ PGresult *res; string sql = "SELECT * FROM tipo_exame WHERE nome_exame = '"+ tipoExame+"' or nome_exame like '%"+ tipoExame+"%' or nome_exame like '%"+ tipoExame+"' or nome_exame like '"+tipoExame+"%'"; res = PQexec(conn, sql.c_str()); if (PQresultStatus(res) != PGRES_TUPLES_OK) { fprintf(stderr, "Erro durante a seleçao de nome_exame!\n", PQerrorMessage(conn)); PQclear(res); exit_nicely(); } return res; } void colocaDadosTabelaTipoExame(PGresult* res){ int cod_exame = PQfnumber(res, "cod_exame"); int nome_exame = PQfnumber(res, "nome_exame"); char *codExame, *nomeExame; int linha = PQntuples(res); gchar* dados[linha][2]; for (int i = 0; i < linha;i++) { codExame = PQgetvalue(res, i, cod_exame); nomeExame = PQgetvalue(res, i, nome_exame); dados[i][0] = codExame; dados[i][1]= nomeExame; w = glade_xml_get_widget (xmlJCE, "tabelaTipoExame");

113

gint row = gtk_clist_append( GTK_CLIST (w), dados[i]); }//for } void selecionaCodTabelaTipoExame(GtkWidget *clist, gint row, gint column, GdkEventButton *event, gpointer data){ gchar *text; gtk_clist_get_text(GTK_CLIST(clist), row, 0, &text); w = glade_xml_get_widget(xmlJP,"entryExame"); gtk_entry_set_text(GTK_ENTRY(w),text); fecharJanela(janelaConsultaExame); } void buscarExame(){ w = glade_xml_get_widget(xmlJP,"notebook1"); gtk_notebook_set_current_page (GTK_NOTEBOOK(w),1); } void buscarTipoExame(){ if (janelaConsultaExame == NULL) { xmlJCE = glade_xml_new("interface/interface.glade","JanelaConsultaExame", NULL); w = glade_xml_get_widget (xmlJCE, "buttonConsultaExame"); gtk_signal_connect(GTK_OBJECT(w),"clicked",GTK_SIGNAL_FUNC(consultaExame), NULL); w = glade_xml_get_widget (xmlJCE, "buttonSairConsultaExame"); gtk_signal_connect(GTK_OBJECT(w),"clicked",GTK_SIGNAL_FUNC(fecharJanela), janelaConsultaExame); w = glade_xml_get_widget (xmlJCE, "tabelaTipoExame"); gtk_signal_connect(GTK_OBJECT(w),"select_row", GTK_SIGNAL_FUNC(selecionaCodTabelaTipoExame), NULL); janelaConsultaExame = glade_xml_get_widget(xmlJCE,"JanelaConsultaExame"); gtk_signal_connect(GTK_OBJECT(janelaConsultaExame),"destroy", GTK_SIGNAL_FUNC(fecharJanela),janelaConsultaExame); }//if else { w = glade_xml_get_widget(xmlJCE,"entryConsultaExame"); gtk_entry_set_text(GTK_ENTRY(w),""); w = glade_xml_get_widget (xmlJCE, "tabelaTipoExame"); gtk_clist_clear(GTK_CLIST(w)); }//else gtk_widget_show(janelaConsultaExame); } void novoExame(){ w = glade_xml_get_widget(xmlJP,"notebook1"); gtk_notebook_set_current_page (GTK_NOTEBOOK(w),0); } string formatarData(){ w = glade_xml_get_widget(xmlJP,"entryDiaN"); string diaN = gtk_entry_get_text(GTK_ENTRY(w)); w = glade_xml_get_widget(xmlJP,"entryMesN");

114

string mesN = gtk_entry_get_text(GTK_ENTRY(w)); w = glade_xml_get_widget(xmlJP,"entryAnoN"); string anoN = gtk_entry_get_text(GTK_ENTRY(w)); w = glade_xml_get_widget(xmlJP,"entryHoraN"); string horaN = gtk_entry_get_text(GTK_ENTRY(w)); w = glade_xml_get_widget(xmlJP,"entryMinN"); string minN = gtk_entry_get_text(GTK_ENTRY(w)); string data = diaN+"/"+mesN+"/"+anoN+" "+horaN+":"+minN+" "; return data; } void inserirDadosTabelaPaciente(string id_interno,string nome, string data_nascimento,string sexo, string tem_cadastro){ if (conn == NULL) conectarBanco(); PGresult *res; string sql; sql = "Insert into paciente (id_paciente_interno,nome_completo,sexo,data_nascimento,tem_cad_paciente) VALUES ('"+id_interno+"','"+nome+"','"+sexo+"','"+data_nascimento+"','"+tem_cadastro+"')"; res = PQexec(conn, sql.c_str()); if (PQresultStatus(res) == PGRES_FATAL_ERROR) { fprintf(stderr, "Erro durante a inserção dos dados na tabela paciente!\n", PQerrorMessage(conn)); PQclear(res); exit_nicely(); }//if } void inserirDadosTabelaExame(){ PGresult *res; string sql; w = glade_xml_get_widget(xmlJP,"entryIDInterno"); string id_interno = gtk_entry_get_text(GTK_ENTRY(w)); w = glade_xml_get_widget(xmlJP,"entryDataColeta"); string data_coleta = gtk_entry_get_text(GTK_ENTRY(w)); w = glade_xml_get_widget(xmlJP,"entryExame"); string cod_exame = gtk_entry_get_text(GTK_ENTRY(w)); GtkComboBox *combo=GTK_COMBO_BOX (glade_xml_get_widget(xmlJP,"cbUrgencia")); string urgencia; int n = gtk_combo_box_get_active (GTK_COMBO_BOX (combo)); if (n==0) urgencia = "S"; if (n==1) urgencia = "N"; sql = "Insert into exame (id_paciente_interno,cod_tipo_exame,urgencia,data_coleta) VALUES('"+id_interno+"','"+cod_exame+"','"+urgencia+"','"+data_coleta+"')"; res = PQexec(conn, sql.c_str()); if (PQresultStatus(res) == PGRES_FATAL_ERROR) { fprintf(stderr, "Erro durante a inserção dos dados na tabela exame!\n", PQerrorMessage(conn)); PQclear(res); exit_nicely(); }//if

115

} void limparCamposCadastro(){ w = glade_xml_get_widget(xmlJP,"entryIDInterno"); gtk_entry_set_text(GTK_ENTRY(w),""); w = glade_xml_get_widget(xmlJP,"entryEtiqueta"); gtk_entry_set_text(GTK_ENTRY(w),""); w = glade_xml_get_widget(xmlJP,"entryDataColeta"); gtk_entry_set_text(GTK_ENTRY(w),""); w = glade_xml_get_widget(xmlJP,"entryExame"); gtk_entry_set_text(GTK_ENTRY(w),""); w = glade_xml_get_widget(xmlJP,"entryNome"); gtk_entry_set_text(GTK_ENTRY(w),""); w = glade_xml_get_widget(xmlJP,"entryDiaN"); gtk_entry_set_text(GTK_ENTRY(w),""); w = glade_xml_get_widget(xmlJP,"entryMesN"); gtk_entry_set_text(GTK_ENTRY(w),""); w = glade_xml_get_widget(xmlJP,"entryAnoN"); gtk_entry_set_text(GTK_ENTRY(w),""); w = glade_xml_get_widget(xmlJP,"entryHoraN"); gtk_entry_set_text(GTK_ENTRY(w),""); w = glade_xml_get_widget(xmlJP,"entryMinN"); gtk_entry_set_text(GTK_ENTRY(w),""); GtkComboBox *combo = GTK_COMBO_BOX (glade_xml_get_widget(xmlJP,"cbSexo")); gtk_combo_box_set_active (GTK_COMBO_BOX (combo),-1); combo = GTK_COMBO_BOX (glade_xml_get_widget(xmlJP,"cbUrgencia")); gtk_combo_box_set_active (GTK_COMBO_BOX (combo),-1); } void salvarExame(){ if (conn == NULL) conectarBanco(); if ((tem_cad_paciente == NULL) or (tem_cad_paciente==" ")) { w = glade_xml_get_widget(xmlJP,"entryIDInterno"); string id_interno = gtk_entry_get_text(GTK_ENTRY(w)); w = glade_xml_get_widget(xmlJP,"entryNome"); string nome = gtk_entry_get_text(GTK_ENTRY(w)); string data_nascimento = formatarData(); string sexo; GtkComboBox *combo = GTK_COMBO_BOX (glade_xml_get_widget(xmlJP,"cbSexo")); int n = gtk_combo_box_get_active (GTK_COMBO_BOX (combo)); if (n==0) sexo = "F"; if (n==1) sexo = "M"; inserirDadosTabelaPaciente(id_interno,nome,data_nascimento,sexo,"N"); inserirDadosTabelaExame(); }//if else { inserirDadosTabelaExame(); tem_cad_paciente=" "; }//else limparCamposCadastro(); }

116

void sair() { gtk_main_quit(); //Encerra o loop principal do GTK } ----------------------Classe MainInterface.h (Aplicação Gerência de Exames)------------------- #include <glade/glade.h> // Carrega os recursos do Glade #include <gtk/gtk.h> //Carrega os recursos do GTK #include <libpq-fe.h> #ifndef unix #include <stdlib.h> #include <string> #include <winsock2.h> #endif #ifdef unix #include <ctype.h> // for isdigit #include <sys/types.h> // for connect(), bind(), accept(), #include <sys/socket.h> // for connect(), listen(), bind() accept(), #include <netinet/in.h> // for ntons(), htonl(), etc... #include <arpa/inet.h> // for inet_addre() #include <unistd.h> // for close(), read(), write() #include <netdb.h> // for gethostbyname #include <sys/time.h> // for timeval struct, and select() #include <string.h> // for memset() #include <map> // for STL map class (Reference counting) #endif //GladeXML * xml; //Cria um ponteiro para uma estrutura GladeXML using std::string; extern "C" { //Fechar aplicação void sair(); //encerra conexão com banco de dados e a aplicação void exit_nicely(); //habilita a aba referente a busca de exames cadastrados void buscarExame(); /*inicializa a janelaConsultaExame para a busca do código referente a um determinado tipo de exame*/ void buscarTipoExame(); //habilita a aba refente a inclusão de um novo exame void novoExame(); //armazena os dados referentes a inclusão de um exame void salvarExame(); //busca os tipos de exames registrados void consultaExame(); //fecha a janela ConsultaExame void fecharJanela(GtkWidget* janela); //faz a conexão com o database void conectarBanco();

117

//retorna resultado da seleção dos tipos de exames PGresult* selectTipoExame(string tipoExame); //armazena o resultado da seleção dos tipoos de exames em uma tabela void colocaDadosTabelaTipoExame(PGresult* res); //Obtem-se o texto armazenado na celula cliclada. void selecionaCodTabelaTipoExame(GtkWidget *clist, gint row, gint column, GdkEventButton *event, gpointer data); /*retorna dados do paciente se o seu id_interno estiver cadastrado, evento referente a saída do campo edit(entryIdInterno)*/ static gboolean buscarDadosPaciente(); /*formata a data de nascimento do paciente para ser armazenada na base de dados*/ string formatarData(); //insere novo paciente em sua base de dados void inserirDadosTabelaPaciente(string id_interno,string nome, string dataNascimento,string sexo, string tem_cadastro); //insere novo exame em sua base de dados void inserirDadosTabelaExame(); //limpar campos referentes a aba de novos registros de exames void limparCamposCadastro(); /*habilita e desabilita botões quando os pages do notebook da janelaPrincipal são selecionadas*/ void alteraEnabledBotoes(GtkNotebook *notebook,GtkNotebookPage *page, gint page_num, gpointer user_data); //retorna os exames cadastrados para um determinado paciente void buscarExamesCadastrados(); /*seta a variavel id_etiqueta_ResulExame com o valor referente ao id_exame da linha selecionada na tabela da janelaResultadoExame*/ void selecionaDadosTabelaExame(GtkWidget *clist, gint row, gint column, GdkEventButton *event, gpointer data); //inicializa a janela referente a Resultado de exames void verResultadoExame(); //armazena os dados referentes a resultado de um determinado exame void salvarResultadoExame(); //encerrar a execução da janelaCOnsultaExame void sairConsultaExame(); /*limpa os edits referentes a um determinado exame(page) na janela ResultadoExame */ void limparCamposResultadoExame(int page); /*seleciona dados(data_coleta, etiqueta_exame e nome_exame) referentes a um determinado exame para que sejam visualizados na janela ResultadoExame*/ void selecionarDadosResultado(); //encerra a execução da janelaResultadoExame void fecharJanelaRE(); /*visualiza os dados na janelaResultadoExame de um exame de hemograma registrado na base de dados*/ void preencherDadosResultadoHemograma(PGresult *res); /*visualiza os dados na janelaResultadoExame de um exame de urina registrado na base de dados*/ void preencherDadosResultadoUrina(PGresult *res); /*visualiza os dados na janelaResultadoExame de um exame de colesterol registrado na base de dados*/ void preencherDadosResultadoColesterol(PGresult *res); //recebe as mensagens que foram enviadas pelo cliente void *receberMensagem(void *s);

118

//aguarda envio de mensagens do cliente void *ouvirCliente(void* i); /*Metodo chamado qdo a aplicação recebe uma mensagem do tipo ADT;verifica se paciente já se encontra registrado na sua base de dados*/ bool pacienteJaTemCadastro(string id_paciente); //retorna o endereço IP da máquina local char *getEndIPLocal(); //efetua update na tabela Paciente void updatePaciente(string id_paciente, string flag); /*gera string contendo resultado de um determinado exame para ser enviado posteriormente ao cliente, este por vez gera a mesma mensagem em HL7 para ser enviada ao servidor que a encaminha ao aplicativo ProntuarioEletronico*/ string criarResultadoParaProntuario(string id_paciente,string flag, string cod_exame); /*gera string contendo busca de um determinado paciente para ser enviado posteriormente ao cliente, este por vez gera a mesma mensagem em HL7 para ser enviada ao servidor que a encaminha ao aplicativo cadastroPaciente*/ string criarBuscaParaCadastroPaciente(string id_paciente); //estabelece conexão com o cliente via socket void enviarParaCliente(string mensagem); /*envia mensagem(string) ao cliente quando o aplicativo estiver rodando em sistema operacional Windows*/ void enviarMensagem(SOCKET s, string msg); /*envia mensagem(string) ao cliente quando o aplicativo estiver rodando em sistema operacional Unix*/ void enviarMensagemUnix(int s, string msg); /*verifica se aplicativo já enviou uma string de busca para o aplicativo Cadastopciente*/ bool jaFezBuscaEmCadastroPaciente(string id_paciente); //armazena dados refentes a busca no aplicativo cadastroPaciente void armazenarNaBusca(string id,string cod_exame); //exclui dados referentes a busca em cadastroPaciente void excluirDaBusca(string id_paciente); //formata data_nascimento recebida de uma mensagem do tipo ADT (inclui "/") string alterarFormatoDataNascimento(string nascimento); } ----------------------------uCliente.pas (Aplicação Cadastro de Pacientes)------------------------- unit uCliente; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Grids, ComCtrls,ImgList, ToolWin, IdComponent,Spin, ExtCtrls, Buttons, IdTCPConnection, IdTCPClient, IdBaseComponent, jpeg, xmldom, XMLIntf, msxmldom, XMLDoc, DB, DBClient, MConnect, SConnect, ScktComp, Mask, DBCtrls, DBTables, UDataModulo, FMTBcd, SqlExpr, Provider, ADODB, Sockets, IdTCPServer; type private public

119

procedure inicialize; procedure RecebeMensagem(msg:String); function PreencheMensagemCadastroPaciente:String; procedure PreencheFormulario; procedure SalvarNoBanco; function IdentificaSexo(i:integer):string; function IdentificaEstadoCivil(i:integer):string; function IdentificaGrupoEtnico(i:integer):string; function IdentificaRaca(i:integer):string; function IdentificaReligiao(i:integer):string; function extrairToken(BaseString, BreakString: string; StringList: TStringList): TStringList; procedure limparCamposRecebimento; procedure salvardadosRecebidos(t: TStringList); procedure fazerConsulta(tabela, campo:string;var nome,nascimento,id,sexo, resultado:string); function preencherMensagemRespostaConsulta(nome,nascimento,sexo,id, resultado,destino, idResposta:string):string; function acrescentarDigito(valor: string):string; end; TClientDataThread = class(TThread) private public ListBuffer :TStringList; TargetList :TStrings; procedure synchAddDataToControl; constructor Create(CreateSuspended: Boolean); procedure Execute; override; procedure Terminate; end; var Form1: TForm1; mensagemEnvio:string; implementation uses IdSocketHandle; // Aqui a classe IdSocketHandle é definida {$R *.dfm} //------------- TClientDataThread impl ------------- constructor TClientDataThread.Create(CreateSuspended: Boolean); begin inherited Create(CreateSuspended); FreeOnTerminate := true; ListBuffer := TStringList.Create; end; procedure TClientDataThread.Terminate; begin ListBuffer.Free; inherited; end;

120

procedure TClientDataThread.Execute; begin Synchronize(synchAddDataToControl); end; procedure TClientDataThread.synchAddDataToControl; begin TargetList.AddStrings(ListBuffer); end; //------------- end TClientDataThread impl -------- procedure TForm1.fazerConsulta(tabela,campo:string; var nome,nascimento,id,sexo, resultado:string); begin if (self.QueryConsulta.Active) then self.queryConsulta.Active:=false; self.QueryConsulta.CommandText:='Select * from paciente where patient_id_internal = '+quotedStr(campo); self.QueryConsulta.Active:=true; if self.QueryConsulta.RecordCount = 0 then resultado:='NF' else resultado:='OK'; nome:= self.queryConsulta.fieldByName('nome_completo').AsString; nascimento:= self.QueryConsulta.fieldByName('data_nascimento').AsString; sexo:= self.QueryConsulta.fieldByName('sexo').AsString; id:= self.QueryConsulta.fieldByName('patient_id_internal').AsString; end; function TForm1.preencherMensagemRespostaConsulta(nome,nascimento,sexo,id, resultado,destino,idResposta:string):string; begin result:= 'CadastroPaciente|'+ 'CadastroPaciente-Resposta|'+ destino+' '+'|'+ idResposta+' '+'|'+ resultado+' '+'|'+ ' '+'|'+ ' '+'|'+ id+' '+'|'+ ' '+'|'+ nome+' '+'|'+ ' '+'|'+ nascimento+' '+'|'+ sexo+' '+'|'+ ' '+'|'+ ' '+'|'+ ' '+'|'+ ' '+'|'+ ' '+'|'+ ' '+'|'+ ' '+'|'+ ' '+'|'+ ' '+'|'+ ' '+'|'+

121

' '+'|'+ ' '+'|'+ ' '+'|'+ ' '+'|'+ ' '+'|'+ ' '+'|'+ ' '+'|'+ ' '+'|'+ ' '+'|'+ ' '+'|'+ ' '+'|'; end; procedure TForm1.RecebeMensagem(msg: String); var t: TStringList; msgResposta,nome,sexo,id,nascimento,resultad:string; begin limparCamposRecebimento; t := TStringList.create; t:= extrairToken(msg,'|',t); self.idmensagem.Text:=t[0]; self.tipoMensagem.Text:=t[1]; self.dataMensagem.Text:=t[2]; self.remetente.Text:=t[3]; if (trim(t[1])='ACK')then//se recebeu mensagem de confirmação... begin self.confirmacao.Text:=t[4]; self.idConfirmacao.Text:=t[5]; showmessage('Confirmação recebida!'); end else if (trim(t[1])='RQP') then begin self.fazerConsulta(t[5],t[4],nome,nascimento,id,sexo,resultad); msgResposta:=preencherMensagemRespostaConsulta(nome,nascimento,sexo,id, resultad,t[3],t[6]); if not(ClienteSocket.Active) then ClienteSocket.Active:=true; ClienteSocket.Sendln(msgResposta); ClienteSocket.Active:=false; end; t.Clear; t:= extrairToken(msg,'̈',t); t:= extrairToken(msg,'̈',t); self.MsgsRecebidas.Lines.Append(t[1]); self.MsgsRecebidas.Lines.Append('************************'); end; procedure TForm1.salvarDadosRecebidos(t: TStringList); begin self.ADODataSet1.FieldByName('patient_id_internal').AsString:= t[8]; self.ADODataSet1.FieldByName('nome_completo').AsString:= t[9]; self.ADODataSet1.FieldByName('data_nascimento').AsString:= t[10]; self.ADODataSet1.FieldByName('sexo').AsString:= t[11]; self.ADODataSet1.FieldByName('patient_address').AsString:= t[12];

122

self.ADODataSet1.FieldByName('phone_number_home').AsString:= t[13]; self.ADODataSet1.FieldByName('phone_number_business').AsString:= t[14]; self.ADODataSet1.FieldByName('patient_account_number').AsString:= t[15]; self.ADODataSet1.Post; self.ADODataSet1.Insert; end; function TForm1.extrairToken(BaseString, BreakString: string; StringList: TStringList): TStringList; var EndOfCurrentString: byte; begin repeat EndOfCurrentString := Pos(BreakString, BaseString); if EndOfCurrentString = 0 then StringList.add(BaseString) else StringList.add(Copy(BaseString, 1, EndOfCurrentString - 1)); BaseString := Copy(BaseString, EndOfCurrentString + length(BreakString), length(BaseString) - EndOfCurrentString); until EndOfCurrentString = 0; result := StringList; end; procedure TForm1.sbSalvarClick(Sender: TObject); begin mensagemEnvio:= PreencheMensagemCadastroPaciente; if not(ClienteSocket.Active) then ClienteSocket.Active:=true; ClienteSocket.Sendln(self.PreencheMensagemCadastroPaciente); ClienteSocket.Active:=false; SalvarNoBanco; inicialize; end; function TForm1.PreencheMensagemCadastroPaciente:String; var diaNasc,mesNasc,horaNasc,minNasc,diaM,mesM,horaM,minM: string; begin diaNasc:= self.acrescentarDigito(mesN.Text); mesNasc:= self.acrescentarDigito(mesN.Text); horaNasc:= self.acrescentarDigito(horaN.Text); minNasc:= self.acrescentarDigito(minN.Text); diaM:= self.acrescentarDigito(mesF.Text); mesM:= self.acrescentarDigito(mesF.Text); horaM:= self.acrescentarDigito(horaF.Text); minM:= self.acrescentarDigito(minF.Text); result:= 'CadastroPaciente|'+ 'CadastroPaciente-Inclusao|'+ Set_ID.Text+' '+'|'+ Patient_ID_External.Text+' '+'|'+ Patient_ID_Internal.Text+' '+'|'+ Alternate_Patient_ID.Text+' '+'|'+

123

Sobrenome.Text+'̂'+PrimeiroNome.Text+'̂'+nomeMeio.Text+'̂'+ Sufixo.Text+'̂'+Prefixo.Text+' '+'|'+ Mother_Maiden_Name.Text+' '+'|'+ anoN.Text+mesNasc+diaNasc+horaNasc+minNasc+' '+'|'+ IdentificaSexo(cbSexo.ItemIndex)+' '+'|'+ Patient_Alias.Text+' '+'|'+ cbRaca.Text+' '+'|'+ Patient_Address.Text+' '+'|'+ Phone_Number_Home.Text+' '+'|'+ Phone_Number_Business.Text+' '+'|'+ Primary_Language.Text+' '+'|'+ cbEstadoCivil.Text+' '+'|'+ cbReligiao.Text+' '+'|'+ Patient_Account_Number.Text+' '+'|'+ SSN_Number.Text+' '+'|'+ CNH1.Text+'̂'+CNH2.Text+'̂'+CNH3.Text+' '+'|'+ Mother_Identifier.Text+' '+'|'+ cbGrupoEtnico.Text+' '+'|'+ Birth_Place.Text+' '+'|'+ Multiple_Birth_Indicator.Text+' '+'|'+ Birth_Order.Text+' '+'|'+ Citizenship.Text+' '+'|'+ Veterans_Military_Status.Text+' '+'|'+ Nationality.Text+' '+'|'+ anoF.Text+mesM+diaM+horaM+minM+' '+'|'+ Patient_Death_Indicator.Text+' '+'|'; end; procedure TForm1.FormCreate(Sender: TObject); begin self.ServidorSocket.Active:=true; end; procedure TForm1.ServidorSocketAccept(Sender: TObject; ClientSocket: TCustomIpClient); var msg:string; DataThread: TClientDataThread; begin DataThread:= TClientDataThread.Create(true); msg:= ClientSocket.Receiveln; if msg<>'' then RecebeMensagem(msg); DataThread.Resume; end; end. ----------------------------prontuario.pas (Aplicação Promtuario Eletronico)---------------------- unit prontuario; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, DB, ADODB, DBTables, ScktComp, StdCtrls, ComCtrls, DBCtrls, Menus, Sockets, Grids, DBGrids, IdHL7, IdBaseComponent, IdComponent, IdTCPServer, IdFingerServer, jpeg;

124

type TForm1 = class(TForm) function extrairToken(BaseString, BreakString: string; StringList: TStringList): TStringList; procedure RecebeMensagem(msg: String); procedure salvarNovoCadastroPaciente(t: TStringList); procedure atualizarProntuarioPaciente(t: TStringList); procedure ServidorSocketAccept(Sender: TObject; ClientSocket: TCustomIpClient); procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } end; TClientDataThread = class(TThread) private public ListBuffer :TStringList; TargetList :TStrings; procedure synchAddDataToControl; constructor Create(CreateSuspended: Boolean); procedure Execute; override; procedure Terminate; end; var Form1: TForm1; implementation uses IdSocketHandle; // This is where the IdSocketHandle class is defined. {$R *.dfm} //------------- TClientDataThread impl ------------- constructor TClientDataThread.Create(CreateSuspended: Boolean); begin inherited Create(CreateSuspended); FreeOnTerminate := true; ListBuffer := TStringList.Create; end; procedure TClientDataThread.Terminate; begin ListBuffer.Free; inherited; end; procedure TClientDataThread.Execute; begin Synchronize(synchAddDataToControl); end; procedure TClientDataThread.synchAddDataToControl; begin TargetList.AddStrings(ListBuffer);

125

end; //------------- end TClientDataThread impl ------------- procedure TForm1.RecebeMensagem(msg: String); var t: TStringList; begin t := TStringList.create; t:= extrairToken(msg,'|',t); if (trim(t[1])='ACK')then //se recebeu mensagem de confirmação... trim tira os espaços em branco begin showmessage('Confirmação recebida!'); end else if (trim(t[1])='PIN') then begin atualizarProntuarioPaciente(t); end else if (trim(t[1])='ADT') then salvarNovoCadastroPaciente(t); t.Clear; //t:= extrairToken(msg,'̈',t); end; procedure TForm1.salvarNovoCadastroPaciente(t: TStringList); var cnh : string; begin if (t[22]=' ^ ^ ') then cnh := ''; //inserir na tabela criada self.ADODataSet1.Insert; self.ADODataSet1.FieldByName('patient_id_internal').AsString:= t[4]; self.ADODataSet1.FieldByName('nome_completo').AsString:= t[5]; self.ADODataSet1.FieldByName('data_nascimento').AsString:= t[6]; self.ADODataSet1.FieldByName('sexo').AsString:= t[7]; self.ADODataSet1.FieldByName('patient_address').AsString:= t[8]; self.ADODataSet1.FieldByName('phone_number_home').AsString:= t[9]; self.ADODataSet1.FieldByName('phone_number_business').AsString:= t[10]; self.ADODataSet1.FieldByName('patient_account_number').AsString:= t[11]; self.ADODataSet1.FieldByName('id').AsString:= t[12]; self.ADODataSet1.FieldByName('patient_id_external').AsString:= t[13]; self.ADODataSet1.FieldByName('alternate_patient_id').AsString:= t[14]; self.ADODataSet1.FieldByName('mother_maiden_name').AsString:= t[15]; self.ADODataSet1.FieldByName('patient_alias').AsString:= t[16]; self.ADODataSet1.FieldByName('raca').AsString:= t[17]; self.ADODataSet1.FieldByName('primary_language').AsString:= t[18]; self.ADODataSet1.FieldByName('estado_civil').AsString:= t[19]; self.ADODataSet1.FieldByName('religiao').AsString:= t[20]; self.ADODataSet1.FieldByName('ssn_number').AsString:= t[21]; self.ADODataSet1.FieldByName('cnh').AsString:= cnh; self.ADODataSet1.FieldByName('mother_identifier').AsString:= t[23]; self.ADODataSet1.FieldByName('grupo_etnico').AsString:= t[24]; self.ADODataSet1.FieldByName('birth_place').AsString:= t[25]; self.ADODataSet1.FieldByName('multiple_birth_indicator').AsString:= t[26];

126

self.ADODataSet1.FieldByName('birth_order').AsString:= t[27]; self.ADODataSet1.FieldByName('citizenship').AsString:= t[28]; self.ADODataSet1.FieldByName('veterans_military_status').AsString:= t[29]; self.ADODataSet1.FieldByName('nationality').AsString:= t[30]; self.ADODataSet1.FieldByName('data_falescimento').AsString:= t[31]; self.ADODataSet1.FieldByName('patient_death_indicator').AsString:= t[32]; self.ADODataSet1.Post; end; procedure TForm1.atualizarProntuarioPaciente(t: TStringList); var i,total,exameAtual: integer; begin total:= strToInt(t[7]); exameAtual:= 7; self.ADOBuscaExame.Active:= false; for i:=1 to total do begin inc(exameAtual); self.UpdateSQL1.InsertSQL.Clear; self.UpdateSQL1.InsertSQL.Text:= 'insert into exame (patient_id_internal,dataexame,resultado) values ('+ quotedstr(t[4])+' , '+ quotedstr(t[2])+' , '+ quotedstr(t[exameAtual])+' )'; self.UpdateSQL1.Apply(ukInsert); end; self.ADOBuscaExame.Active:=true; end; function TForm1.extrairToken(BaseString, BreakString: string; StringList: TStringList): TStringList; var EndOfCurrentString: byte; begin repeat EndOfCurrentString := Pos(BreakString, BaseString); if EndOfCurrentString = 0 then StringList.add(BaseString) else StringList.add(Copy(BaseString, 1, EndOfCurrentString - 1)); BaseString := Copy(BaseString, EndOfCurrentString + length(BreakString), length(BaseString) - EndOfCurrentString); until EndOfCurrentString = 0; result := StringList; end; procedure TForm1.ServidorSocketAccept(Sender: TObject; ClientSocket: TCustomIpClient); var msg:string; DataThread: TClientDataThread; begin // create thread DataThread:= TClientDataThread.Create(true); msg:= ClientSocket.Receiveln;

127

if msg<>'' then RecebeMensagem(msg); DataThread.Resume; end; procedure TForm1.FormCreate(Sender: TObject); begin ServidorSocket.Active:=true; end; end. ---------------------------------------cliente.cpp (Aplicação Cliente)--------------------------------- #include "Cliente.h" #include <pthread.h> #include <stdio.h> #ifndef unix #include <io.h> #endif #include <iostream> #include <fstream> #include "CMSH.h" #include "LexicoR.h" #include "SemanticoR.h" #include "SintaticoR.h" #include "AnalysisError.h" #include <exception> #include <iomanip> using namespace std; using std::cout; using std::endl; void Cliente::setAplicacaoOrigem(string aplicOrigem){ aplicacaoOrigem = aplicOrigem; } void Cliente::setTipoMensagem(string tipomsg){ tipoMensagem = tipomsg; } void Cliente::setQueryID(string query){ queryID = query; } void Cliente::setAplicacaoDestino(string aplicDestino){ aplicacaoDestino=aplicDestino; } void Cliente::setQueryResult(string qr){ queryResult = qr; }

128

char* Cliente::getEndIPLocal(){ #ifndef unix WORD wVersionRequested; WSADATA wsaData; PHOSTENT hostinfo; wVersionRequested = MAKEWORD( 1, 1 ); #endif #ifdef unix struct hostent *hostinfo; #endif char name[255]; char *ip; #ifndef unix if ( WSAStartup( wVersionRequested, &wsaData ) == 0 ) #endif if( gethostname ( name, sizeof(name)) == 0) { if((hostinfo = gethostbyname(name)) != NULL) { int nCount = 0; #ifndef unix while(hostinfo->h_addr_list[nCount]){ ip = inet_ntoa(*(struct in_addr *)hostinfo->h_addr_list[nCount]); nCount++; } #endif #ifdef unix ip = inet_ntoa(*((struct in_addr *)hostinfo->h_addr)); #endif } } return ip; } void Cliente::contemArquivoConfigServer(const string& fileName) { FILE *file = fopen(fileName.c_str(), "rb"); if (!file){ string msg = "O arquivo "+fileName+ " nao existe!"; MessageBox(NULL,msg.c_str(),"Cliente HL7",MB_ICONSTOP|MB_OK); exit(1); } else fclose(file); } string Cliente::leiaConfigServidor(){ string serverConfigFile = "configServidor.txt"; contemArquivoConfigServer(serverConfigFile); ifstream serverConfig(serverConfigFile.c_str()); string serverIPAddress; // lê endereço ip do servidor no arquivo txt

129

getline(serverConfig,serverIPAddress); char * c = (char *)serverIPAddress.c_str(); string temp = strtok(c,"\r\n"); serverConfig.close(); serverIPAddress = temp; return serverIPAddress; } #ifndef unix void Cliente::enviarMensagem(SOCKET s, string msg){ int bytesSent; const char* sendbuf = msg.c_str(); bytesSent = send( s, sendbuf, strlen(sendbuf), 0 ); closesocket(s); printf("\nMensagem que foi enviada:"); printf(msg.c_str()); printf("\nBytes: %d",bytesSent); printf("\n"); } #endif #ifdef unix void Cliente::enviarMensagemUnix(int s, string msg){ int bytesSent; const char* sendbuf = msg.c_str(); bytesSent = send( s, sendbuf, strlen(sendbuf), 0 ); close(s); } #endif /*papel cliente qdo quem = "S"(servidor) e papel de servidor qdo quem = "A"(aplicacao)*/ bool Cliente::conectar(string msg, string quem, int porta){ bool conectou = false; #ifndef unix WSADATA wsaData; int iResult = WSAStartup( MAKEWORD(2,2), &wsaData ); if ( iResult != NO_ERROR ) printf("Erro no WSAStartup()\n"); SOCKET m_socketEnvio; #endif #ifdef unix int m_socketEnvio; #endif m_socketEnvio = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ); #ifndef unix if ( m_socketEnvio == INVALID_SOCKET ) { printf( "Erro no socket %ld\n", WSAGetLastError() ); WSACleanup(); } #endif #ifdef unix if ( m_socketEnvio == -1 ) {

130

} #endif // Connecta com o servidor. sockaddr_in clientService; clientService.sin_family = AF_INET; string ipServidor; if (quem == "S"){//caso a mensagem deva ser enviada ao servidor ipServidor = leiaConfigServidor(); } else{//caso a mensagem deva ser encaminhada para a aplicação ipServidor = getEndIPLocal(); } clientService.sin_port = htons( porta ); clientService.sin_addr.s_addr = inet_addr( ipServidor.c_str()); #ifndef unix if (connect(m_socketEnvio, (SOCKADDR*) &clientService, sizeof(clientService)) == SOCKET_ERROR) { WSACleanup(); string erro="Não foi possível estabelecer conexão com o servidor"+quem; MessageBox(NULL,erro.c_str(),"Cliente HL7",MB_ICONSTOP|MB_OK); } #endif #ifdef unix if (connect(m_socketEnvio, (struct sockaddr*) &clientService, sizeof(clientService) ) == -1) { printf( "Falha na conexao...%s[%d]\n", strerror(errno),errno); }//if #endif else{ #ifndef unix enviarMensagem(m_socketEnvio, msg); #endif #ifdef unix enviarMensagemUnix(m_socketEnvio,msg); #endif conectou = true; }//else // Send data. return conectou; } string Cliente::getHoraAtual(){ time_t hora; struct tm *datetime; char buffer[128]; tzset(); time(&hora); datetime = localtime(&hora); strftime(buffer, sizeof(buffer),"%X", datetime); return (string) buffer; } string Cliente::getDataHoraAtual(){

131

time_t hora; struct tm *datetime; char buffer[128]; tzset(); time(&hora); datetime = localtime(&hora); strftime(buffer, sizeof(buffer),"%Y%m%d %X", datetime); return (string) buffer; } void Cliente::enviarMensagemConfirmacao(CMSH mshR){ string ipLocal = (string)getEndIPLocal(); string cabecalho= "MSH|^~\\&|"+mshR.getSending_Application()+"|"+ipLocal+"|"+ mshR.getSending_Application()+"|"+ // Receiving_Application mshR.getSending_Facility() + "|"+ // Receiving_Facility getDataHoraAtual()+"||ACK^|"+ // Message_Type "IDMSH"+ getDataHoraAtual()+"|"+ // Message_Control_ID "P|2.3<cr>"; string confirmacao = "MSA|AA|"+mshR.getMessage_Control_ID()+"<cr>"; string temp = cabecalho+confirmacao; conectar(temp,"S",27015); } void Cliente::enviarMensagemParaServidorRespostaBuscaPaciente(Cliente *cliente, CPID *cpid){ string ipLocal = (string)cliente->getEndIPLocal(); string cabecalho = "MSH|^~\\&|"+aplicacaoOrigem+"|"+ipLocal+"|"+ aplicacaoDestino+"|id"+ queryID+"|"+getDataHoraAtual()+ "||RPI^A24|IDMSH"+ getDataHoraAtual()+"|P|2.3<cr>"; string confirmacao = "QAK|"+ queryID+"|"+ queryResult+"<cr>"; string temp; if (queryResult!="NF"){ string pid = preenchePID(cpid); temp = cabecalho+confirmacao+pid; }else temp = cabecalho+confirmacao; conectar(temp,"S",27015); } void Cliente::enviarMensagemParaServidorResultadoExame(char *msg, Cliente *c){ string token = strtok(msg,"|"); c->setAplicacaoOrigem(token); token = strtok(NULL,"|"); c->setTipoMensagem(token); token = strtok(NULL,"|"); c->setAplicacaoDestino(token); token = strtok(NULL,"|"); string idPaciente = token; token = strtok(NULL,"|"); string tabela = token; token = strtok(NULL,"|"); int totlinhas = atoi(token.c_str()); string dsp = ""; for (int i=0; i<totlinhas;i++){ token = strtok(NULL,"|");

132

dsp = dsp + "DSP||"+token+"|<cr>"; } string ipLocal = (string)getEndIPLocal(); string msh = "MSH|^~\\&|"+aplicacaoOrigem+"|"+ipLocal+"|"+aplicacaoDestino+ "|IPConfirmacao|"+getDataHoraAtual()+"||PIN^A08|IDMSH"+ getDataHoraAtual()+"|P|2.3<cr>"; string qrd = "QRD|" + getDataHoraAtual()+"|T|I|"+ idPaciente+"|||2000|"+ idPaciente+"|"+ tabela +"|GE||T<cr>"; string temp = msh + qrd+ dsp; conectar(temp,"S",27015); } void Cliente::enviarMensagemParaServidorPedidoBuscaPaciente(char *msg,Cliente *c){ string token = strtok(msg,"|"); c->setAplicacaoOrigem(token); token = strtok(NULL,"|"); c->setTipoMensagem(token); token = strtok(NULL,"|"); c->setAplicacaoDestino(token); token = strtok(NULL,"|"); string idPaciente = token; token = strtok(NULL,"|"); string tabela = token; string ipLocal = (string)getEndIPLocal(); string msh = "MSH|^~\\&|"+aplicacaoOrigem+"|"+ipLocal+"|"+aplicacaoDestino+ "|IPConfirmacao|"+ getDataHoraAtual()+"||RQP^A19|IDMSH"+ getDataHoraAtual()+"|P|2.3<cr>"; string qrd = "QRD|" + getDataHoraAtual()+"|T|I|"+ idPaciente+"|||2000|"+ idPaciente+"|"+ tabela +"|GE||T<cr>"; string qrf = "QRF|" + aplicacaoOrigem+"|||||ANY|ANY|ALL|0800<cr>"; string temp = msh + qrd+ qrf; conectar(temp,"S",27015); } CPID* construirPID(char *msg, Cliente *c){ CPID *cpid = new CPID(); string token = strtok(msg,"|"); c->setAplicacaoOrigem(token); c->setAplicacaoDestino(token); token = strtok(NULL,"|"); c->setTipoMensagem(token); string m = token; if (m == "CadastroPaciente-Resposta"){ token = strtok(NULL,"|"); string z = token; z = token.substr(0,(token.size()-1)); c->setAplicacaoDestino(z); token = strtok(NULL,"|"); string k = token; k = token.substr(0,(token.size()-1));

133

c->setQueryID(k); token = strtok(NULL,"|"); string j = token; j = token.substr(0,(token.size()-1)); c->setQueryResult(j); } token = strtok(NULL,"|"); cpid->setSet_ID(token); token = strtok(NULL,"|"); cpid->setPatient_ID_External(token); token = strtok(NULL,"|"); m = token.substr(0,(token.size()-1)); cpid->setPatient_ID_Internal(m); token = strtok(NULL,"|"); cpid->setAlternate_Patient_ID(token); token = strtok(NULL,"|"); cpid->setPatient_Name(token); token = strtok(NULL,"|"); cpid->setMother_Maiden_Name(token); token = strtok(NULL,"|"); cpid->setDate_Time_of_Birth(token); token = strtok(NULL,"|"); cpid-> setSex(token); token = strtok(NULL,"|"); cpid->setPatient_Alias(token); token = strtok(NULL,"|"); cpid->setRace(token); token = strtok(NULL,"|"); cpid->setPatient_Address(token); token = strtok(NULL,"|"); cpid->setPhone_Number_Home(token); token = strtok(NULL,"|"); cpid->setPhone_Number_Business(token); token = strtok(NULL,"|"); cpid->setPrimary_Language(token); token = strtok(NULL,"|"); cpid->setMarital_Status(token); token = strtok(NULL,"|"); cpid->setReligion(token); token = strtok(NULL,"|"); cpid->setPatient_Account_Number(token); token = strtok(NULL,"|"); cpid->setSSN_Number(token); token = strtok(NULL,"|"); string t = token; if (t==" ") t = " ^ ^ "; cpid->setDriver_License_Number(t); token = strtok(NULL,"|"); cpid->setMother_Identifier(token); token = strtok(NULL,"|"); cpid->setEthnic_Group(token); token = strtok(NULL,"|"); cpid->setBirth_Place(token); token = strtok(NULL,"|"); cpid->setMultiple_Birth_Indicator(token);

134

token = strtok(NULL,"|"); cpid->setBirth_Order(token); token = strtok(NULL,"|"); cpid->setCitizenship(token); token = strtok(NULL,"|"); cpid->setVeterans_Military_Status(token); token = strtok(NULL,"|"); cpid->setNationality(token); token = strtok(NULL,"|"); cpid->setPatient_Death_Date_and_Time(token); token = strtok(NULL,"|"); cpid->setPatient_Death_Indicator(token); return cpid; } string Cliente::construirMensagemAdmissaoParaAplicacao(CMSH msh,CEVN evn, CPID pid, string msg){ return (msh.getMessage_Control_ID()+"|"+ msh.getMessage_Type_Event()+"|"+ msh.getDate_Time_of_Message()+"|"+ msh.getSending_Application()+"|"+ pid.getPatient_ID_Internal()+"|"+pid.getPatient_Name()+"|"+ pid.getDate_Time_of_Birth()+"|"+pid.getSex()+"|"+ pid.getPatient_Address()+"|"+pid.getPhone_Number_Home()+"|"+ pid.getPhone_Number_Business()+"|"+pid.getPatient_Account_Number()+ "|"+ pid.getSet_ID()+"|"+ pid.getPatient_ID_External()+"|"+ pid.getAlternate_Patient_ID()+"|"+ pid.getMother_Maiden_Name()+"|"+ pid.getPatient_Alias()+"|"+ pid.getRace()+"|"+ pid.getPrimary_Language()+"|"+ pid.getMarital_Status()+"|"+ pid.getReligion()+"|"+pid.getSSN_Number()+"|"+ pid.getDriver_License_Number()+"|"+pid.getMother_Identifier()+"|"+ pid.getEthnic_Group()+"|"+ pid.getBirth_Place()+"|"+ pid.getMultiple_Birth_Indicator()+"|"+ pid.getBirth_Order()+"|"+pid.getCitizenship()+"|"+ pid.getVeterans_Military_Status()+"|"+ pid.getNationality()+"|"+ pid.getPatient_Death_Date_and_Time()+"|"+ pid.getPatient_Death_Indicator()+ "|"+"¨"+msg+"¨"); } string Cliente::construirMensagemConfirmacaoParaAplicacao(CMSH msh,CMSA msa, string msg){ return (msh.getMessage_Control_ID()+"|"+ msh.getMessage_Type_Event()+"|"+ msh.getDate_Time_of_Message()+"|"+ msh.getSending_Application()+ +"|"+ msa.getAcknowledgment_Code()+"|"+ msa.getMessage_Control_ID()+"|"+"¨"+msg+"¨"); } string Cliente::construirMensagemParaAplicacaoPedidoDadosPaciente(CMSH msh, CQRD qrd,string msg){ return (msh.getMessage_Control_ID()+"|"+ msh.getMessage_Type_Event()+"|"+ msh.getDate_Time_of_Message()+"|"+ msh.getSending_Application()+"|"+ qrd.getWho_subject_filter()+"|" + qrd.getWhat_subject_filter()+"|"+ qrd.getQuery_ID()+"|"+"¨"+msg+"¨"); } string Cliente::construirMensagemParaAplicacaoRespostaDadosPaciente(CMSH msh,

135

CQAK qak,CPID pid,string msg2){ return (msh.getMessage_Control_ID()+"|"+ msh.getMessage_Type_Event()+"|"+ msh.getDate_Time_of_Message()+"|"+ msh.getSending_Application()+ +"|"+ qak.getQuery_Tag_QAK()+"|"+ qak.getQuery_Response_Status()+"|"+ pid.getPatient_ID_Internal()+"|"+pid.getPatient_Name()+"|"+ pid.getDate_Time_of_Birth()+"|"+pid.getSex()+"|"+ pid.getPatient_Address()+"|"+pid.getPhone_Number_Home()+"|"+ pid.getPhone_Number_Business()+"|"+ pid.getPatient_Account_Number()+"|"+"¨"+msg2+"¨"); } string Cliente::construirMensagemParaAplicacaoRespostaDadosPacienteNF(CMSH msh, CQAK qak,string msg2){ return (msh.getMessage_Control_ID()+"|"+ msh.getMessage_Type_Event()+"|"+ msh.getDate_Time_of_Message()+"|"+ msh.getSending_Application()+ +"|"+ qak.getQuery_Tag_QAK()+"|"+ qak.getQuery_Response_Status()+"|"+ +"¨"+msg2+"¨"); } string Cliente::construirMensagemParaAplicacaoAtualizacaoProntuario(CMSH msh, CQRD qrd,vector<CDSP> vetDSP,string msg){ string tamanho; char buf [3]; string elementoDSP = ""; for (int i=0;i<vetDSP.size();i++) elementoDSP = elementoDSP+ vetDSP[i].getData_Line()+"|"; itoa(vetDSP.size(),buf,10); tamanho = (string)buf; return (msh.getMessage_Control_ID()+"|"+ msh.getMessage_Type_Event()+"|"+ msh.getDate_Time_of_Message()+"|"+ msh.getSending_Application()+ "|"+ qrd.getWho_subject_filter()+"|" + qrd.getWhat_subject_filter()+"|"+ qrd.getQuery_ID()+"|"+tamanho+ "|"+elementoDSP+ "¨"+msg+"¨"); } void* receberMensagem(void *s){ #ifndef unix SOCKET soc = (SOCKET) s; #endif #ifdef unix int soc = (int) s; #endif int bytesRecv = -1; char recvbuf[3000] = ""; bytesRecv = recv( soc, recvbuf, 3000, 0 ); //ver tamanho if (bytesRecv > 0) { try{ Cliente *cliente = new Cliente(); char* msg = recvbuf; printf(msg); string msg2 = msg; /*verifica o tipo de mensagem recebida: se veio do servidor ou da interface */ string msgRecebida = strtok(recvbuf,"|");

136

string origem = msgRecebida; msgRecebida = strtok(NULL,"|"); string tipo = msgRecebida; if (origem =="CadastroPaciente") { CPID *pid = new CPID(); pid = construirPID((char*) msg2.c_str(),cliente); if (tipo =="CadastroPaciente-Inclusao"){ cliente->enviarMensagemCadastroPacienteParaServidor(cliente,pid); }else{ cliente->enviarMensagemParaServidorRespostaBuscaPaciente(cliente,pid); } delete pid; } //if (origem =="CadastroPaciente") else if (origem =="GerenciaExames"){ if (tipo =="ResultadoExame"){ cliente->enviarMensagemParaServidorResultadoExame( (char*) msg2.c_str(),cliente); }else cliente->enviarMensagemParaServidorPedidoBuscaPaciente( (char*) msg2.c_str(),cliente); } else{ //mensagem formato HL7 LexicoR *anLexico = new LexicoR(msg2.c_str()); SintaticoR *anSintatico = new SintaticoR(); SemanticoR *anSemantico = new SemanticoR(); anSintatico->parse(anLexico,anSemantico); CMSH mshR = anSemantico->enviaObjetoMSHR(); string destino = mshR.getReceiving_Application(); int porta = atoi(mshR.getSecurity().c_str()); string msgAplicacao; string evento = mshR.getMessage_Type_Event(); if (evento == "ACK"){ CMSA msaR = anSemantico->enviaObjetoMSAR(); printf("\nRecebeu mensagem de confirmacao!\n"); msgAplicacao = cliente->construirMensagemConfirmacaoParaAplicacao(mshR,msaR,msg2); cliente->conectar(msgAplicacao,"A",porta); }else if (evento == "RQP"){ CQRD qrdR = anSemantico->enviaObjetoQRDR(); printf("\nMensagem de solicitacao de busca recebida!\n"); msgAplicacao = cliente->construirMensagemParaAplicacaoPedidoDadosPaciente(mshR,qrdR,msg2); cliente->conectar(msgAplicacao,"A",porta); }else if (evento == "RPI"){ CQAK qakR = anSemantico->enviaObjetoQAKR(); if (qakR.getQuery_Response_Status()!="NF"){ CPID pidR = anSemantico->enviaObjetoPIDR(); msgAplicacao = cliente->construirMensagemParaAplicacaoRespostaDadosPaciente(mshR,qakR,pidR,msg2); }else msgAplicacao = cliente->construirMensagemParaAplicacaoRespostaDadosPacienteNF(mshR,qakR,msg2); printf("\nRecebeu resposta da solicitacao de busca!\n"); cliente->conectar(msgAplicacao,"A",porta);

137

}else if (evento == "PIN"){ CQRD qrdR = anSemantico->enviaObjetoQRDR(); vector<CDSP> vetDSPR; vetDSPR = anSemantico->enviaVetorDSPR(); printf("\nRecebeu atualizacao prontuario paciente\n"); msgAplicacao = cliente->construirMensagemParaAplicacaoAtualizacaoProntuario(mshR,qrdR,vetDSPR,msg2); cliente->conectar(msgAplicacao,"A",porta); if (cliente->conectar(msgAplicacao,"A",porta)) cliente->enviarMensagemConfirmacao(mshR); }else if (evento == "ADT"){ printf("\nRecebeu mensagem admissao paciente\n"); CEVN evnR = anSemantico->enviaObjetoEVNR(); CPID pidR = anSemantico->enviaObjetoPIDR(); msgAplicacao = cliente->construirMensagemAdmissaoParaAplicacao(mshR, evnR,pidR,msg2); if (cliente->conectar(msgAplicacao,"A",porta)) cliente->enviarMensagemConfirmacao(mshR); } delete anLexico; delete anSintatico; delete anSemantico; }//else mensagem formato HL7 delete cliente; }//try catch (AnalysisError *e){ fprintf(stderr,"Ocorreu exceção: \n", e->getMessage()); }//catch }// if (bytesRecv > 0) } void Cliente::ouvirServidor(){ #ifndef unix // Inicializa Winsock. WSADATA wsaData; //inicia o socket, o MAKEWORD(2,2) encontra versão do winsocket int iResult = WSAStartup( MAKEWORD(2,2), &wsaData ); if ( iResult != NO_ERROR ){} // Cria socket. SOCKET m_socket; #endif #ifdef unix int m_socket; #endif m_socket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ); /*primeiro parametro é a familia, segundo é o tipo(TCP ou UDP e o terceiro eh o protocolo associado a familia)*/ #ifndef unix if ( m_socket == INVALID_SOCKET ) { WSACleanup();

138

} #endif #ifdef unix if ( m_socket == -1) { printf("Não foi possível conectar" ); } #endif // Bind the socket. sockaddr_in service; service.sin_family = AF_INET; service.sin_addr.s_addr = inet_addr(getEndIPLocal()); service.sin_port = htons( 27014 ); //bind associa o socket ao endereço #ifndef unix if ( bind( m_socket,(SOCKADDR*)&service, sizeof(service)) == SOCKET_ERROR ){ closesocket(m_socket); } #endif #ifdef unix if ( bind( m_socket, (struct sockaddr*)&service, sizeof(service)) == -1 ) { close(m_socket); } #endif //lista o numero max de conexões aceitas pelo servidor if ( listen( m_socket, 10 ) == -1 ){} #ifndef unix SOCKET AcceptSocket; #endif #ifdef unix int AcceptSocket; #endif pthread_t threadCliente; int status; while (true) { //Aguarda por novas conexões AcceptSocket = accept( m_socket, NULL, NULL ); if (AcceptSocket != -1) { int rc = pthread_create(&threadCliente, NULL, receberMensagem, (void *)AcceptSocket); rc = pthread_join(threadCliente, (void **)&status); if (rc){ exit(-1); } #ifndef unix closesocket(AcceptSocket); #endif #ifdef unix close(AcceptSocket); #endif }//fim do if }//fim do while }

139

string Cliente::preenchePID(CPID *cpid){ return("PID|"+cpid->getSet_ID()+"|"+cpid->getPatient_ID_External()+"|"+ cpid->getPatient_ID_Internal()+"|"+cpid->getAlternate_Patient_ID()+"|"+ cpid->getPatient_Name()+"|"+cpid->getMother_Maiden_Name()+"|"+ cpid->getDate_Time_of_Birth()+"|"+cpid->getSex()+"|"+ cpid->getPatient_Alias()+"|"+cpid->getRace()+"|"+ cpid->getPatient_Address()+"||"+cpid->getPhone_Number_Home()+"|"+ cpid->getPhone_Number_Business()+"|"+cpid->getPrimary_Language()+"|"+ cpid->getMarital_Status()+"|"+cpid->getReligion()+"|"+ cpid->getPatient_Account_Number()+"|"+cpid->getSSN_Number()+"|"+ cpid->getDriver_License_Number()+"|"+cpid->getMother_Identifier()+"|"+ cpid->getEthnic_Group()+"|"+cpid->getBirth_Place()+"|"+ cpid->getMultiple_Birth_Indicator()+"|"+cpid->getBirth_Order()+"|"+ cpid->getCitizenship()+"|"+cpid->getVeterans_Military_Status()+"|"+ cpid->getNationality()+"|"+cpid->getPatient_Death_Date_and_Time()+"|"+ cpid->getPatient_Death_Indicator()+"<cr>"); } void Cliente::enviarMensagemCadastroPacienteParaServidor(Cliente *cliente, CPID *cpid){ string ipLocal = (string)getEndIPLocal(); string msh = "MSH|^~\\&|"+aplicacaoOrigem+"|"+ipLocal+"|"+aplicacaoDestino+ "|IPConfirmacao|"+ getDataHoraAtual()+"||ADT^A01|IDMSH"+ getDataHoraAtual()+"|P|2.3<cr>"; string evn = "EVN|A01|"+ getDataHoraAtual()+ "<cr>"; string mensagem = msh + evn + cliente->preenchePID(cpid); cliente->conectar(mensagem,"S",27015); } int main(int argc,char *argv[]){ //O Corpo principal do Programa printf("Cliente inicializado..."); Cliente *cliente = new Cliente(); cliente->setAplicacaoOrigem("CadastroPaciente"); cliente->ouvirServidor(); delete cliente; return 0; } ---------------------------------------cliente.h (Aplicação Cliente)--------------------------------- #ifndef Cliente_H #define Cliente_H #ifndef unix #ifndef WIN32 #define WIN32 #endif #endif #ifndef unix

140

#include <winsock2.h> #include <string> #endif #ifdef unix #include <ctype.h> // for isdigit #include <sys/types.h> // for connect(), bind(), accept(), #include <sys/socket.h> // for connect(), listen(), bind() accept(), #include <netinet/in.h> // for ntons(), htonl(), etc... #include <arpa/inet.h> // for inet_addre() #include <unistd.h> // for close(), read(), write() #include <netdb.h> // for gethostbyname #include <sys/time.h> // for timeval struct, and select() #include <string.h> // for memset() #include <map> // for STL map class (Reference counting) #endif #include "CMSH.h" #include "CPID.h" #include "CEVN.h" #include "CMSA.h" #include "CQRD.h" #include "CQRF.h" #include "CQAK.h" #include "CDSP.h" #include <vector> using std::vector; using std::string; class Cliente { private: string aplicacaoOrigem; string aplicacaoDestino; string tipoMensagem; string queryID; string queryResult; public: void setAplicacaoOrigem(string aplicOrigem); void setAplicacaoDestino(string aplicDestino); void setQueryID(string query); void setTipoMensagem(string tipoMsg); void setQueryResult(string qr); //retorna mensagem de admissão que deverá ser enviada para aplicação string construirMensagemAdmissaoParaAplicacao(CMSH mshR,CEVN evnr, CPID pidr, string msg); //retorna mensagem de confirmação recebida para a aplicação string construirMensagemConfirmacaoParaAplicacao(CMSH msh,CMSA msa, string msg);

141

//retorna mensagem consulta de paciente string construirMensagemParaAplicacaoPedidoDadosPaciente(CMSH msh, CQRD qrd,string msg); //retorna mensagem resultado consulta por paciente localizado string construirMensagemParaAplicacaoRespostaDadosPaciente(CMSH mshR, CQAK qakR,CPID pidR,string msg2); //retorna mensagem para recebimento de resultado(atualizar dados paciente) string construirMensagemParaAplicacaoAtualizacaoProntuario(CMSH msh, CQRD qrd,vector<CDSP> vetDSP,string msg); //retorna mensagem resultado consulta por paciente não encontrado string construirMensagemParaAplicacaoRespostaDadosPacienteNF(CMSH msh, CQAK qak,string msg2); //Retorna o endereço IP local char* getEndIPLocal(); /*Verifica se o arquivo de configuração que contém o end ip do servidor se encontra na pasta do projeto.*/ void contemArquivoConfigServer(const string& fileName); //Retorna o endereço IP do servidor a partir do arquivo configServidor.txt string leiaConfigServidor(); #ifndef unix /*Cliente envia mensagem para o servidor, que por vez o encaminha para a aplicação destino*/ void enviarMensagem(SOCKET s,string msg); #endif #ifdef unix /*Cliente envia mensagem para o servidor, que por vez o encaminha para a aplicação destino*/ void enviarMensagemUnix(int s,string msg); #endif //Cliente conecta com o servidor bool conectar(string mensagem, string quem, int porta); //Envia mensagem de confirmação void enviarMensagemConfirmacao(CMSH mshR); //Envia mensagem HL7 para consulta paciente void enviarMensagemParaServidorPedidoBuscaPaciente(char *msg,Cliente *c); //Envia mensagem HL7 resultante da busca por paciente void enviarMensagemParaServidorRespostaBuscaPaciente(Cliente *cliente, CPID *cpid); //Envia mensagem HL7 para atualização de dados do paciente void enviarMensagemParaServidorResultadoExame(char* msg,Cliente *c);

142

//aguarda novas mensagens enviadas tanto pelo servidor qto pela Aplicação void ouvirServidor(); //envia mensagem HL7 para admissão de paciente void enviarMensagemCadastroPacienteParaServidor(Cliente *cliente, CPID *cpid); //retorna a hora do sistema string getHoraAtual(); //Retorna a data e hora atual string getDataHoraAtual(); //preenche segmemto identificacao paciente string preenchePID(CPID *cpid); }; //Cria thread responsável por aguardar mensagens enviadas pelo servidor extern "C" void *receberMensagem(void *s); #endif ---------------------------------------Servidor.cpp (Aplicação Servidor)----------------------------- #include <pthread.h> #include "LexicoR.h" #include "SemanticoR.h" #include "SintaticoR.h" #include "AnalysisError.h" #include "Server.h" #include <exception> #include <stdio.h> #ifndef unix #include <io.h> #endif #include <iostream> using std::exception; PGconn *conn; pthread_mutex_t mutex; void beginRegion(){ pthread_mutex_lock(&mutex);} void endRegion(){ pthread_mutex_unlock(&mutex); } char* Server::getEndIPLocal(){ #ifndef unix WORD wVersionRequested; WSADATA wsaData; PHOSTENT hostinfo; wVersionRequested = MAKEWORD( 1, 1 ); #endif #ifdef unix

143

struct hostent *hostinfo; #endif char name[255]; char *ip; #ifndef unix if ( WSAStartup( wVersionRequested, &wsaData ) == 0 ) #endif if( gethostname ( name, sizeof(name)) == 0){ if((hostinfo = gethostbyname(name)) != NULL){ int nCount = 0; #ifndef unix while(hostinfo->h_addr_list[nCount]){ ip = inet_ntoa(*(struct in_addr *)hostinfo->h_addr_list[nCount]); nCount++; } #endif #ifdef unix ip = inet_ntoa(*((struct in_addr *)hostinfo->h_addr)); #endif } } return ip; } CMSH Server::validacaoMensagem(char *mensagem){ CMSH mshR; try{ LexicoR *anLexico = new LexicoR(mensagem); SintaticoR *anSintatico = new SintaticoR(); SemanticoR *anSemantico = new SemanticoR(); anSintatico->parse(anLexico,anSemantico); mshR = anSemantico->enviaObjetoMSHR(); string msg = mensagem; printf("Msg recebida: %s\n",msg.c_str()); }//try catch (AnalysisError *e){ printf("Deu exceção: \n", e->getMessage()); } return mshR; } void Server::exit_nicely(){ PQfinish(conn); exit(1); } string Server::getDataHoraAtual(){ time_t hora; struct tm *datetime; char buffer[128]; tzset(); time(&hora); datetime = localtime(&hora);

144

strftime(buffer, sizeof(buffer),"%d/%m/%Y %X", datetime); return (string) buffer; } void Server::inserirErroBanco(string msgErro){ PGresult *res; string sql = "Insert into erros values( '"+msgErro+"', '"+ getDataHoraAtual()+"')"; res = PQexec(conn, sql.c_str()); if (PQresultStatus(res) == PGRES_FATAL_ERROR){ fprintf(stderr, "Erro no banco ao inserir dados em Erros! %s", PQerrorMessage(conn)); PQclear(res); exit_nicely(); } else{ PQclear(res); } } void Server::conectarBanco(){ conn = PQsetdbLogin("localhost","5432",NULL,NULL,"HL7","postgres","phigres*"); if (PQstatus(conn) != CONNECTION_OK){ fprintf(stderr, "Conexao com database falhou: %s", PQerrorMessage(conn)); exit_nicely(); } } bool Server::verificaIPDestino(string ip){ const char *paramValues[1]; PGresult *res; paramValues[0] = ip.c_str(); beginRegion(); res = PQexecParams(conn, "SELECT * FROM Configuracoes WHERE ip = $1",1,NULL, paramValues, NULL,NULL,1); if (PQresultStatus(res) != PGRES_TUPLES_OK){ fprintf(stderr, "Erro durante a seleçao do ip destino: %s", PQerrorMessage(conn)); PQclear(res); exit_nicely(); } endRegion(); if (PQntuples(res)>0) return true; else return false; } vector<Aplicacao>Server:: verificarDestino(string aplicacao, string evento, string ip, string aplicOrigem){ PGresult *res; vector<Aplicacao> vetorAplic; /*se tipo de evento for ORU ou ADT, a mensagem deverá ser encaminhada para

145

todas as aplicações registradas na tabela de Configuracao */ if (evento=="ACK"){ const char *paramValues[1]; paramValues[0] = aplicacao.c_str(); beginRegion(); res = PQexecParams(conn,"SELECT * FROM Configuracoes WHERE aplicacao = $1", 1, NULL, paramValues, NULL, NULL, 1); if (PQresultStatus(res) != PGRES_TUPLES_OK){ fprintf(stderr, "Erro ao selecionar dados da Aplicacao: %s", PQerrorMessage(conn)); PQclear(res); exit_nicely(); }else{ int ip_fnum = PQfnumber(res, "IP"); int porta_fnum = PQfnumber(res, "porta"); int aplic_fnum = PQfnumber(res, "aplicacao"); char *ip_ptr, *porta_ptr, *aplic_ptr; for (int i=0 ; i<PQntuples(res);i++){ ip_ptr = PQgetvalue(res, i, ip_fnum); porta_ptr = PQgetvalue(res, i, porta_fnum); aplic_ptr = PQgetvalue(res, i, aplic_fnum); Aplicacao aplic; aplic.endIP = (string)ip_ptr; aplic.porta = (string)porta_ptr; vetorAplic.push_back(aplic); }//for }//else endRegion(); } else{ if ((evento== "RQP")||(evento=="RPI")||(evento=="PIN")){ const char *paramValues[1]; paramValues[0] = aplicacao.c_str(); string sql= "Select * from Configuracoes where aplicacao = $1"; beginRegion(); res = PQexecParams(conn, sql.c_str(),1,NULL,paramValues,NULL,NULL,1); if (PQresultStatus(res) != PGRES_TUPLES_OK){ fprintf(stderr,"Erro ao selecionar todos os dados em Configuracoes!%s", PQerrorMessage(conn)); PQclear(res); exit_nicely(); }//if else { int ip_fnum = PQfnumber(res, "IP"); int porta_fnum = PQfnumber(res, "porta"); int aplic_fnum = PQfnumber(res, "aplicacao"); char *ip_ptr, *porta_ptr, *aplic_ptr; for (int i=0 ; i<PQntuples(res);i++){ ip_ptr = PQgetvalue(res, i, ip_fnum); porta_ptr = PQgetvalue(res, i, porta_fnum); aplic_ptr = PQgetvalue(res, i, aplic_fnum); Aplicacao aplic; aplic.endIP = (string)ip_ptr; aplic.porta = (string)porta_ptr; vetorAplic.push_back(aplic); }//for

146

}//else } else{ const char *paramValues[2]; paramValues[0] = ip.c_str(); paramValues[1] = aplicOrigem.c_str(); string sql= "Select * from Configuracoes where (ip <> $1 or aplicacao <> $2) and aplicacao <> $2"; beginRegion(); res = PQexecParams(conn, sql.c_str(),2,NULL,paramValues,NULL,NULL,1); if (PQresultStatus(res) != PGRES_TUPLES_OK){ fprintf(stderr,"Erro ao selecionar todos os dados em Configuracoes!%s", PQerrorMessage(conn)); PQclear(res); exit_nicely(); }//if else { int ip_fnum = PQfnumber(res, "IP"); int porta_fnum = PQfnumber(res, "porta"); int aplic_fnum = PQfnumber(res, "aplicacao"); char *ip_ptr, *porta_ptr, *aplic_ptr; for (int i=0 ; i<PQntuples(res);i++){ ip_ptr = PQgetvalue(res, i, ip_fnum); porta_ptr = PQgetvalue(res, i, porta_fnum); aplic_ptr = PQgetvalue(res, i, aplic_fnum); Aplicacao aplic; aplic.endIP = (string)ip_ptr; aplic.porta = (string)porta_ptr; vetorAplic.push_back(aplic); }//for }//else }//else }endRegion(); PQclear(res); return vetorAplic; } void Server::armazenarCaixaSaida(string ipDestino, string ipRemetente, string msg, string porta, string idMsg){ PGresult *res; string dataHora = getDataHoraAtual(); string sql = "Insert into caixasaida values( '"+ipDestino+"', '"+ipRemetente+ "', "+porta+", '"+msg+"', '"+idMsg+"', to_timestamp('"+dataHora+ "','DD/MM/YYYY HH24:MI:SS'))"; beginRegion(); res = PQexec(conn, sql.c_str()); if (PQresultStatus(res) == PGRES_FATAL_ERROR){ fprintf(stderr, "Erro no banco ao inserir dados na Caixa Saida! %s", PQerrorMessage(conn)); PQclear(res); inserirErroBanco("Erro no banco ao inserir dados na Caixa Saida: "+sql); exit_nicely(); } else{ PQclear(res);

147

printf("Dados armazenados na caixa de saida!\n"); } endRegion(); } void Server::enviarMensagem(string msg, vector<Aplicacao> ips, CMSH cmshr){ int bytesSent; string ipRemetente = cmshr.getSending_Facility(); string msgAlterada; int total = ips.size(); printf("\nTotal IPs encontrados: %d",total); for (int i=0; i<ips.size();i++){ string porta = ips[i].porta; msgAlterada = adicionarPortaNaMsgRecebida(msg, porta); #ifndef unix SOCKET socDestino; #endif #ifdef unix int socDestino; #endif socDestino = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ); #ifndef unix if ( socDestino == INVALID_SOCKET ) { printf( "Erro no socket(): %ld\n", WSAGetLastError() ); } #endif #ifdef unix if ( socDestino == -1 ) { printf( "Erro no socket() \n"); } #endif else{ sockaddr_in service; string ip = ips[i].endIP; service.sin_family = AF_INET; service.sin_addr.s_addr = inet_addr( ip.c_str() ); service.sin_port = htons( atoi("27014") ); #ifndef unix if (connect( socDestino, (SOCKADDR*) &service, sizeof(service))== SOCKET_ERROR) { printf("Nao foi possivel conectar com o destino %s\n", ip.c_str()); char * c = (char *)msgAlterada.c_str(); string tok = strtok(c,"\\"); string temp = tok+ "\\\\&"; temp = temp + strtok(NULL,"&" ); armazenarCaixaSaida(ips[i].endIP, ipRemetente, temp, ips[i].porta, cmshr.getMessage_Control_ID());

148

}//if #endif #ifdef unix if (connect( socDestino, (struct sockaddr*)&service, sizeof(service)) == -1) { printf("Nao foi possivel conectar com o destino %s\n", ip.c_str()); char * c = (char *)msgAlterada.c_str(); string tok = strtok(c,"\\"); string temp = tok+ "\\\\&"; temp = temp + strtok(NULL,"&" ); armazenarCaixaSaida(ips[i].endIP, ipRemetente,temp,ips[i].porta, cmshr.getMessage_Control_ID()); }//if #endif else{ const char* sendbuf = msgAlterada.c_str(); bytesSent = send( socDestino, sendbuf, strlen(sendbuf), 0 ); printf("Mensagem enviada ao destino %s\n",ip.c_str()); printf("Porta: %s\n",porta.c_str()); printf( "_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\n" ); //ips.erase(ips.begin()+i); }//else }//else #ifndef unix closesocket(socDestino); #endif #ifdef unix close(socDestino); #endif }//for } void Server::excluiCaixaMensagem(char* ip, char* idmsg, char* porta){ const char *paramValues[3]; PGresult *res; paramValues[0] = ip; paramValues[2] = idmsg; paramValues[1] = porta; res = PQexecParams(conn,"DELETE FROM CaixaSaida WHERE \"ipDestino\" = $1 and porta = $2 and \"idMsg\" = $3", 3, NULL,paramValues,NULL,NULL,1); if (PQresultStatus(res) == PGRES_FATAL_ERROR){ fprintf(stderr, "Erro no banco ao excluir dados na Caixa de Saida! %s", PQerrorMessage(conn)); PQclear(res); inserirErroBanco("Erro no banco ao excluir msg "+(string)idmsg+ " na Caixa de Saida"); exit_nicely(); } else{ PQclear(res); printf("Msg excluida da caixa de saida!\n");

149

} } PGresult* Server::temMsgCaixaSaida(){ PGresult *res; bool temMsgExpirada = false; string temp = "SELECT \"ipDestino\", \"ipOrigem\", porta, mensagem, \"idMsg\", now()-\"dataHora\" as tempocaixa FROM CaixaSaida"; beginRegion(); res = PQexec(conn,temp.c_str()); if (PQresultStatus(res) != PGRES_TUPLES_OK){ fprintf(stderr,"Falha ao selecionar dados da caixa de saida: %s", PQerrorMessage(conn)); PQclear(res); exit_nicely(); }//if else{ if (PQntuples(res)>0){ int dataHora_fnum = PQfnumber(res, "tempocaixa"); int ipDestino_fnum = PQfnumber(res, "\"ipDestino\""); int idmsg_fnum = PQfnumber(res, "\"idMsg\""); int porta_fnum = PQfnumber(res, "porta"); int msg_fnum = PQfnumber(res, "mensagem"); char *ip_ptr, *porta_ptr, *idmsg_ptr, *msg_ptr, *dataHora_ptr; for (int i = 0; i < PQntuples(res);i++){ dataHora_ptr = PQgetvalue(res, i, dataHora_fnum); if (atoi(dataHora_ptr) > 4){ ip_ptr = PQgetvalue(res, i, ipDestino_fnum); idmsg_ptr = PQgetvalue(res, i, idmsg_fnum); porta_ptr = PQgetvalue(res, i, porta_fnum); msg_ptr = PQgetvalue(res, i, msg_fnum); excluiCaixaMensagem(ip_ptr, idmsg_ptr, porta_ptr); inserirErroBanco("Expirou msg caixa saida!Destino: "+(string)ip_ptr+ " porta: "+(string)porta_ptr+"/MSG: "+(string)msg_ptr); temMsgExpirada = true; printf("Tem msg expirada...\n"); }//if }//for }//if endRegion(); }//else if (temMsgExpirada){ PQclear(res); beginRegion();//mutex res = PQexec(conn, "SELECT * FROM CaixaSaida"); if (PQresultStatus(res) != PGRES_TUPLES_OK){ fprintf(stderr,"Falha refresh caixa de saida: %s",PQerrorMessage(conn)); PQclear(res); exit_nicely(); }//if endRegion(); }//if return res; } void Server::envioMensagensCaixaSaida(PGresult *res){

150

int ipDestino_fnum = PQfnumber(res, "\"ipDestino\""); int idmsg_fnum = PQfnumber(res, "\"idMsg\""); int porta_fnum = PQfnumber(res, "porta"); int msg_fnum = PQfnumber(res, "mensagem"); char *ip_ptr, *porta_ptr, *idmsg_ptr, *msg_ptr; for (int i = 0; i < PQntuples(res);i++){ ip_ptr = PQgetvalue(res, i, ipDestino_fnum); idmsg_ptr = PQgetvalue(res, i, idmsg_fnum); porta_ptr = PQgetvalue(res, i, porta_fnum); msg_ptr = PQgetvalue(res, i, msg_fnum); if (verificaIPDestino((string)ip_ptr)){ #ifndef unix SOCKET socDestino; #endif #ifdef unix int socDestino; #endif socDestino = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ); #ifndef unix if ( socDestino == INVALID_SOCKET ) { printf( "Erro no socket(): %ld\n", WSAGetLastError() ); WSACleanup(); } #endif #ifdef unix if ( socDestino == -1) { printf( "Erro no socket\n" ); } #endif sockaddr_in service; service.sin_family = AF_INET; service.sin_addr.s_addr = inet_addr( ip_ptr ); service.sin_port = htons( 27014 ); #ifndef unix if ( connect( socDestino, (SOCKADDR*) &service, sizeof(service)) == SOCKET_ERROR){ printf("Nao foi possivel conectar com o destino %s",ip_ptr); printf(" da msg da cxa saida.\n"); }//if #endif #ifdef unix if (connect(socDestino,(struct sockaddr*)&service, sizeof(service)) == -1){ printf("Nao foi possivel conectar com o destino %s",ip_ptr); printf(" da msg da cxa saida.\n"); }//if #endif else{ const char* sendbuf = msg_ptr; int bytesSent = send( socDestino, sendbuf, strlen(sendbuf), 0);

151

printf( "Mensagem enviada ao destino com sucesso!! \n"); printf( "_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\n\n" ); excluiCaixaMensagem(ip_ptr, idmsg_ptr, porta_ptr); #ifndef unix closesocket(socDestino); #endif #ifdef unix close(socDestino); #endif }//else }//if }//for } #ifndef unix void Server::enviarMensagemErro(SOCKET s,string msg, CMSH cmshr){ string ipOrigem = cmshr.getSending_Facility(); sockaddr_in service; service.sin_family = AF_INET; service.sin_addr.s_addr = inet_addr(ipOrigem.c_str()); service.sin_port = htons( 27014 ); if (connect( s, (SOCKADDR*) &service, sizeof(service) ) == SOCKET_ERROR){ printf("Msg de erro enviado para caixa de Saida \n"); armazenarCaixaSaida(ipOrigem,"Servidor", msg, "27014", cmshr.getMessage_Control_ID()); } else{ printf("Msg de erro enviado para %s\n",ipOrigem.c_str()); const char* sendbuf = msg.c_str(); int bytesSent = send( s, sendbuf, strlen(sendbuf), 0 ); if (bytesSent < 0){ armazenarCaixaSaida(ipOrigem,"Servidor", msg, "27014", cmshr.getMessage_Control_ID()); } closesocket(s); }//else } #endif #ifdef unix void Server::enviarMensagemErroUnix(int soc,string msg, CMSH cmshr){ string ipOrigem = cmshr.getSending_Facility(); sockaddr_in service; service.sin_family = AF_INET; service.sin_addr.s_addr = inet_addr(ipOrigem.c_str()); service.sin_port = htons( 27014 ); if (connect( soc,(struct sockaddr*) &service, sizeof(service)) == -1){ printf("Msg de erro enviado para caixa de Saida \n"); armazenarCaixaSaida(ipOrigem,"Servidor", msg, "27014", cmshr.getMessage_Control_ID()); } else{ printf("Msg de erro enviado para %s\n",ipOrigem.c_str()); const char* sendbuf = msg.c_str(); int bytesSent = send( soc, sendbuf, strlen(sendbuf), 0 );

152

if (bytesSent < 0){ armazenarCaixaSaida(ipOrigem,"Servidor", msg, "27014", cmshr.getMessage_Control_ID()); } close(soc); }//else } #endif string Server::adicionarPortaNaMsgRecebida(string msg, string porta){ string mensagem = msg; int i = mensagem.find("||",0); mensagem.replace(i+1,0,porta); printf("\nPorta acrescentada na mensagem"); printf(mensagem.c_str()); printf("\n"); return mensagem; } void *receberMensagem(void * s){ #ifndef unix SOCKET soc = (SOCKET) s; #endif #ifdef unix int soc = (int) s; #endif Server *servidor = new Server(); int bytesRecv = -1; char recvbuf[3000] = ""; vector<Aplicacao> vetorAplic; bytesRecv = recv( soc, recvbuf, 3000, 0 ); if (bytesRecv > 0) { CMSH cmshr = servidor->validacaoMensagem(recvbuf); string aplicdestino = cmshr.getReceiving_Application(); string evento = cmshr.getMessage_Type_Event(); if (aplicdestino!= "" ){ vetorAplic = servidor->verificarDestino(aplicdestino, evento, cmshr.getSending_Facility(), cmshr.getSending_Application()); if (vetorAplic.size()>0){ printf("Mensagem recebida de %s\n",cmshr.getSending_Facility().c_str()); printf("Mensagem encaminhada para %s\n",aplicdestino.c_str()); printf( "_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\n\n" ); servidor->enviarMensagem((string)recvbuf,vetorAplic,cmshr); } else{ printf("Destino da msg recebida nao foi encontrado!\n"); #ifndef unix servidor->enviarMensagemErro(soc,"Aplicacao "+aplicdestino+ " inexistente./nConsulte o administrador do sistema.", cmshr); #endif #ifdef unix servidor->enviarMensagemErroUnix(soc,"Aplicacao "+aplicdestino+ " inexistente./nConsulte o administrador do sistema.", cmshr); #endif

153

}//else } //if }//if delete servidor; } #ifndef unix SOCKET Server::inicializar(){ // Inicializa Winsock. WSADATA wsaData; //inicia o socket, o MAKEWORD(2,2) encontra versão do winsocket int iResult = WSAStartup( MAKEWORD(2,2), &wsaData ); if ( iResult != NO_ERROR ) printf("Erro no WSAStartup()\n"); // Create a socket. SOCKET m_socket; m_socket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ); /*primeiro parametro é a familia, segundo é o tipo(TCP ou UDP e o terceiro eh o protocolo //associado a familia)*/ if ( m_socket == INVALID_SOCKET ) { printf( "Erro no socket(): %ld\n", WSAGetLastError() ); WSACleanup(); } sockaddr_in service; service.sin_family = AF_INET; service.sin_addr.s_addr = inet_addr(getEndIPLocal()); service.sin_port = htons( 27015 ); //bind associa o socket ao endereço if ( bind( m_socket,(SOCKADDR*)&service, sizeof(service)) == SOCKET_ERROR){ printf( "bind falhou.\n" ); closesocket(m_socket); } //lista o numero max de conexões aceitas pelo servidor if ( listen( m_socket, 1 ) == SOCKET_ERROR ) printf( "Erro listening do socket.\n"); return m_socket; } #endif #ifdef unix int Server::inicializarUnix(){ int m_socket; m_socket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ); //primeiro parametro é a familia, segundo é o tipo(TCP ou UDP) e o terceiro // é o protocolo associado a familia) if ( m_socket == -1 ) { printf( "Erro no socket \n"); } sockaddr_in service; service.sin_family = AF_INET;

154

service.sin_addr.s_addr = inet_addr(getEndIPLocal()); service.sin_port = htons( 27015 ); //bind associa o socket ao endereço if ( bind( m_socket, (struct sockaddr*) &service, sizeof(service)) == -1 ) { printf( "bind falhou.\n" ); close(m_socket); } //lista o numero max de conexões aceitas pelo servidor if ( listen( m_socket, 1 ) == -1 ) printf( "Erro listening do socket.\n"); return m_socket; } #endif void* controleCaixaDeSaida(void * i){ PGresult *res; Server *servidor = new Server(); time_t horainicial, horaatual, hora; time(&horainicial); hora = horainicial; time(&horaatual); //verifica caixa de saida se já se passaram 10 min da ultima verificação if (hora <= horaatual){ res = servidor->temMsgCaixaSaida(); if (PQntuples(res)>0){ printf("Envio msgs caixa de saida...\n"); servidor->envioMensagensCaixaSaida(res); //intervalo de tempo para verficar a caixa de saida. hora = horainicial+360; }//if }//if delete servidor; return 0; } void* ouvirConexoes(void * soc){ #ifndef unix SOCKET AcceptSocket; SOCKET m_socket = (SOCKET) soc; #endif #ifdef unix int AcceptSocket; int m_socket = (int) soc; #endif pthread_t threadCliente; int status; printf( "Aguardando conexao...\n" ); printf( "_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\n\n" ); //aguarda novas conexões AcceptSocket = accept( m_socket, NULL, NULL ); if (AcceptSocket != -1) {

155

int rc = pthread_create(&threadCliente, NULL, receberMensagem,(void *)AcceptSocket) ; rc = pthread_join(threadCliente, (void **)&status); if (rc){ printf("ERROR; return code from pthread_create de receberMensagem() %d\n", rc); exit(-1); }//if #ifndef unix closesocket(AcceptSocket); #endif #ifdef unix close(AcceptSocket); #endif }//if return 0; } int main(int argc,char *argv[]) { Server *servidor = new Server(); servidor->conectarBanco(); #ifndef unix SOCKET soc = servidor->inicializar(); #endif #ifdef unix int soc = servidor->inicializarUnix(); #endif //Criação do mutex if (pthread_mutex_init(&mutex, NULL) < 0) { perror("pthread_mutex_init"); exit(1); } pthread_attr_t attr; pthread_t threads[2]; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); while(true){ int rc1 = pthread_create(&threads[0],&attr,controleCaixaDeSaida,(void *)1); if (rc1){ printf("ERRO pthread_create() controleCaixaDeSaida eh %d\n", rc1); exit(-1); }//if int rc2 = pthread_create(&threads[1], &attr, ouvirConexoes, (void *)soc) ; if (rc2){ printf("ERRO pthread_create() ouvirConexoes eh %d\n", rc2); exit(-1); }//if for (int i = 0; i <2; i++) { pthread_join(threads[i], NULL); } }//while delete servidor; return 0; }

156

---------------------------------------Servidor.h (Aplicação Servidor)----------------------------- #ifndef Server_H #define Server_H #ifndef unix #ifndef WIN32 #define WIN32 #endif #endif #ifndef unix #include <winsock2.h> #include <stdlib.h> #include <string> #include <time.h> #endif #include <libpq-fe.h> #ifdef unix #include <ctype.h> // for isdigit #include <sys/types.h> // for connect(), bind(), accept(), #include <sys/socket.h> // for connect(), listen(), bind() accept(), #include <netinet/in.h> // for ntons(), htonl(), etc... #include <arpa/inet.h> // for inet_addre() #include <unistd.h> // for close(), read(), write() #include <netdb.h> // for gethostbyname #include <sys/time.h> // for timeval struct, and select() #include <string.h> // for memset() #include <map> // for STL map class (Reference counting) #endif #include <vector> #include "CMSH.h" using std::vector; using std::string; typedef struct Aplicacao{ string endIP; string porta; string aplicacaoNome; }Aplicacao; class Server{ public: //Retorna o IP da máquina local char* getEndIPLocal(); //verifica a porta da aplicação destino e adiciona na mensagem

157

string adicionarPortaNaMsgRecebida(string msg, string porta); //Método para verificar a consistência da mensagem HL7 CMSH validacaoMensagem(char *mensagem); //Encerra conexão com o banco void exit_nicely(); //Busca data e hora atual retornando um string no formato da data do postgres(YYMMDD) string getDataHoraAtual(); //Insere um registro na tabela Erros quando ocorrer erros: exclusão, qdo expirar mensagem da caixa de saída void inserirErroBanco(string msgErro); //realiza a conexão com o banco de dados postgres void conectarBanco(); //Verifica se o IP do destino da mensagem da caixa de saída é válido(encontra-se na tabela de configurações bool verificaIPDestino(string ip); //Retorna os IPs correspondentes a determinadas aplicações vector<Aplicacao> verificarDestino(string aplicacao, string evento, string ip, string aplicOrigem); //Insere valores referentes a mensagem na caixa de saída quando o destino não estiver on-line void armazenarCaixaSaida(string ipDestino, string ipRemetente, string msg, string porta, string idMsg); //Envia mensagem para o(s) IP(s) destino void enviarMensagem(string msg, vector<Aplicacao> ips, CMSH cmshr); //Ao enviar uma mensagem da caixa de saída exclui da tabela caixaSaida void excluiCaixaMensagem(char* ip, char* idmsg, char* porta); //Verifica se existem mensagens para serem enviadas na caixa de saída PGresult* temMsgCaixaSaida(); //Envia mensagem da caixaSaida void envioMensagensCaixaSaida(PGresult *res); //Envia mensagem de erro para o cliente que enviou uma mensagem com destino inválido #ifndef unix void enviarMensagemErro(SOCKET s,string msg, CMSH cmshr); #endif #ifdef unix void enviarMensagemErroUnix(int s,string msg, CMSH cmshr); #endif //Inicializa o socket #ifndef unix SOCKET inicializar(); #endif #ifdef unix int inicializarUnix(); #endif

158

}; //Thread para aceitar novas conexões com o servidor extern "C" void *ouvirConexoes(void * soc); //Thread para tentar enviar mensagens da caixa de saída após determinado tempo extern "C" void *controleCaixaDeSaida(void * i); //thread que recebe as mensagens enviadas através do socket extern "C" void *receberMensagem(void * s); #endif ---------------------------------------AnalysisError.h (Usado nas aplicações Servidor e Cliente)----------------------------- #ifndef ANALYSIS_ERROR_H #define ANALYSIS_ERROR_H #include <string> class AnalysisError { public: AnalysisError(const std::string &msg, int position = -1) : message(msg), position(position) { } const char *getMessage() const { return message.c_str(); } int getPosition() const { return position; } private: std::string message; int position; }; ---------------------------------------CDSP.cpp (Usado nas aplicações Servidor e Cliente)-------------------------- #include "CDSP.h" CDSP::CDSP(){ Segment_ID_DSP = ""; Display_Level =""; Data_Line=""; Logical_Break_Point=""; Result_ID=""; Fim_Linha=""; } void CDSP::setSegment_ID_DSP(string token){ Segment_ID_DSP = token; } string CDSP::getSegment_ID_DSP(){ return Segment_ID_DSP; }

159

void CDSP::setDisplay_Level(string token){ Display_Level = token; } string CDSP::getDisplay_Level(){ return Display_Level; } void CDSP::setData_Line(string token){ Data_Line = token; } string CDSP::getData_Line(){ return Data_Line; } void CDSP::setLogical_Break_Point(string token){ Logical_Break_Point = token; } string CDSP::getLogical_Break_Point(){ return Logical_Break_Point; } void CDSP::setResult_ID(string token){ Result_ID = token; } string CDSP::getResult_ID(){ return Result_ID; } void CDSP::setFim_Linha(string token){ Fim_Linha = token; } string CDSP::getFim_Linha(){ return Fim_Linha; } string CDSP::getDSP(){ return (Segment_ID_DSP + Display_Level+ Data_Line+ Logical_Break_Point+ Result_ID+ Fim_Linha); } ----------------------------------CEVN.cpp (Usado nos Aplicações Cliente e Servidor)----------------------------- include "CEVN.h" CEVN::CEVN(){ Segment_ID = ""; Event_Type_Code = ""; Recorded_Date_Time = ""; Date_Time_Planned_Event = ""; Event_Reason_Code = ""; Operator_ID = ""; Event_Occurred = "";

160

Fim_Linha = ""; } void CEVN::setSegment_ID(string token){ Segment_ID = token; } string CEVN::getSegment_ID(){ return Segment_ID; } void CEVN::setEvent_Type_Code (string token){ Event_Type_Code = token; } string CEVN::getEvent_Type_Code(){ return Event_Type_Code; } void CEVN::setRecorded_Date_Time (string token){ Recorded_Date_Time = token; } string CEVN::getRecorded_Date_Time(){ return Recorded_Date_Time; } void CEVN::setDate_Time_Planned_Event(string token){ Date_Time_Planned_Event = token; } string CEVN::getDate_Time_Planned_Event (){ return Date_Time_Planned_Event; } void CEVN::setEvent_Reason_Code(string token){ Event_Reason_Code = token; } string CEVN::getEvent_Reason_Code (){ return Event_Reason_Code; } void CEVN::setOperator_ID(string token){ Operator_ID = token; } string CEVN::getOperator_ID (){ return Operator_ID; }

161

void CEVN::setEvent_Occurred(string token){ Event_Occurred= token; } string CEVN::getEvent_Occurred (){ return Event_Occurred; } void CEVN::setFim_Linha(string token){ Fim_Linha = token; } string CEVN::getFim_Linha(){ return Fim_Linha; } string CEVN::getEVN(){ return (Segment_ID+ Event_Type_Code+Recorded_Date_Time +Date_Time_Planned_Event + Event_Reason_Code +Operator_ID + Event_Occurred + Fim_Linha); } ----------------------------------CMSA.cpp (Usado nos aplicações Cliente e Servidoror)--------------------------- #include "CMSA.h" CMSA::CMSA(){ Segment_ID = ""; Acknowledgment_Code= ""; Message_Control_ID = ""; Text_Message = ""; Expected_Sequence_Number= ""; Delayed_Acknowledgment_Type = ""; Error_Condition = ""; Fim_Linha= ""; } void CMSA::setSegment_ID (string token){ Segment_ID = token; } string CMSA::getSegment_ID(){ return Segment_ID; } void CMSA::setAcknowledgment_Code (string token){ Acknowledgment_Code = token; } string CMSA::getAcknowledgment_Code(){ return Acknowledgment_Code; } void CMSA::setMessage_Control_ID (string token){ Message_Control_ID = token;

162

} string CMSA::getMessage_Control_ID(){ return Message_Control_ID; } void CMSA::setText_Message (string token){ Text_Message = token; } string CMSA::getText_Message(){ return Text_Message; } void CMSA::setExpected_Sequence_Number (string token){ Expected_Sequence_Number = token; } string CMSA::getExpected_Sequence_Number(){ return Expected_Sequence_Number; } void CMSA::setDelayed_Acknowledgment_Type (string token){ Delayed_Acknowledgment_Type =token; } string CMSA::getDelayed_Acknowledgment_Type(){ return Delayed_Acknowledgment_Type ; } void CMSA::setError_Condition (string token){ Error_Condition = token; } string CMSA::getError_Condition(){ return Error_Condition; } void CMSA::setFim_Linha (string token){ Fim_Linha = token; } string CMSA::getFim_Linha(){ return Fim_Linha; } string CMSA::getMSA(){ return (Segment_ID + Acknowledgment_Code+ Message_Control_ID + Text_Message+ Expected_Sequence_Number + Delayed_Acknowledgment_Type +Error_Condition +Fim_Linha); } -----------------------------------CMSH.cpp (Usado nas aplicações Cliente e Servidor)----------------------------- #include "CMSH.h" CMSH::CMSH(){ Segment_ID = ""; Field_Separator = ""; Encoding_Caracters = ""; Sending_Application = ""; Sending_Facility = ""; Receiving_Application = ""; Receiving_Facility = "";

163

Date_Time_of_Message = ""; Security = ""; Message_Type_Event = ""; Message_Type_Segment = ""; Message_Control_ID = ""; Processing_ID = ""; Version_ID = ""; Fim_Linha = ""; } string CMSH::getSegment_ID(){ return Segment_ID; } void CMSH::setSegment_ID (string token){ Segment_ID = token; } void CMSH::setField_Separator(string token){ Field_Separator = token; } string CMSH::getField_Separator(){ return Field_Separator; } void CMSH::setEncoding_Caracters(string token){ Encoding_Caracters = token; } string CMSH::getEncoding_Caracters(){ return Encoding_Caracters; } void CMSH::setSending_Application(string token){ Sending_Application = token; } string CMSH::getSending_Application(){ return Sending_Application; } void CMSH::setSending_Facility (string token){ Sending_Facility = token; } string CMSH::getSending_Facility(){ return Sending_Facility; } void CMSH::setReceiving_Application (string token){ Receiving_Application = token; } string CMSH::getReceiving_Application (){ return Receiving_Application; } void CMSH::setReceiving_Facility (string token){ Receiving_Facility = token; } string CMSH::getReceiving_Facility (){ return Receiving_Facility; } void CMSH::setDate_Time_of_Message (string token){ Date_Time_of_Message = token; }

164

string CMSH::getDate_Time_of_Message(){ return Date_Time_of_Message; } void CMSH::setSecurity (string token){ Security = token; } string CMSH::getSecurity(){ return Security; } string CMSH::getMessage_Type(){ return (Message_Type_Event + " "+Message_Type_Segment); } void CMSH::setMessage_Type_Event (string token){ Message_Type_Event = token; } string CMSH::getMessage_Type_Event(){ return Message_Type_Event; } void CMSH::setMessage_Type_Segment (string token){ Message_Type_Segment = token; } string CMSH::getMessage_Type_Segment(){ return Message_Type_Segment; } void CMSH::setMessage_Control_ID (string token){ Message_Control_ID = token; } string CMSH::getMessage_Control_ID(){ return Message_Control_ID; } void CMSH::setProcessing_ID (string token){ Processing_ID = token; } string CMSH::getProcessing_ID(){ return Processing_ID; } void CMSH::setVersion_ID (string token){ Version_ID = token; } string CMSH::getVersion_ID(){ return Version_ID; } void CMSH::setFim_Linha(string token){ Fim_Linha = token; } string CMSH::getFim_Linha(){ return Fim_Linha; } string CMSH::getMSH(){ return (Segment_ID+Field_Separator+Encoding_Caracters+Sending_Application+ Sending_Facility+Receiving_Application+ Receiving_Facility+ Date_Time_of_Message+ Security+ Message_Type_Event+ Message_Type_Segment+ Message_Control_ID + Processing_ID + Version_ID + Fim_Linha); } ------------------------------------CPID.cpp (Usado nas aplicações Cliente e Servidor)-----------------------------

165

#include "CPID.h" CPID::CPID(){ Segment_ID = ""; Set_ID = ""; Patient_ID_External = ""; Patient_ID_Internal = ""; Alternate_Patient_ID = ""; Patient_Name = ""; Mother_Maiden_Name = ""; Date_Time_of_Birth = ""; Sex = ""; Patient_Alias = ""; Race = ""; Patient_Address = ""; County_Code = ""; Phone_Number_Home = ""; Phone_Number_Business = ""; Primary_Language = ""; Marital_Status = ""; Religion = ""; Patient_Account_Number = ""; SSN_Number = ""; Driver_License_Number = ""; Mother_Identifier = ""; Ethnic_Group = ""; Birth_Place = ""; Multiple_Birth_Indicator = ""; Birth_Order = ""; Citizenship = ""; Veterans_Military_Status = ""; Nationality = ""; Patient_Death_Date_and_Time = ""; Patient_Death_Indicator =""; } void CPID:: setSegment_ID (string token){ Segment_ID = token; } string CPID:: getSegment_ID(){ return Segment_ID; } void CPID:: setSet_ID (string token){ Set_ID = token; } string CPID:: getSet_ID (){ return Set_ID; } void CPID:: setPatient_ID_External (string token){ Patient_ID_External = token; } string CPID:: getPatient_ID_External(){ return Patient_ID_External; }

166

void CPID:: setPatient_ID_Internal (string token){ Patient_ID_Internal= token; } string CPID:: getPatient_ID_Internal(){ return Patient_ID_Internal; } void CPID:: setAlternate_Patient_ID (string token){ Alternate_Patient_ID = token; } string CPID:: getAlternate_Patient_ID(){ return Alternate_Patient_ID; } void CPID:: setPatient_Name (string token){ Patient_Name = token; } string CPID:: getPatient_Name(){ return Patient_Name; } void CPID:: setMother_Maiden_Name (string token){ Mother_Maiden_Name= token; } string CPID:: getMother_Maiden_Name(){ return Mother_Maiden_Name; } void CPID:: setDate_Time_of_Birth (string token){ Date_Time_of_Birth = token; } string CPID:: getDate_Time_of_Birth(){ return Date_Time_of_Birth; } void CPID:: setSex (string token){ Sex= token; } string CPID:: getSex(){ return Sex; } void CPID:: setPatient_Alias (string token){ Patient_Alias= token; } string CPID:: getPatient_Alias(){ return Patient_Alias; } void CPID:: setRace (string token){ Race = token; } string CPID:: getRace(){ return Race; } void CPID:: setPatient_Address (string token){ Patient_Address= token; } string CPID:: getPatient_Address(){ return Patient_Address; }

167

void CPID:: setCounty_Code (string token){ County_Code= token; } string CPID:: getCounty_Code(){ return County_Code; } void CPID:: setPhone_Number_Home (string token){ Phone_Number_Home = token; } string CPID:: getPhone_Number_Home(){ return Phone_Number_Home; } void CPID:: setPhone_Number_Business (string token){ Phone_Number_Business = token; } string CPID:: getPhone_Number_Business(){ return Phone_Number_Business; } void CPID:: setPrimary_Language (string token){ Primary_Language = token; } string CPID:: getPrimary_Language(){ return Primary_Language; } void CPID:: setMarital_Status (string token){ Marital_Status = token; } string CPID:: getMarital_Status(){ return Marital_Status ; } void CPID:: setReligion (string token){ Religion = token; } string CPID:: getReligion(){ return Religion; } void CPID:: setPatient_Account_Number (string token){ Patient_Account_Number = token; } string CPID:: getPatient_Account_Number(){ return Patient_Account_Number ; } void CPID:: setSSN_Number (string token){ SSN_Number= token; } string CPID:: getSSN_Number(){ return SSN_Number; } void CPID:: setDriver_License_Number (string token){ Driver_License_Number = token; } string CPID:: getDriver_License_Number(){ return Driver_License_Number ; }

168

void CPID:: setMother_Identifier (string token){ Mother_Identifier= token; } string CPID:: getMother_Identifier(){ return Mother_Identifier; } void CPID:: setEthnic_Group (string token){ Ethnic_Group = token; } string CPID:: getEthnic_Group(){ return Ethnic_Group ; } void CPID:: setBirth_Place (string token){ Birth_Place = token; } string CPID:: getBirth_Place(){ return Birth_Place ; } void CPID:: setMultiple_Birth_Indicator (string token){ Multiple_Birth_Indicator = token; } string CPID:: getMultiple_Birth_Indicator(){ return Multiple_Birth_Indicator; } void CPID:: setBirth_Order (string token){ Birth_Order = token; } string CPID:: getBirth_Order(){ return Birth_Order ; } void CPID:: setCitizenship (string token){ Citizenship= token; } string CPID:: getCitizenship(){ return Citizenship; } void CPID:: setVeterans_Military_Status (string token){ Veterans_Military_Status = token; } string CPID:: getVeterans_Military_Status(){ return Veterans_Military_Status ; } void CPID:: setNationality (string token){ Nationality = token; } string CPID:: getNationality(){ return Nationality ; } void CPID:: setPatient_Death_Date_and_Time (string token){ Patient_Death_Date_and_Time = token; } string CPID:: getPatient_Death_Date_and_Time(){ return Patient_Death_Date_and_Time ; } void CPID:: setPatient_Death_Indicator (string token){ Patient_Death_Indicator = token; }

169

string CPID:: getPatient_Death_Indicator(){ return Patient_Death_Indicator; } void CPID:: setFim_Linha (string token){ Fim_Linha = token; } string CPID:: getFim_Linha(){ return Fim_Linha; } string CPID:: getPID(){ return (Segment_ID+ Set_ID+ Patient_ID_External+ Patient_ID_Internal+ Alternate_Patient_ID+ Patient_Name+ Mother_Maiden_Name+ Date_Time_of_Birth+ Sex+ Patient_Alias+ Race+ Patient_Address+ County_Code+Phone_Number_Home+ Phone_Number_Business+ Primary_Language+ Marital_Status+ Religion+ Patient_Account_Number+ SSN_Number+Driver_License_Number+Mother_Identifier+ Ethnic_Group+ Birth_Place+ Multiple_Birth_Indicator+ Birth_Order+Citizenship+ Veterans_Military_Status+Nationality+Patient_Death_Date_and_Time+Patient_Death_Indicator+Fim_Linha); } -----------------------------------CQAK.cpp (Usado nas aplicações Cliente e Servidor)----------------------------- #include "CQAK.h" CQAK::CQAK(){ Segment_ID_QAK = ""; Query_Tag_QAK = ""; Query_Response_Status = ""; Fim_Linha = ""; } void CQAK::setSegment_ID_QAK(string token){ Segment_ID_QAK = token; } string CQAK::getSegment_ID_QAK(){ return Segment_ID_QAK; } void CQAK::setQuery_Tag_QAK(string token){ Query_Tag_QAK = token; } string CQAK::getQuery_Tag_QAK(){ return Query_Tag_QAK; } void CQAK::setQuery_Response_Status(string token){ Query_Response_Status = token; } string CQAK::getQuery_Response_Status(){ return Query_Response_Status; } void CQAK::setFim_Linha(string token){ Fim_Linha = token; } string CQAK::getFim_Linha(){ return Fim_Linha; }

170

string CQAK::getQAK(){ return (Segment_ID_QAK +Query_Tag_QAK+ Query_Response_Status+ Fim_Linha); } ----------------------------------CQRD.cpp (Usado nas aplicações Cliente e Servidor)----------------------------- #include "CQRD.h" CQRD::CQRD(){ Segment_ID = ""; Query_date_time = ""; Query_format_code= ""; Query_priority= ""; Query_ID= ""; Deferred_response_type= ""; Deferred_response_date_time= ""; Quantity_limited_request= ""; Who_subject_filter= ""; What_subject_filter= ""; What_department_data_code= ""; What_data_code_value_qualifier= ""; Query_results_level= ""; Fim_Linha = ""; } void CQRD::setSegment_ID(string token){ Segment_ID = token; } string CQRD::getSegment_ID(){ return Segment_ID; } void CQRD::setQuery_date_time(string token){ Query_date_time = token; } string CQRD::getQuery_date_time(){ return Query_date_time; } void CQRD::setQuery_format_code(string token){ Query_format_code = token; } string CQRD::getQuery_format_code(){ return Query_format_code; } void CQRD::setQuery_priority(string token){ Query_priority = token;} string CQRD::getQuery_priority(){ return Query_priority; } void CQRD::setQuery_ID(string token){ Query_ID= token; } string CQRD::getQuery_ID(){ return Query_ID; } void CQRD::setDeferred_response_type(string token){ Deferred_response_type= token; }

171

string CQRD::getDeferred_response_type(){ return Deferred_response_type; } void CQRD::setDeferred_response_date_time(string token){ Deferred_response_date_time= token; } string CQRD::getDeferred_response_date_time(){ return Deferred_response_date_time; } void CQRD::setQuantity_limited_request(string token){ Quantity_limited_request= token; } string CQRD::getQuantity_limited_request(){ return Quantity_limited_request; } void CQRD::setWho_subject_filter(string token){ Who_subject_filter= token; } string CQRD::getWho_subject_filter(){ return Who_subject_filter; } void CQRD::setWhat_subject_filter(string token){ What_subject_filter= token; } string CQRD::getWhat_subject_filter(){ return What_subject_filter; } void CQRD::setWhat_department_data_code(string token){ What_department_data_code= token; } string CQRD::getWhat_department_data_code(){ return What_department_data_code; } void CQRD::setWhat_data_code_value_qualifier(string token){ What_data_code_value_qualifier = token; } string CQRD::getWhat_data_code_value_qualifier(){ return What_data_code_value_qualifier; } void CQRD::setQuery_results_level(string token){ Query_results_level= token; } string CQRD::getQuery_results_level(){ return Query_results_level;} void CQRD::setFim_Linha(string token){ Fim_Linha = token; } string CQRD::getFim_Linha(){ return Fim_Linha; } string CQRD::getQRD(){ return (Segment_ID +Query_date_time+ Query_format_code+ Query_priority +Query_ID + Deferred_response_type+ Deferred_response_date_time+Quantity_limited_request+ Who_subject_filter+ What_subject_filter+ What_department_data_code+ What_data_code_value_qualifier+ Query_results_level+Fim_Linha); }

172

----------------------------------CQRF.cpp (Usado nas aplicações Servidor e Cliente)----------------------------- #include "CQRF.h" CQRF::CQRF(){ Segment_ID = ""; Where_Subject_Filter = ""; When_Data_Start_Date_Time = ""; When_Data_End_Date_Time = ""; What_User_Qualifier = ""; Other_QRY_Subject_Filter = ""; Which_Date_Time_Qualifier = ""; Which_Date_Time_Status_Qualifier = ""; Date_Time_Selection_Qualifier = ""; When_Quantity_Timing_Qualifier = ""; Fim_Linha = ""; } void CQRF::setSegment_ID(string token){ Segment_ID = token; } string CQRF::getSegment_ID(){ return Segment_ID ; } void CQRF::setWhere_Subject_Filter(string token){ Where_Subject_Filter = token; } string CQRF::getWhere_Subject_Filter(){ return Where_Subject_Filter; } void CQRF::setWhen_Data_Start_Date_Time(string token){ When_Data_Start_Date_Time= token; } string CQRF::getWhen_Data_Start_Date_Time(){ return When_Data_Start_Date_Time; } void CQRF::setWhen_Data_End_Date_Time(string token){ When_Data_End_Date_Time = token; } string CQRF::getWhen_Data_End_Date_Time(){ return When_Data_End_Date_Time; } void CQRF::setWhat_User_Qualifier(string token){ What_User_Qualifier= token; } string CQRF::getWhat_User_Qualifier(){ return What_User_Qualifier; } void CQRF::setOther_QRY_Subject_Filter(string token){ Other_QRY_Subject_Filter= token; } string CQRF::getOther_QRY_Subject_Filter(){ return Other_QRY_Subject_Filter; }

173

void CQRF::setWhich_Date_Time_Qualifier(string token){ Which_Date_Time_Qualifier= token; } string CQRF::getWhich_Date_Time_Qualifier(){ return Which_Date_Time_Qualifier; } void CQRF::setWhich_Date_Time_Status_Qualifier(string token){ Which_Date_Time_Status_Qualifier= token; } string CQRF::getWhich_Date_Time_Status_Qualifier(){ return Which_Date_Time_Status_Qualifier; } void CQRF::setDate_Time_Selection_Qualifier(string token){ Date_Time_Selection_Qualifier= token; } string CQRF::getDate_Time_Selection_Qualifier(){ return Date_Time_Selection_Qualifier; } void CQRF::setWhen_Quantity_Timing_Qualifier(string token){ When_Quantity_Timing_Qualifier= token; } string CQRF::getWhen_Quantity_Timing_Qualifier(){ return When_Quantity_Timing_Qualifier; } void CQRF::setFim_Linha(string token){ Fim_Linha = token; } string CQRF::getFim_Linha(){ return Fim_Linha; } string CQRF::getQRF(){ return (Where_Subject_Filter+ When_Data_Start_Date_Time + When_Data_End_Date_Time+ What_User_Qualifier + Other_QRY_Subject_Filter+ Which_Date_Time_Qualifier+ Which_Date_Time_Status_Qualifier+ Date_Time_Selection_Qualifier+ When_Quantity_Timing_Qualifier+ Fim_Linha); } ----------------------------------Lexico.cpp (Usado nas aplicações Servidor e Cliente)----------------------------- #include "Lexico.h" void Lexico::setInput(const char *input) { this->input = input; setPosition(0); } Token *Lexico::nextToken() throw (LexicalError) {

174

if ( ! hasInput() ) return 0; unsigned start = position; int state = 0; int oldState = 0; int endState = -1; int end = -1; while (hasInput()) { oldState = state; state = nextState(nextChar(), state); if (state < 0) break; else { if (tokenForState(state) >= 0) { endState = state; end = position; } } } if (endState < 0 || (endState != state && tokenForState(oldState) == -2)) throw LexicalError(SCANNER_ERROR[oldState], start); position = end; TokenId token = tokenForState(endState); if (token == 0) return nextToken(); else { std::string lexeme = input.substr(start, end-start); token = lookupToken(token, lexeme); return new Token(token, lexeme, start); } } int Lexico::nextState(unsigned char c, int state) const { int next = SCANNER_TABLE[state][c]; return next; } TokenId Lexico::tokenForState(int state) const { int token = -1; if (state >= 0 && state < STATES_COUNT) token = TOKEN_STATE[state];

175

return static_cast<TokenId>(token); } TokenId Lexico::lookupToken(TokenId base, const std::string &key) { int start = SPECIAL_CASES_INDEXES[base]; int end = SPECIAL_CASES_INDEXES[base+1]-1; while (start <= end) { int half = (start+end)/2; const std::string current = SPECIAL_CASES_KEYS[half]; if (current == key) return static_cast<TokenId>(SPECIAL_CASES_VALUES[half]); else if (current < key) start = half+1; else //(current > key) end = half-1; } return base; } -------------------------------Sintatico.cpp (Usado nas aplicações Servidor e Cliente)----------------------------- #include "Sintatico.h" void Sintatico::parse(Lexico *scanner, Semantico *semanticAnalyser) throw (AnalysisError) { this->scanner = scanner; this->semanticAnalyser = semanticAnalyser; //Limpa a pilha while (! stack.empty()) stack.pop(); stack.push(DOLLAR); stack.push(START_SYMBOL); if (previousToken != 0 && previousToken != currentToken) delete previousToken; previousToken = 0; if (currentToken != 0) delete currentToken; currentToken = scanner->nextToken(); while ( ! step() ) ; } bool Sintatico::step() throw (AnalysisError) { if (currentToken == 0) //Fim de Sentenca { int pos = 0; if (previousToken != 0) pos = previousToken->getPosition() + previousToken->getLexeme().size();

176

currentToken = new Token(DOLLAR, "$", pos); } int a = currentToken->getId(); int x = stack.top(); stack.pop(); if (x == EPSILON) { return false; } else if (isTerminal(x)) { if (x == a) { if (stack.empty()) return true; else { if (previousToken != 0) delete previousToken; previousToken = currentToken; currentToken = scanner->nextToken(); return false; } } else { throw SyntaticError(PARSER_ERROR[x], currentToken->getPosition()); } } else if (isNonTerminal(x)) { if (pushProduction(x, a)) return false; else throw SyntaticError(PARSER_ERROR[x], currentToken->getPosition()); } else // isSemanticAction(x) { semanticAnalyser->executeAction(x-FIRST_SEMANTIC_ACTION, previousToken); return false; } } bool Sintatico::pushProduction(int topStack, int tokenInput) { int p = PARSER_TABLE[topStack-FIRST_NON_TERMINAL][tokenInput-1]; if (p >= 0) { int *production = PRODUCTIONS[p]; //empilha a produção em ordem reversa int length = production[0]; for (int i=length; i>=1; i--)

177

{ stack.push( production[i] ); } return true; } else return false; } ------------------------------SemanticError.h (Usado nas aplicações Servidor e Cliente)------------------------- #ifndef SEMANTIC_ERROR_H #define SEMANTIC_ERROR_H #include "AnalysisError.h" #include <string> class SemanticError : public AnalysisError { public: SemanticError(const std::string &msg, int position = -1) : AnalysisError(msg, position) { } }; #endif -------------------------------SyntaticError.h (Usado nas aplicações Servidor e Cliente)-------------------------- #ifndef SYNTATIC_ERROR_H #define SYNTATIC_ERROR_H #include "AnalysisError.h" #include <string> class SyntaticError : public AnalysisError { public: SyntaticError(const std::string &msg, int position = -1) : AnalysisError(msg, position) { } };#endif -----------------------------------Token.h (Usado nas aplicações Servidor e Cliente)----------------------------- #ifndef TOKEN_H #define TOKEN_H #include "Constants.h" #include <string> class Token {

178

public: Token(TokenId id, const std::string &lexeme, int position) : id(id), lexeme(lexeme), position(position) { } TokenId getId() const { return id; } const std::string &getLexeme() const { return lexeme; } int getPosition() const { return position; } private: TokenId id; std::string lexeme; int position; }; #endif -----------------------------Semantico.cpp (Usado nas aplicações Servidor e Cliente)----------------------------- #include "Semantico.h" void Semantico::executeAction(int action, const Token *token) throw (SemanticError ){ switch (action){ case 01: executeAction01(token); break; case 02: executeAction02(token); break; case 03: executeAction03(token); break; case 04: executeAction04(token); break; case 05: executeAction05(token); break; case 06: executeAction06(token); break; case 07: executeAction07(token); break; case 8: executeAction08(token); break; case 9: executeAction09(token); break; case 10: executeAction10(token); break; case 1010: executeAction1010(token); break; case 11: executeAction11(token); break; case 12: executeAction12(token); break; case 13: executeAction13(token); break; case 14: executeAction14(token); break; case 15: executeAction15(token); break; case 16: executeAction16(token); break; case 17: executeAction17(token); break; case 18: executeAction18(token); break; case 19: executeAction19(token); break; case 20: executeAction20(token); break; case 21: executeAction21(token); break; case 22: executeAction22(token); break; case 23: executeAction23(token); break; case 24: executeAction24(token); break; case 25: executeAction25(token); break; case 26: executeAction26(token); break; case 27: executeAction27(token); break; case 28: executeAction28(token); break; case 29: executeAction29(token); break; case 30: executeAction30(token); break; case 31: executeAction31(token); break; case 32: executeAction32(token); break; case 33: executeAction33(token); break;

case 34: executeAction34(token); break; case 35: executeAction35(token); break; case 36: executeAction36(token); break; case 37: executeAction37(token); break; case 38: executeAction38(token); break; case 39: executeAction39(token); break; case 40: executeAction40(token); break; case 41: executeAction41(token); break; case 42: executeAction42(token); break; case 43: executeAction43(token); break; case 44: executeAction44(token); break; case 45: executeAction45(token); break; case 46: executeAction46(token); break; case 47: executeAction47(token); break; case 48: executeAction48(token); break; case 49: executeAction49(token); break; case 50: executeAction50(token); break; case 51: executeAction51(token); break; case 52: executeAction52(token); break; case 53: executeAction53(token); break; case 54: executeAction54(token); break; case 55: executeAction55(token); break; case 56: executeAction56(token); break; case 57: executeAction57(token); break; case 58: executeAction58(token); break; case 59: executeAction59(token); break; case 60: executeAction60(token); break; case 61: executeAction61(token); break; case 62: executeAction62(token); break; case 63: executeAction63(token); break; case 114: executeAction114(token); break; case 115: executeAction115(token); break; case 116: executeAction116(token); break; case 117: executeAction117(token); break;

179

case 118: executeAction118(token); break; case 119: executeAction119(token); break; case 120: executeAction120(token); break; case 121: executeAction121(token); break; case 122: executeAction122(token); break; case 123: executeAction123(token); break; case 124: executeAction124(token); break; case 125: executeAction125(token); break; case 126: executeAction126(token); break; case 127: executeAction127(token); break; case 128: executeAction128(token); break; case 129: executeAction129(token); break; case 130: executeAction130(token); break; case 131: executeAction131(token); break; case 132: executeAction132(token); break; case 133: executeAction133(token); break; case 134: executeAction134(token); break; case 135: executeAction135(token); break; case 136: executeAction136(token); break; case 137: executeAction137(token); break; case 138: executeAction138(token); break; case 160: executeAction160(token); break; case 161: executeAction161(token); break; case 162: executeAction162(token); break; case 163: executeAction163(token); break; case 164: executeAction164(token); break; case 165: executeAction165(token); break; case 174: executeAction174(token); break; case 175: executeAction175(token); break; case 176: executeAction176(token); break; case 1760: executeAction176(token); break;

180

} } void Semantico::executeAction01(const Token *token) throw (SemanticError ){ msh = new CMSH(); msh->setSegment_ID(token->getLexeme()); } void Semantico::executeAction02(const Token *token) throw (SemanticError ){ msh->setField_Separator(token->getLexeme()); } void Semantico::executeAction03(const Token *token) throw (SemanticError ){ msh->setEncoding_Caracters(msh->getEncoding_Caracters()+token->getLexeme()); } void Semantico::executeAction04(const Token *token) throw (SemanticError ){ msh->setSending_Application(msh->getSending_Application()+token->getLexeme()); } void Semantico::executeAction05(const Token *token) throw (SemanticError ){ msh->setSending_Facility(msh->getSending_Facility()+token->getLexeme()); } void Semantico::executeAction06(const Token *token) throw (SemanticError ){ msh->setReceiving_Application(msh->getReceiving_Application()+ token->getLexeme()); } void Semantico::executeAction07(const Token *token) throw (SemanticError ){ msh->setReceiving_Facility(msh->getReceiving_Facility()+ token->getLexeme()); } void Semantico::executeAction08(const Token *token) throw (SemanticError ){ msh->setDate_Time_of_Message(msh->getDate_Time_of_Message()+token->getLexeme()); } void Semantico::executeAction09(const Token *token) throw (SemanticError ){ msh->setSecurity(msh->getSecurity()+token->getLexeme()); } void Semantico::executeAction10(const Token *token) throw (SemanticError ){ msh->setMessage_Type_Event(msh->getMessage_Type_Event()+token->getLexeme()); } void Semantico::executeAction1010(const Token *token) throw (SemanticError ){ msh->setMessage_Type_Segment(msh->getMessage_Type_Segment()+token->getLexeme()); } void Semantico::executeAction11(const Token *token) throw (SemanticError ){ msh->setMessage_Control_ID(msh->getMessage_Control_ID()+token->getLexeme()); } void Semantico::executeAction12(const Token *token) throw (SemanticError ){ msh->setProcessing_ID(msh->getProcessing_ID()+token->getLexeme()); } void Semantico::executeAction13(const Token *token) throw (SemanticError ){ msh->setVersion_ID(token->getLexeme()); }

181

void Semantico::executeAction14(const Token *token) throw (SemanticError ){ msh->setFim_Linha(token->getLexeme()); } void Semantico::executeAction15(const Token *token) throw (SemanticError ){ if (pid== NULL ){ pid = new CPID(); } pid->setSegment_ID(pid->getSegment_ID()+token->getLexeme()); } void Semantico::executeAction16(const Token *token) throw (SemanticError ){ pid->setSet_ID(pid->getSet_ID()+token->getLexeme()); } void Semantico::executeAction17(const Token *token) throw (SemanticError ){ pid->setPatient_ID_External(pid->getPatient_ID_External()+token->getLexeme()); } void Semantico::executeAction18(const Token *token) throw (SemanticError ){ pid->setPatient_ID_Internal(pid->getPatient_ID_Internal()+token->getLexeme()); } void Semantico::executeAction19(const Token *token) throw (SemanticError ){ pid->setAlternate_Patient_ID(pid->getAlternate_Patient_ID()+token->getLexeme()); } void Semantico::executeAction20(const Token *token) throw (SemanticError ){ pid->setPatient_Name(pid->getPatient_Name()+token->getLexeme()); } void Semantico::executeAction21(const Token *token) throw (SemanticError ){ pid->setMother_Maiden_Name(pid->getMother_Maiden_Name()+token->getLexeme()); } void Semantico::executeAction22(const Token *token) throw (SemanticError ){ pid->setDate_Time_of_Birth(pid->getDate_Time_of_Birth()+token->getLexeme()); } void Semantico::executeAction23(const Token *token) throw (SemanticError ){ pid->setSex(pid->getSex()+token->getLexeme()); } void Semantico::executeAction24(const Token *token) throw (SemanticError ){ pid->setPatient_Alias(pid->getPatient_Alias() + token->getLexeme()); } void Semantico::executeAction25(const Token *token) throw (SemanticError ){ pid->setRace(pid->getRace()+token->getLexeme()); } void Semantico::executeAction26(const Token *token) throw (SemanticError ){ pid->setPatient_Address(pid->getPatient_Address()+token->getLexeme()); } void Semantico::executeAction27(const Token *token) throw (SemanticError ){ pid->setCounty_Code(pid->getCounty_Code()+token->getLexeme()); }

182

void Semantico::executeAction28(const Token *token) throw (SemanticError ){ pid->setPhone_Number_Home(pid->getPhone_Number_Home()+token->getLexeme()); } void Semantico::executeAction29(const Token *token) throw (SemanticError ){ pid->setPhone_Number_Business(pid->getPhone_Number_Business()+token->getLexeme()); } void Semantico::executeAction30(const Token *token) throw (SemanticError ){ pid->setPrimary_Language(pid->getPrimary_Language()+token->getLexeme()); } void Semantico::executeAction31(const Token *token) throw (SemanticError ){ pid->setMarital_Status(pid->getMarital_Status()+token->getLexeme()); } void Semantico::executeAction32(const Token *token) throw (SemanticError ){ pid->setReligion(pid->getReligion()+token->getLexeme()); } void Semantico::executeAction33(const Token *token) throw (SemanticError ){ pid->setPatient_Account_Number(pid->getPatient_Account_Number()+token->getLexeme()); } void Semantico::executeAction34(const Token *token) throw (SemanticError ){ pid->setSSN_Number(pid->getSSN_Number()+token->getLexeme()); } void Semantico::executeAction35(const Token *token) throw (SemanticError ){ pid->setDriver_License_Number(pid->getDriver_License_Number()+token->getLexeme()); } void Semantico::executeAction36(const Token *token) throw (SemanticError ){ pid->setMother_Identifier(pid->getMother_Identifier()+token->getLexeme()); } void Semantico::executeAction37(const Token *token) throw (SemanticError ){ pid->setEthnic_Group(pid->getEthnic_Group()+token->getLexeme()); } void Semantico::executeAction38(const Token *token) throw (SemanticError ){ pid->setBirth_Place(pid->getBirth_Place()+token->getLexeme()); } void Semantico::executeAction39(const Token *token) throw (SemanticError ){ pid->setMultiple_Birth_Indicator(pid->getMultiple_Birth_Indicator()+token->getLexeme()); } void Semantico::executeAction40(const Token *token) throw (SemanticError ){ pid->setBirth_Order(pid->getBirth_Order()+token->getLexeme()); } void Semantico::executeAction41(const Token *token) throw (SemanticError ){ pid->setCitizenship(pid->getCitizenship()+token->getLexeme()); } void Semantico::executeAction42(const Token *token) throw (SemanticError ){

183

pid->setVeterans_Military_Status(pid->getVeterans_Military_Status()+token->getLexeme()); } void Semantico::executeAction43(const Token *token) throw (SemanticError ){ pid->setNationality(pid->getNationality()+token->getLexeme()); } void Semantico::executeAction44(const Token *token) throw (SemanticError ){ pid->setPatient_Death_Date_and_Time(pid->getPatient_Death_Date_and_Time()+token->getLexeme()); } void Semantico::executeAction45(const Token *token) throw (SemanticError ){ pid->setPatient_Death_Indicator(pid->getPatient_Death_Indicator()+token->getLexeme()); } void Semantico::executeAction46(const Token *token) throw (SemanticError ){ pid->setFim_Linha(token->getLexeme()); } void Semantico::executeAction47(const Token *token) throw (SemanticError ){ evn = new CEVN(); evn->setSegment_ID(evn->getSegment_ID()+token->getLexeme()); } void Semantico::executeAction48(const Token *token) throw (SemanticError ){ evn->setEvent_Type_Code(evn->getEvent_Type_Code()+token->getLexeme()); } void Semantico::executeAction49(const Token *token) throw (SemanticError ){ evn->setRecorded_Date_Time(evn->getRecorded_Date_Time()+token->getLexeme()); } void Semantico::executeAction50(const Token *token) throw (SemanticError ){ evn->setDate_Time_Planned_Event(evn->getDate_Time_Planned_Event()+token->getLexeme()); } void Semantico::executeAction51(const Token *token) throw (SemanticError ){ evn->setEvent_Reason_Code(evn->getEvent_Reason_Code()+token->getLexeme()); } void Semantico::executeAction52(const Token *token) throw (SemanticError ){ evn->setOperator_ID(evn->getOperator_ID()+token->getLexeme()); } void Semantico::executeAction53(const Token *token) throw (SemanticError ){ evn->setEvent_Occurred(evn->getEvent_Occurred()+token->getLexeme()); } void Semantico::executeAction54(const Token *token) throw (SemanticError ){ evn->setFim_Linha(token->getLexeme()); } void Semantico::executeAction55(const Token *token) throw (SemanticError ){ if (msa== NULL){ msa= new CMSA(); } msa->setSegment_ID(msa->getSegment_ID()+token->getLexeme()); }

184

void Semantico::executeAction56(const Token *token) throw (SemanticError ){ msa->setAcknowledgment_Code(msa->getAcknowledgment_Code()+token->getLexeme()); } void Semantico::executeAction57(const Token *token) throw (SemanticError ){ msa->setMessage_Control_ID(msa->getMessage_Control_ID()+token->getLexeme()); } void Semantico::executeAction58(const Token *token) throw (SemanticError ){ msa->setText_Message(msa->getText_Message()+token->getLexeme()); } void Semantico::executeAction59(const Token *token) throw (SemanticError ){ msa->setExpected_Sequence_Number(msa->getExpected_Sequence_Number()+token->getLexeme()); } void Semantico::executeAction60(const Token *token) throw (SemanticError ){ msa->setDelayed_Acknowledgment_Type(msa->getDelayed_Acknowledgment_Type()+token->getLexeme()); } void Semantico::executeAction61(const Token *token) throw (SemanticError ){ msa->setError_Condition(msa->getError_Condition()+token->getLexeme()); } void Semantico::executeAction62(const Token *token) throw (SemanticError ){ msa->setFim_Linha(token->getLexeme()); } void Semantico::executeAction114(const Token *token) throw (SemanticError ){ if (qrd== NULL){ qrd= new CQRD(); } qrd->setSegment_ID(qrd->getSegment_ID()+token->getLexeme()); } void Semantico::executeAction115(const Token *token) throw (SemanticError ){ qrd->setQuery_date_time(qrd->getQuery_date_time()+token->getLexeme()); } void Semantico::executeAction116(const Token *token) throw (SemanticError ){ qrd->setQuery_format_code(qrd->getQuery_format_code()+token->getLexeme()); } void Semantico::executeAction117(const Token *token) throw (SemanticError ){ qrd->setQuery_priority(qrd->getQuery_priority()+token->getLexeme()); } void Semantico::executeAction118(const Token *token) throw (SemanticError ){ qrd->setQuery_ID(qrd->getQuery_ID()+token->getLexeme()); } void Semantico::executeAction119(const Token *token) throw (SemanticError ){ qrd->setDeferred_response_type(qrd->getDeferred_response_type()+token->getLexeme()); }

185

void Semantico::executeAction120(const Token *token) throw (SemanticError ){ qrd->setDeferred_response_date_time(qrd->getDeferred_response_date_time()+token->getLexeme()); } void Semantico::executeAction121(const Token *token) throw (SemanticError ){ qrd->setQuantity_limited_request(qrd->getQuantity_limited_request()+token->getLexeme()); } void Semantico::executeAction122(const Token *token) throw (SemanticError ){ qrd->setWho_subject_filter(qrd->getWho_subject_filter()+token->getLexeme()); } void Semantico::executeAction123(const Token *token) throw (SemanticError ){ qrd->setWhat_subject_filter(qrd->getWhat_subject_filter()+token->getLexeme()); } void Semantico::executeAction124(const Token *token) throw (SemanticError ){ qrd->setWhat_department_data_code(qrd->getWhat_department_data_code()+token->getLexeme()); } void Semantico::executeAction125(const Token *token) throw (SemanticError ){ qrd->setWhat_data_code_value_qualifier(qrd->getWhat_data_code_value_qualifier()+

token->getLexeme()); } void Semantico::executeAction126(const Token *token) throw (SemanticError ){ qrd->setQuery_results_level(qrd->getQuery_results_level()+token->getLexeme()); } void Semantico::executeAction127(const Token *token) throw (SemanticError ){ qrd->setFim_Linha(token->getLexeme()); } void Semantico::executeAction128(const Token *token) throw (SemanticError ){ qrf= new CQRF(); qrf->setSegment_ID(qrf->getSegment_ID()+token->getLexeme()); } void Semantico::executeAction129(const Token *token) throw (SemanticError ){ qrf->setWhere_Subject_Filter(qrf->getWhere_Subject_Filter()+token->getLexeme()); } void Semantico::executeAction130(const Token *token) throw (SemanticError ){ qrf->setWhen_Data_Start_Date_Time(qrf->getWhen_Data_Start_Date_Time()+token->getLexeme()); } void Semantico::executeAction131(const Token *token) throw (SemanticError ){ qrf->setWhen_Data_End_Date_Time(qrf->getWhen_Data_End_Date_Time()+token->getLexeme()); } void Semantico::executeAction132(const Token *token) throw (SemanticError ){ qrf->setWhat_User_Qualifier(qrf->getWhat_User_Qualifier()+token->getLexeme()); } void Semantico::executeAction133(const Token *token) throw (SemanticError ){ qrf->setOther_QRY_Subject_Filter(qrf->getOther_QRY_Subject_Filter()+token->getLexeme()); }

186

void Semantico::executeAction134(const Token *token) throw (SemanticError ){ qrf->setWhich_Date_Time_Qualifier(qrf->getWhich_Date_Time_Qualifier()+token->getLexeme()); } void Semantico::executeAction135(const Token *token) throw (SemanticError ){ qrf->setWhich_Date_Time_Status_Qualifier(qrf->getWhich_Date_Time_Status_Qualifier()+token->getLexeme()); } void Semantico::executeAction136(const Token *token) throw (SemanticError ){ qrf->setDate_Time_Selection_Qualifier(qrf->getDate_Time_Selection_Qualifier()+token->getLexeme()); } void Semantico::executeAction137(const Token *token) throw (SemanticError ){ qrf->setWhen_Quantity_Timing_Qualifier(qrf->getWhen_Quantity_Timing_Qualifier()+token->getLexeme()); } void Semantico::executeAction138(const Token *token) throw (SemanticError ){ qrf->setFim_Linha(token->getLexeme()); } void Semantico::executeAction160(const Token *token) throw (SemanticError ){ dsp= CDSP(); dsp.setSegment_ID_DSP(dsp.getSegment_ID_DSP()+token->getLexeme()); } void Semantico::executeAction161(const Token *token) throw (SemanticError ){ dsp.setDisplay_Level(dsp.getDisplay_Level()+token->getLexeme()); } void Semantico::executeAction162(const Token *token) throw (SemanticError ){ dsp.setData_Line(dsp.getData_Line()+token->getLexeme()); } void Semantico::executeAction163(const Token *token) throw (SemanticError ){ dsp.setLogical_Break_Point(dsp.getLogical_Break_Point()+token->getLexeme()); } void Semantico::executeAction164(const Token *token) throw (SemanticError ){ dsp.setResult_ID(dsp.getResult_ID()+token->getLexeme()); } void Semantico::executeAction165(const Token *token) throw (SemanticError ){ dsp.setFim_Linha(token->getLexeme()); vetorDSP.push_back(dsp); } void Semantico::executeAction173(const Token *token) throw (SemanticError ){ if (qak== NULL){ qak= new CQAK(); } qak->setSegment_ID_QAK(qak->getSegment_ID_QAK()+token->getLexeme()); } void Semantico::executeAction174(const Token *token) throw (SemanticError ){ qak->setQuery_Tag_QAK(qak->getQuery_Tag_QAK()+ token->getLexeme()); }

187

void Semantico::executeAction175(const Token *token) throw (SemanticError ){ qak->setQuery_Response_Status(qak->getQuery_Response_Status()+token->getLexeme()); } void Semantico::executeAction176(const Token *token) throw (SemanticError ){ qak->setFim_Linha(token->getLexeme()); } CMSH Semantico::enviaObjetoMSH(){ return *msh; } CEVN Semantico::enviaObjetoEVN(){ return *evn; } CPID Semantico::enviaObjetoPID(){ return *pid; } CMSA Semantico::enviaObjetoMSA(){ return *msa; } CQRD Semantico::enviaObjetoQRD(){ return *qrd; } CQRF Semantico::enviaObjetoQRF(){ return *qrf; } vector<CDSP> Semantico::enviaObjetoDSP(){ return vetorDSP; } CQAK Semantico::enviaObjetoQAK(){ return *qak; }