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 ;
24+ import org .springframework .web .util .UriComponentsBuilder ;
1725
1826import ca .uhn .fhir .model .api .annotation .ResourceDef ;
1927import ca .uhn .fhir .rest .api .MethodOutcome ;
@@ -28,6 +36,8 @@ public class FhirBridgeClient extends AbstractComplexFhirClient
2836 private static final Logger logger = LoggerFactory .getLogger (FhirBridgeClient .class );
2937 private static final OutcomeLogger outcomeLogger = new OutcomeLogger (logger );
3038
39+ private static final String NUM_CODEX_BLOOD_GAS_PANEL = "https://www.netzwerk-universitaetsmedizin.de/fhir/StructureDefinition/blood-gas-panel" ;
40+
3141 /**
3242 * @param geccoClient
3343 * not <code>null</code>
@@ -43,14 +53,16 @@ public void storeBundle(Bundle bundle)
4353 // either bundle has a patient, or patient should already exists
4454 Patient patient = createOrUpdatePatient (bundle ).orElseGet (() -> getExistingPatientOrThrow (bundle ));
4555
56+ Map <String , IdType > resourceIdsByUuid = new HashMap <>();
4657 for (int i = 0 ; i < bundle .getEntry ().size (); i ++)
4758 {
4859 BundleEntryComponent entry = bundle .getEntry ().get (i );
4960
5061 if (isEntrySupported (entry , e -> !(e .getResource () instanceof Patient )))
51- createOrUpdateEntry (i , entry , patient );
62+ createOrUpdateEntry (i , entry , patient , resourceIdsByUuid );
63+
64+ // only log for non Patients
5265 else if (!entry .hasResource () || !(entry .getResource () instanceof Patient ))
53- // only log for non Patients
5466 logger .warn ("Bundle entry at index {} not supported, ignoring entry" , i );
5567 }
5668 }
@@ -220,21 +232,28 @@ private Optional<Patient> create(Patient newPatient, String pseudonym, String bu
220232 }
221233 }
222234
223- private void createOrUpdateEntry (int index , BundleEntryComponent entry , Patient patient )
235+ private void createOrUpdateEntry (int index , BundleEntryComponent entry , Patient patient ,
236+ Map <String , IdType > resourceIdsByUuid )
224237 {
225238 Resource resource = entry .getResource ();
226239 String url = entry .getRequest ().getUrl ();
227240
228241 Optional <Resource > existingResource = findResourceInLocalFhirStore (url , resource .getClass ());
229- existingResource .ifPresentOrElse (existing -> update (existing , resource , entry .getFullUrl ()),
230- () -> create (resource , entry .getFullUrl ()));
242+ IdType resourceId = existingResource .map (
243+ existing -> update (existing , fixTemporaryReferences (resource , resourceIdsByUuid ), entry .getFullUrl ()))
244+ .orElseGet (() -> create (fixTemporaryReferences (resource , resourceIdsByUuid ), entry .getFullUrl ()));
245+
246+ resourceIdsByUuid .put (entry .getFullUrl (), resourceId );
231247 }
232248
233249 private Optional <Resource > findResourceInLocalFhirStore (String url , Class <? extends Resource > resourceType )
234250 {
235251 if (geccoClient .shouldUseChainedParameterNotLogicalReference ())
236252 url = url .replace ("patient:identifier" , "patient.identifier" );
237253
254+ UriComponentsBuilder urlBuilder = UriComponentsBuilder .fromUriString (url );
255+ url = urlBuilder .encode ().build ().toString ();
256+
238257 try
239258 {
240259 Bundle resultBundle = geccoClient .getGenericFhirClient ().search ().byUrl (url ).sort ()
@@ -254,7 +273,7 @@ private Optional<Resource> findResourceInLocalFhirStore(String url, Class<? exte
254273 return Optional .of (resultBundle .getEntryFirstRep ().getResource ());
255274 else
256275 {
257- logger .warn ("Error while search for Resource with url {}, bundle has no {} resource" , url ,
276+ logger .warn ("Error while searching for Resource with url {}, bundle has no {} resource" , url ,
258277 resourceType .getAnnotation (ResourceDef .class ).name ());
259278
260279 if (resultBundle .getEntryFirstRep ().getResponse ().hasOutcome ()
@@ -273,7 +292,7 @@ private Optional<Resource> findResourceInLocalFhirStore(String url, Class<? exte
273292 }
274293 catch (UnprocessableEntityException e )
275294 {
276- logger .warn ("Error while search for Resource with url {}, message: {}, status: {}" , url , e .getMessage (),
295+ logger .warn ("Error while searching for Resource with url {}, message: {}, status: {}" , url , e .getMessage (),
277296 e .getStatusCode ());
278297
279298 IBaseOperationOutcome outcome = e .getOperationOutcome ();
@@ -285,18 +304,60 @@ private Optional<Resource> findResourceInLocalFhirStore(String url, Class<? exte
285304 }
286305 catch (BaseServerResponseException e )
287306 {
288- logger .warn ("Error while search for Resource with url {}, message: {}, status: {}" , url , e .getMessage (),
307+ logger .warn ("Error while searching for Resource with url {}, message: {}, status: {}" , url , e .getMessage (),
289308 e .getStatusCode ());
309+
310+ IBaseOperationOutcome outcome = e .getOperationOutcome ();
311+
312+ if (outcome != null && outcome instanceof OperationOutcome )
313+ outcomeLogger .logOutcome ((OperationOutcome ) outcome );
314+
290315 throw e ;
291316 }
292317 catch (Exception e )
293318 {
294- logger .warn ("Error while search for Resource with url " + url , e );
319+ logger .warn ("Error while searching for Resource with url " + url , e );
295320 throw e ;
296321 }
297322 }
298323
299- private void update (Resource existingResource , Resource newResource , String bundleFullUrl )
324+ private Resource fixTemporaryReferences (Resource resource , Map <String , IdType > resourceIdsByUuid )
325+ {
326+ if (resource == null )
327+ return null ;
328+
329+ else if (resource instanceof Observation )
330+ {
331+ if (resource .getMeta ().getProfile ().stream ().map (CanonicalType ::getValue )
332+ .anyMatch (url -> NUM_CODEX_BLOOD_GAS_PANEL .equals (url )
333+ || (url != null && url .startsWith (NUM_CODEX_BLOOD_GAS_PANEL + "|" ))))
334+ {
335+ Observation observation = (Observation ) resource ;
336+ List <Reference > members = observation .getHasMember ();
337+ for (int i = 0 ; i < members .size (); i ++)
338+ {
339+ Reference member = members .get (i );
340+ if (member .hasReference ())
341+ {
342+ String uuid = member .getReference ();
343+ IdType resourceId = resourceIdsByUuid .get (uuid );
344+
345+ if (resourceId != null )
346+ {
347+ logger .debug (
348+ "Replacing reference at Observation.hasMember[{}] from bundle resource {} with existing resource id" ,
349+ i , resource .getIdElement ().getValue ());
350+ member .setReferenceElement (resourceId .toUnqualifiedVersionless ());
351+ }
352+ }
353+ }
354+ }
355+ }
356+
357+ return resource ;
358+ }
359+
360+ private IdType update (Resource existingResource , Resource newResource , String bundleFullUrl )
300361 {
301362 logger .debug ("Updating {}" , newResource .getResourceType ().name ());
302363
@@ -309,7 +370,7 @@ private void update(Resource existingResource, Resource newResource, String bund
309370
310371 if (outcome .getId () == null )
311372 {
312- logger .warn ("Could not update {} {}" , newResource .getResourceType ().name (),
373+ logger .warn ("Could not update {} {}: unknown reason " , newResource .getResourceType ().name (),
313374 newResource .getIdElement ().toString ());
314375 if (outcome .getOperationOutcome () != null && outcome .getOperationOutcome () instanceof OperationOutcome )
315376 outcomeLogger .logOutcome ((OperationOutcome ) outcome .getOperationOutcome ());
@@ -318,7 +379,15 @@ private void update(Resource existingResource, Resource newResource, String bund
318379 + newResource .getIdElement ().toString ());
319380 }
320381 else if (outcome .getOperationOutcome () != null && outcome .getOperationOutcome () instanceof OperationOutcome )
382+ {
321383 outcomeLogger .logOutcome ((OperationOutcome ) outcome .getOperationOutcome ());
384+ logger .warn ("Could not update {} {}: unknown reason" , newResource .getResourceType ().name (),
385+ newResource .getIdElement ().toString ());
386+ throw new RuntimeException ("Could not create " + newResource .getResourceType ().name () + " "
387+ + newResource .getIdElement ().toString () + ": unknown reason" );
388+ }
389+ else
390+ return (IdType ) outcome .getId ();
322391 }
323392 catch (UnprocessableEntityException e )
324393 {
@@ -361,7 +430,7 @@ else if (outcome.getOperationOutcome() != null && outcome.getOperationOutcome()
361430 }
362431 }
363432
364- private void create (Resource newResource , String bundleFullUrl )
433+ private IdType create (Resource newResource , String bundleFullUrl )
365434 {
366435 logger .debug ("Creating {}" , newResource .getResourceType ().name ());
367436
@@ -381,7 +450,15 @@ private void create(Resource newResource, String bundleFullUrl)
381450 + newResource .getIdElement ().toString ());
382451 }
383452 else if (outcome .getOperationOutcome () != null && outcome .getOperationOutcome () instanceof OperationOutcome )
453+ {
384454 outcomeLogger .logOutcome ((OperationOutcome ) outcome .getOperationOutcome ());
455+ logger .warn ("Could not create {} {}: unknown reason" , newResource .getResourceType ().name (),
456+ newResource .getIdElement ().toString ());
457+ throw new RuntimeException ("Could not create " + newResource .getResourceType ().name () + " "
458+ + newResource .getIdElement ().toString () + ": unknown reason" );
459+ }
460+ else
461+ return (IdType ) outcome .getId ();
385462 }
386463 catch (UnprocessableEntityException e )
387464 {
0 commit comments