22
33import static de .netzwerk_universitaetsmedizin .codex .processes .data_transfer .ConstantsDataTransfer .NAMING_SYSTEM_NUM_CODEX_CRR_PSEUDONYM ;
44
5+ import java .util .HashMap ;
6+ import java .util .List ;
7+ import java .util .Map ;
58import java .util .Optional ;
69import java .util .function .Predicate ;
710
811import org .hl7 .fhir .instance .model .api .IBaseOperationOutcome ;
912import org .hl7 .fhir .r4 .model .Bundle ;
1013import org .hl7 .fhir .r4 .model .Bundle .BundleEntryComponent ;
1114import org .hl7 .fhir .r4 .model .Bundle .HTTPVerb ;
15+ import org .hl7 .fhir .r4 .model .CanonicalType ;
16+ import org .hl7 .fhir .r4 .model .IdType ;
17+ import org .hl7 .fhir .r4 .model .Observation ;
1218import org .hl7 .fhir .r4 .model .OperationOutcome ;
1319import org .hl7 .fhir .r4 .model .Patient ;
20+ import org .hl7 .fhir .r4 .model .Reference ;
1421import org .hl7 .fhir .r4 .model .Resource ;
1522import org .slf4j .Logger ;
1623import org .slf4j .LoggerFactory ;
@@ -28,6 +35,8 @@ public class FhirBridgeClient extends AbstractComplexFhirClient
2835 private static final Logger logger = LoggerFactory .getLogger (FhirBridgeClient .class );
2936 private static final OutcomeLogger outcomeLogger = new OutcomeLogger (logger );
3037
38+ private static final String NUM_CODEX_BLOOD_GAS_PANEL = "https://www.netzwerk-universitaetsmedizin.de/fhir/StructureDefinition/blood-gas-panel" ;
39+
3140 /**
3241 * @param geccoClient
3342 * not <code>null</code>
@@ -43,14 +52,16 @@ public void storeBundle(Bundle bundle)
4352 // either bundle has a patient, or patient should already exists
4453 Patient patient = createOrUpdatePatient (bundle ).orElseGet (() -> getExistingPatientOrThrow (bundle ));
4554
55+ Map <String , IdType > resourceIdsByUuid = new HashMap <>();
4656 for (int i = 0 ; i < bundle .getEntry ().size (); i ++)
4757 {
4858 BundleEntryComponent entry = bundle .getEntry ().get (i );
4959
5060 if (isEntrySupported (entry , e -> !(e .getResource () instanceof Patient )))
51- createOrUpdateEntry (i , entry , patient );
61+ createOrUpdateEntry (i , entry , patient , resourceIdsByUuid );
62+
63+ // only log for non Patients
5264 else if (!entry .hasResource () || !(entry .getResource () instanceof Patient ))
53- // only log for non Patients
5465 logger .warn ("Bundle entry at index {} not supported, ignoring entry" , i );
5566 }
5667 }
@@ -220,14 +231,18 @@ private Optional<Patient> create(Patient newPatient, String pseudonym, String bu
220231 }
221232 }
222233
223- private void createOrUpdateEntry (int index , BundleEntryComponent entry , Patient patient )
234+ private void createOrUpdateEntry (int index , BundleEntryComponent entry , Patient patient ,
235+ Map <String , IdType > resourceIdsByUuid )
224236 {
225237 Resource resource = entry .getResource ();
226238 String url = entry .getRequest ().getUrl ();
227239
228240 Optional <Resource > existingResource = findResourceInLocalFhirStore (url , resource .getClass ());
229- existingResource .ifPresentOrElse (existing -> update (existing , resource , entry .getFullUrl ()),
230- () -> create (resource , entry .getFullUrl ()));
241+ IdType resourceId = existingResource .map (
242+ existing -> update (existing , fixTemporaryReferences (resource , resourceIdsByUuid ), entry .getFullUrl ()))
243+ .orElseGet (() -> create (fixTemporaryReferences (resource , resourceIdsByUuid ), entry .getFullUrl ()));
244+
245+ resourceIdsByUuid .put (entry .getFullUrl (), resourceId );
231246 }
232247
233248 private Optional <Resource > findResourceInLocalFhirStore (String url , Class <? extends Resource > resourceType )
@@ -302,7 +317,43 @@ private Optional<Resource> findResourceInLocalFhirStore(String url, Class<? exte
302317 }
303318 }
304319
305- private void update (Resource existingResource , Resource newResource , String bundleFullUrl )
320+ private Resource fixTemporaryReferences (Resource resource , Map <String , IdType > resourceIdsByUuid )
321+ {
322+ if (resource == null )
323+ return null ;
324+
325+ else if (resource instanceof Observation )
326+ {
327+ if (resource .getMeta ().getProfile ().stream ().map (CanonicalType ::getValue )
328+ .anyMatch (url -> NUM_CODEX_BLOOD_GAS_PANEL .equals (url )
329+ || (url != null && url .startsWith (NUM_CODEX_BLOOD_GAS_PANEL + "|" ))))
330+ {
331+ Observation observation = (Observation ) resource ;
332+ List <Reference > members = observation .getHasMember ();
333+ for (int i = 0 ; i < members .size (); i ++)
334+ {
335+ Reference member = members .get (i );
336+ if (member .hasReference ())
337+ {
338+ String uuid = member .getReference ();
339+ IdType resourceId = resourceIdsByUuid .get (uuid );
340+
341+ if (resourceId != null )
342+ {
343+ logger .debug (
344+ "Replacing reference at Observation.hasMember[{}] from bundle resource {} with existing resource id" ,
345+ i , resource .getIdElement ().getValue ());
346+ member .setReferenceElement (resourceId );
347+ }
348+ }
349+ }
350+ }
351+ }
352+
353+ return resource ;
354+ }
355+
356+ private IdType update (Resource existingResource , Resource newResource , String bundleFullUrl )
306357 {
307358 logger .debug ("Updating {}" , newResource .getResourceType ().name ());
308359
@@ -315,7 +366,7 @@ private void update(Resource existingResource, Resource newResource, String bund
315366
316367 if (outcome .getId () == null )
317368 {
318- logger .warn ("Could not update {} {}" , newResource .getResourceType ().name (),
369+ logger .warn ("Could not update {} {}: unknown reason " , newResource .getResourceType ().name (),
319370 newResource .getIdElement ().toString ());
320371 if (outcome .getOperationOutcome () != null && outcome .getOperationOutcome () instanceof OperationOutcome )
321372 outcomeLogger .logOutcome ((OperationOutcome ) outcome .getOperationOutcome ());
@@ -324,7 +375,15 @@ private void update(Resource existingResource, Resource newResource, String bund
324375 + newResource .getIdElement ().toString ());
325376 }
326377 else if (outcome .getOperationOutcome () != null && outcome .getOperationOutcome () instanceof OperationOutcome )
378+ {
327379 outcomeLogger .logOutcome ((OperationOutcome ) outcome .getOperationOutcome ());
380+ logger .warn ("Could not update {} {}: unknown reason" , newResource .getResourceType ().name (),
381+ newResource .getIdElement ().toString ());
382+ throw new RuntimeException ("Could not create " + newResource .getResourceType ().name () + " "
383+ + newResource .getIdElement ().toString () + ": unknown reason" );
384+ }
385+ else
386+ return (IdType ) outcome .getId ();
328387 }
329388 catch (UnprocessableEntityException e )
330389 {
@@ -367,7 +426,7 @@ else if (outcome.getOperationOutcome() != null && outcome.getOperationOutcome()
367426 }
368427 }
369428
370- private void create (Resource newResource , String bundleFullUrl )
429+ private IdType create (Resource newResource , String bundleFullUrl )
371430 {
372431 logger .debug ("Creating {}" , newResource .getResourceType ().name ());
373432
@@ -387,7 +446,15 @@ private void create(Resource newResource, String bundleFullUrl)
387446 + newResource .getIdElement ().toString ());
388447 }
389448 else if (outcome .getOperationOutcome () != null && outcome .getOperationOutcome () instanceof OperationOutcome )
449+ {
390450 outcomeLogger .logOutcome ((OperationOutcome ) outcome .getOperationOutcome ());
451+ logger .warn ("Could not create {} {}: unknown reason" , newResource .getResourceType ().name (),
452+ newResource .getIdElement ().toString ());
453+ throw new RuntimeException ("Could not create " + newResource .getResourceType ().name () + " "
454+ + newResource .getIdElement ().toString () + ": unknown reason" );
455+ }
456+ else
457+ return (IdType ) outcome .getId ();
391458 }
392459 catch (UnprocessableEntityException e )
393460 {
0 commit comments