Page History
...
NXRG - Design- og arkitekturbeskrivelse
TODO: skrive hvad slet er først, og anvend så det istedet for deprecated.
Indledning
Formål
Dokumentdeling gør det muligt for aktører sundhedsvæsnet at dele relevante data om borgere, og dermed skabe et overblik over den enkelte borgers situation for de aktører som har brug for dette. Det kan være dem, som planlægger og gennemfører behandlingsforløb eller for borgerens selv og omsorgspersoner. Samtidig skal det være muligt for borgeren at bestemme, hvem han/hun vil dele disse data med gennem samtykke samt se, hvem der har læst data via MinLog. Infrastrukturen der muliggør deling af dokumenter på tværs af sundhedsaktører er baseret på IHE XDS standarden
...
| Code Block | ||||
|---|---|---|---|---|
| ||||
<ns2:Classification classificationScheme="urn:uuid:f4f85eac-e6cb-4883-b524-f2705394840f" classifiedObject="urn:uuid:69d3b9f3-7919-40e0-8731-32fb339216c2" nodeRepresentation="N" id="urn:uuid:9068bc2b-1717-4337-abfb-027f303b20c6">
<ns2:Slot name="codingScheme">
<ns2:ValueList>
<ns2:Value>2.16.840.1.113883.5.25</ns2:Value>
</ns2:ValueList>
</ns2:Slot>
<ns2:Name>
<ns2:LocalizedString xml:lang="en-US" charset="UTF-8" value="N"/>
</ns2:Name>
</ns2:Classification>
<ns2:ExternalIdentifier registryObject="urn:uuid:69d3b9f3-7919-40e0-8731-32fb339216c2" identificationScheme="urn:uuid:58a6f841-87b3-4a3e-92fd-a8ffeff98427" value="2512489996^^^&1.2.208.176.1.2&ISO" id="urn:uuid:6dc240d8-d871-4df1-b8c6-3414f1415022">
<ns2:Name>
<ns2:LocalizedString value="XDSDocumentEntry.patientId"/>
</ns2:Name>
</ns2:ExternalIdentifier> |
Det følgende er eksempelkode til at illustrere et ITI-41 kald til oprettelse af et dokument
Vigtige Objekter og attributer
TODO: bedre overskrift
Når man arbejder med OpeneHealth core model er der nogle centrale klasser/objekter man arbejder med. 3 af dem er SubmissionSet, DocumentEntry og Relation:
| Gliffy Diagram | ||||||||
|---|---|---|---|---|---|---|---|---|
|
(Simplificert figur efter figur 4.1-1 i ITI TF-3. Da man på NSP ikke arbejder med folders er disse elementer udeladt)
Man anvender submissionSet når man sender data ind (dvs ikke til søgninger). Et submissionSet pakker et kald ind. Indholdet af et submissionSet er documententries og associations. Opretter man nye dokumenter, vil der i et submissionset være en eller flere documentEntries (et for hvert dokument) og tilsvarende antal "SE-DE HasMember" associationer. Tilsvarende gælder for ret dokument. Men her vil der yderligere være en "Relationship" association af typen "replace". Deprecater man et dokument, har man ikke en docuemntEntry, men en "Relationship" association af typen "update availability status".
Når man opretter et documentEntry skal der sættes et entryUuid på. Dette id er vigtigt, da det anvendes i forbindelse med senere ret og deprecate af dokumentet. Det skal have prefix "urn:uuid:" for at være et entryUuid, ellers vil det blive opfattet som et symbolsk id, og den kaldte komponent vil selv tildele et gyldigt entryUuid.
Når man udfylder documentEntry med metadata skal man huske de førnævnte CDA standarder.
I forbindelse med, at man opretter associationer, skal der angives en source og target entryuuid, udover associationens egen entryUuid. Her gælder
- For opret af dokumenter: source er submissionSet entryUuid og target er documentEntry's entryUuid
- For ret, som for opret. Men den ekstra "replace" association er source nye dokuments entryUuid og target det gamle dokument
- For slet: source er submissionSet entryUuid og target er entryUuid for det dokument som skal deprecates
TODO: hvilke id'er er vigtige ud over de nævne?
Når man laver en fremsøgning med ITI-18 kan man få to typer af objekter tilbage basert på den return type man sætter i kaldet.
- LEAF_CLASS: her returnes en liste af matchende documentEntry
- OBJECT_REF: her returnes en liste af objekt referencer
TODO: debug nxrg og se faktisk lister
Eksempler på kald
Det følgende er eksempelkode til at illustrere et ITI-41 kald til oprettelse af et dokument
| Code Block | ||||||||
|---|---|---|---|---|---|---|---|---|
| ||||||||
// Nyt kald/request
ProvideAndRegisterDocumentSet provideAndRegisterDocumentSet = new ProvideAndRegisterDocumentSet();
// Opret documentEntry
DocumentEntry documentEntry = new DocumentEntry();
AssigningAuthority patientIdAssigningAuthority = new AssigningAuthority("1.2.208.176.1.2"); // OID for CPR registret
Identifiable patientIdentifiable = patientIdentifiable = new Identifiable("2512489996", patientIdAssigningAuthority);
documentEntry.setPatientId(patientIdentifiable);
... mere metadata, se CDA profilen
// Tilføj dokumentet til request
provideAndRegisterDocumentSet.getDocuments().add(new Document(documentEntry, new DataHandler(new ByteArrayDataSource(documentPayload.getBytes(), documentEntry. | ||||||||
| Code Block | ||||||||
| ||||||||
// Nyt kald/request
ProvideAndRegisterDocumentSet provideAndRegisterDocumentSet = new ProvideAndRegisterDocumentSet();
// Opret documentEntry
DocumentEntry documentEntry = new DocumentEntry();
AssigningAuthority patientIdAssigningAuthority = new AssigningAuthority("1.2.208.176.1.2"); // OID for CPR registret
Identifiable patientIdentifiable = patientIdentifiable = new Identifiable("2512489996", patientIdAssigningAuthority);
documentEntry.setPatientId(patientIdentifiable);
... mere metadata, se CDA profilen
// Tilføj dokumentet til request
provideAndRegisterDocumentSet.getDocuments().add(new Document(documentEntry, new DataHandler(new ByteArrayDataSource(documentPayload.getBytes(), documentEntry.getMimeType()))));
// Opret SubmissionSet
provideAndRegisterDocumentSet.setSubmissionSet(createSubmissionSet(documentEntry.getPatientId(), contentTypeCode, submissionTime));
// Opret association mellem SubmissionSet og DocumentEntry
provideAndRegisterDocumentSet.getAssociations().add(createAssociation(submissionSet, documentEntry));
// Transformer request - dette laver core model om til RIM format
ProvideAndRegisterDocumentSetTransformer registerDocumentSetTransformer = new ProvideAndRegisterDocumentSetTransformer(ebXMLFactory);
EbXMLProvideAndRegisterDocumentSetRequest30 ebxmlRequest = (EbXMLProvideAndRegisterDocumentSetRequest30) registerDocumentSetTransformer.toEbXML(provideAndRegisterDocumentSet);
ProvideAndRegisterDocumentSetRequestType provideAndRegisterDocumentSetRequestType = ebxmlRequest.getInternal();
// Udfør kald
RegistryResponseType registryResponse = iti41PortType.documentRepositoryProvideAndRegisterDocumentSetB(provideAndRegisterDocumentSetRequestType);
// Transformer response - dette laver RIM format til core model
ResponseTransformer responseTransformer = new ResponseTransformer(ebXMLFactory);
Response response = responseTransformer.fromEbXML(new EbXMLRegistryResponse30(registryResponse));
// Aflæs kaldets svar
if (response.getStatus().equals(Status.SUCCESS)) {
// Kaldet gik godt
} else
if (response.getStatus().equals(Status.PARTIAL_SUCCESS) || response.getStatus().equals(Status.FAILURE)) {
// Der er warning eller fejl i kaldet, håndter dem
for (ErrorInfo error : response.getErrors()) {
}
} |
(Det er flere detaljer omkring ITI-41 eksempelkode i anvender guiden til DROS.)TODO map til tegning)
Et tilsvarende eksempel for ITI-18 fremsøgning kunne se således ud:
| Code Block | ||||||||
|---|---|---|---|---|---|---|---|---|
| ||||||||
// Nyt kald/request
FindDocumentsQuery findDocumentsQuery = new FindDocumentsQuery();
// Opret søge kriterier
AssigningAuthority patientIdAssigningAuthority = new AssigningAuthority("1.2.208.176.1.2"); // OID for CPR registret
Identifiable patientIdentifiable = patientIdentifiable = new Identifiable("2512489996", patientIdAssigningAuthority);
findDocumentsQuery.setPatientId(patientIdentifiable); // angiv patienten dokumenterne vedrører
List<AvailabilityStatus> searchStatusList = new LinkedList<AvailabilityStatus>();
searchStatusList.add(AvailabilityStatus.APPROVED);
findDocumentsQuery.setStatus(searchStatusList); // søg efter dokumenter, som har status approved
findDocumentsQuery.getServiceStartTime().setFrom(serviceStartTimeFrom); // søg efter specifik dato interval som start tidspunkt
findDocumentsQuery.getServiceStartTime().setTo(serviceStartTimeTo); // ved at angive fra og til serviceStartTime
QueryRegistry queryRegistry = new QueryRegistry(findDocumentsQuery);
queryRegistry.setReturnType(QueryReturnType.LEAF_CLASS); //returner fuld metadata for de fremsøgte dokumenter
// Transformer request - dette laver core model om til RIM format
QueryRegistryTransformer requestTransformer = new QueryRegistryTransformer();
EbXMLAdhocQueryRequest30 ebxmlRequest = (EbXMLAdhocQueryRequest30) requestTransformer.toEbXML(queryRegistry);
AdhocQueryRequest adhocQueryRequest = ebxmlRequest.getInternal();
// Udfør kald
AdhocQueryResponse adhocQueryResponse = iti18PortType.documentRegistryRegistryStoredQuery(adhocQueryRequest
AdhocQueryResponse adhocQueryResponse = iti18PortType.documentRegistryRegistryStoredQuery(adhocQueryRequest);
// Transformer response - dette laver RIM format til core model
QueryResponseTransformer responseTransformer = new QueryResponseTransformer(ebXMLFactory);
EbXMLQueryResponse ebXML = new EbXMLQueryResponse30(adhocQueryResponse);
QueryResponse queryResponse = responseTransformer.fromEbXML(ebXML);
// TransformerAflæs responsekaldets - dette laver RIM format til core model
QueryResponseTransformer responseTransformer = new QueryResponseTransformer(ebXMLFactory);
EbXMLQueryResponse ebXML = new EbXMLQueryResponse30(adhocQueryResponse);
QueryResponse queryResponse = responseTransformer.fromEbXML(ebXML);
// Aflæs kaldets svarsvar
if (queryResponse.getStatus().equals(Status.SUCCESS)) {
// Kaldet gik godt, håndter de fremsøgte dokumenter metadata
for (DocumentEntry documentEntry : queryResponse.getDocumentEntries()) {
}
} else
if (queryResponse.getStatus().equals(Status.PARTIAL_SUCCESS) || queryResponse.getStatus().equals(Status.FAILURE)) {
// Kaldet gik godt Der er warning eller fejl i kaldet, håndter de fremsøgte dokumenter metadatadem
for (DocumentEntryErrorInfo documentEntryerror : queryResponse.getDocumentEntriesgetErrors()) {
}
} else
if (queryResponse.getStatus().equals(Status.PARTIAL_SUCCESS) || queryResponse.getStatus().equals(Status.FAILURE)) {
// Der er warning eller fejl i kaldet, håndter dem
for (ErrorInfo error : queryResponse.getErrors()) {
}
}
|
evt. request resspone
eksempler på brug af librariet (hvilke objekter og hvilke id'er skal man tage stillinger)
ise det resulterende "RIM XML" så man forstår sammenhængen.
noget af det kan tages dros anvender guide
evt nævn logiske id'er og hvad der sker hvis man tror man sender et uuuid men ikke gør.
gode steder at kigge: integrationstestene og anvender guides for komponenterne
husk at nævne overholdes af medcom standard for metadata i documententry
...
|
Sammenholder man ovenståede kodeekspempler kan man genkende ovenstående transformeringsfigurs kasser i kodelinierne. Eksempelvis for ITI-41 kaldet, hvor line 1-18 svarer til boks 2 (core model), linie 20-23 til boks 2 og 3 (core model og RIM format), linie 26 til kaldet mellem boks 3 (RIM format) og NSP komponenten, linie 28-30 til boks 3 og 2 (RIM format og core model) samt linie 32-40 til boks 2 (core model)
Savner man inspiration til kodeeksempler er også integrationstestene til f.eks. DROS og NXRG et godt sted at kigge.
TODO: indsæt requst og response på iti41 og 18
Biblioteker til .Net
TODO: find noget
https://www.iheusa.org/sites/iheusa/files/IHE%20Profiles%20for%20Health%20Information%20Exchange.pdf
https://groups.google.com/g/ihe-north-america-connectathon-2007/c/dLNk8mWoMVY
Hjælpeværktøjer og links
De følgende links kan alle bidrage til at lette arbejdet med at implementere dokumentdeling.
...