From 97cfb6de37719c94c24255aaaeb091a521486ff3 Mon Sep 17 00:00:00 2001
From: James Agnew
Date: Mon, 20 May 2024 17:00:18 -0400
Subject: [PATCH] Add utility method to convert Bundle into transaction (#5945)
* Add utility method to convert Bundle into transaction
* Add utility method
* Spotless
* Build fix
---
.../java/ca/uhn/fhir/util/BundleUtil.java | 68 ++++++++++++++++++
...-utility-transaction-converter-method.yaml | 6 ++
.../ips/generator/IpsGenerationR4Test.java | 46 ++++++------
.../large-patient-everything-4.json.gz | Bin 0 -> 5797 bytes
.../uhn/fhir/util/bundle/BundleUtilTest.java | 50 +++++++++++++
5 files changed, 150 insertions(+), 20 deletions(-)
create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_4_0/5945-add-bundleutil-utility-transaction-converter-method.yaml
create mode 100644 hapi-fhir-jpaserver-ips/src/test/resources/large-patient-everything-4.json.gz
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/BundleUtil.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/BundleUtil.java
index 770aa1498c9..f0872b62287 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/BundleUtil.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/BundleUtil.java
@@ -39,6 +39,7 @@ import ca.uhn.fhir.util.bundle.SearchBundleEntryParts;
import com.google.common.collect.Sets;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;
+import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.tuple.Pair;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseBinary;
@@ -59,6 +60,7 @@ import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;
+import static org.apache.commons.lang3.StringUtils.defaultString;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static org.hl7.fhir.instance.model.api.IBaseBundle.LINK_PREV;
@@ -67,6 +69,12 @@ import static org.hl7.fhir.instance.model.api.IBaseBundle.LINK_PREV;
* Fetch resources from a bundle
*/
public class BundleUtil {
+
+ /** Non instantiable */
+ private BundleUtil() {
+ // nothing
+ }
+
private static final Logger ourLog = LoggerFactory.getLogger(BundleUtil.class);
private static final String PREVIOUS = LINK_PREV;
@@ -339,6 +347,66 @@ public class BundleUtil {
TerserUtil.setField(theContext, "entry", theBundle, retVal.toArray(new IBase[0]));
}
+ /**
+ * Converts a Bundle containing resources into a FHIR transaction which
+ * creates/updates the resources. This method does not modify the original
+ * bundle, but returns a new copy.
+ *
+ * This method is mostly intended for test scenarios where you have a Bundle
+ * containing search results or other sourced resources, and want to upload
+ * these resources to a server using a single FHIR transaction.
+ *
+ *
+ * The Bundle is converted using the following logic:
+ *
+ * - Bundle.type is changed to
transaction
+ * - Bundle.request.method is changed to
PUT
+ * - Bundle.request.url is changed to
[resourceType]/[id]
+ * - Bundle.fullUrl is changed to
[resourceType]/[id]
+ *
+ *
+ *
+ * @param theContext The FhirContext to use with the bundle
+ * @param theBundle The Bundle to modify. All resources in the Bundle should have an ID.
+ * @param thePrefixIdsOrNull If not null
, all resource IDs and all references in the Bundle will be
+ * modified to such that their IDs contain the given prefix. For example, for a value
+ * of "A", the resource "Patient/123" will be changed to be "Patient/A123". If set to
+ * null
, resource IDs are unchanged.
+ * @since 7.4.0
+ */
+ public static T convertBundleIntoTransaction(
+ @Nonnull FhirContext theContext, @Nonnull T theBundle, @Nullable String thePrefixIdsOrNull) {
+ String prefix = defaultString(thePrefixIdsOrNull);
+
+ BundleBuilder bb = new BundleBuilder(theContext);
+
+ FhirTerser terser = theContext.newTerser();
+ List entries = terser.getValues(theBundle, "Bundle.entry");
+ for (var entry : entries) {
+ IBaseResource resource = terser.getSingleValueOrNull(entry, "resource", IBaseResource.class);
+ if (resource != null) {
+ Validate.isTrue(resource.getIdElement().hasIdPart(), "Resource in bundle has no ID");
+ String newId = theContext.getResourceType(resource) + "/" + prefix
+ + resource.getIdElement().getIdPart();
+
+ IBaseResource resourceClone = terser.clone(resource);
+ resourceClone.setId(newId);
+
+ if (isNotBlank(prefix)) {
+ for (var ref : terser.getAllResourceReferences(resourceClone)) {
+ var refElement = ref.getResourceReference().getReferenceElement();
+ ref.getResourceReference()
+ .setReference(refElement.getResourceType() + "/" + prefix + refElement.getIdPart());
+ }
+ }
+
+ bb.addTransactionUpdateEntry(resourceClone);
+ }
+ }
+
+ return bb.getBundleTyped();
+ }
+
private static void validatePartsNotNull(LinkedHashSet theDeleteParts) {
if (theDeleteParts == null) {
throw new IllegalStateException(
diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_4_0/5945-add-bundleutil-utility-transaction-converter-method.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_4_0/5945-add-bundleutil-utility-transaction-converter-method.yaml
new file mode 100644
index 00000000000..a397012f304
--- /dev/null
+++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_4_0/5945-add-bundleutil-utility-transaction-converter-method.yaml
@@ -0,0 +1,6 @@
+---
+type: add
+issue: 5945
+title: "A new utility method has been added to `BundleUtil` which converts a FHIR Bundle
+ containing resources (e.g. a search result bundle) into a FHIR transaction bundle which
+ could be used to upload those resources to a server."
diff --git a/hapi-fhir-jpaserver-ips/src/test/java/ca/uhn/fhir/jpa/ips/generator/IpsGenerationR4Test.java b/hapi-fhir-jpaserver-ips/src/test/java/ca/uhn/fhir/jpa/ips/generator/IpsGenerationR4Test.java
index e697ef20b2a..34cf71c0435 100644
--- a/hapi-fhir-jpaserver-ips/src/test/java/ca/uhn/fhir/jpa/ips/generator/IpsGenerationR4Test.java
+++ b/hapi-fhir-jpaserver-ips/src/test/java/ca/uhn/fhir/jpa/ips/generator/IpsGenerationR4Test.java
@@ -47,6 +47,7 @@ import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
+import static ca.uhn.fhir.util.BundleUtil.convertBundleIntoTransaction;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.stringContainsInOrder;
@@ -81,11 +82,7 @@ public class IpsGenerationR4Test extends BaseResourceProviderR4Test {
@Test
public void testGenerateLargePatientSummary() throws IOException {
Bundle sourceData = ClasspathUtil.loadCompressedResource(myFhirContext, Bundle.class, "/large-patient-everything.json.gz");
- sourceData.setType(Bundle.BundleType.TRANSACTION);
- for (Bundle.BundleEntryComponent nextEntry : sourceData.getEntry()) {
- nextEntry.getRequest().setMethod(Bundle.HTTPVerb.PUT);
- nextEntry.getRequest().setUrl(nextEntry.getResource().getIdElement().toUnqualifiedVersionless().getValue());
- }
+ sourceData = convertBundleIntoTransaction(myFhirContext, sourceData, null);
Bundle outcome = mySystemDao.transaction(mySrd, sourceData);
ourLog.info("Created {} resources", outcome.getEntry().size());
@@ -119,11 +116,7 @@ public class IpsGenerationR4Test extends BaseResourceProviderR4Test {
myStorageSettings.setResourceClientIdStrategy(JpaStorageSettings.ClientIdStrategyEnum.ANY);
Bundle sourceData = ClasspathUtil.loadCompressedResource(myFhirContext, Bundle.class, "/large-patient-everything-2.json.gz");
- sourceData.setType(Bundle.BundleType.TRANSACTION);
- for (Bundle.BundleEntryComponent nextEntry : sourceData.getEntry()) {
- nextEntry.getRequest().setMethod(Bundle.HTTPVerb.PUT);
- nextEntry.getRequest().setUrl(nextEntry.getResource().getIdElement().toUnqualifiedVersionless().getValue());
- }
+ sourceData = convertBundleIntoTransaction(myFhirContext, sourceData, null);
Bundle outcome = mySystemDao.transaction(mySrd, sourceData);
ourLog.info("Created {} resources", outcome.getEntry().size());
@@ -145,11 +138,7 @@ public class IpsGenerationR4Test extends BaseResourceProviderR4Test {
myStorageSettings.setResourceClientIdStrategy(JpaStorageSettings.ClientIdStrategyEnum.ANY);
Bundle sourceData = ClasspathUtil.loadCompressedResource(myFhirContext, Bundle.class, "/large-patient-everything-3.json.gz");
- sourceData.setType(Bundle.BundleType.TRANSACTION);
- for (Bundle.BundleEntryComponent nextEntry : sourceData.getEntry()) {
- nextEntry.getRequest().setMethod(Bundle.HTTPVerb.PUT);
- nextEntry.getRequest().setUrl(nextEntry.getResource().getIdElement().toUnqualifiedVersionless().getValue());
- }
+ sourceData = convertBundleIntoTransaction(myFhirContext, sourceData, null);
Bundle outcome = mySystemDao.transaction(mySrd, sourceData);
ourLog.info("Created {} resources", outcome.getEntry().size());
@@ -166,16 +155,33 @@ public class IpsGenerationR4Test extends BaseResourceProviderR4Test {
assertEquals(80, output.getEntry().size());
}
+ @Test
+ public void testGenerateLargePatientSummary4() {
+ Bundle sourceData = ClasspathUtil.loadCompressedResource(myFhirContext, Bundle.class, "/large-patient-everything-4.json.gz");
+ sourceData = convertBundleIntoTransaction(myFhirContext, sourceData, "EPD");
+
+ Bundle outcome = mySystemDao.transaction(mySrd, sourceData);
+ ourLog.info("Created {} resources", outcome.getEntry().size());
+
+ Bundle output = myClient
+ .operation()
+ .onInstance("Patient/EPD2223")
+ .named(JpaConstants.OPERATION_SUMMARY)
+ .withNoParameters(Parameters.class)
+ .returnResourceType(Bundle.class)
+ .execute();
+ ourLog.info("Output: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(output));
+
+ // Verify
+ assertEquals(55, output.getEntry().size());
+ }
+
@Test
public void testGenerateTinyPatientSummary() throws IOException {
myStorageSettings.setResourceClientIdStrategy(JpaStorageSettings.ClientIdStrategyEnum.ANY);
Bundle sourceData = ClasspathUtil.loadCompressedResource(myFhirContext, Bundle.class, "/tiny-patient-everything.json.gz");
- sourceData.setType(Bundle.BundleType.TRANSACTION);
- for (Bundle.BundleEntryComponent nextEntry : sourceData.getEntry()) {
- nextEntry.getRequest().setMethod(Bundle.HTTPVerb.PUT);
- nextEntry.getRequest().setUrl(nextEntry.getResource().getIdElement().toUnqualifiedVersionless().getValue());
- }
+ sourceData = convertBundleIntoTransaction(myFhirContext, sourceData, null);
Bundle outcome = mySystemDao.transaction(mySrd, sourceData);
ourLog.info("Created {} resources", outcome.getEntry().size());
diff --git a/hapi-fhir-jpaserver-ips/src/test/resources/large-patient-everything-4.json.gz b/hapi-fhir-jpaserver-ips/src/test/resources/large-patient-everything-4.json.gz
new file mode 100644
index 0000000000000000000000000000000000000000..cc2fd1e4eaa59c19648a483421c40745d0901f7d
GIT binary patch
literal 5797
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
literal 0
HcmV?d00001
diff --git a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/util/bundle/BundleUtilTest.java b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/util/bundle/BundleUtilTest.java
index ccbb3c60080..85d6c4b4a96 100644
--- a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/util/bundle/BundleUtilTest.java
+++ b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/util/bundle/BundleUtilTest.java
@@ -680,6 +680,56 @@ public class BundleUtilTest {
assertNull(BundleUtil.getBundleTypeEnum(ourCtx, bundle));
}
+ @Test
+ public void testConvertBundleIntoTransaction() {
+ Bundle input = createBundleWithPatientAndObservation();
+
+ Bundle output = BundleUtil.convertBundleIntoTransaction(ourCtx, input, null);
+ assertEquals(Bundle.BundleType.TRANSACTION, output.getType());
+ assertEquals("Patient/123", output.getEntry().get(0).getFullUrl());
+ assertEquals("Patient/123", output.getEntry().get(0).getRequest().getUrl());
+ assertEquals(Bundle.HTTPVerb.PUT, output.getEntry().get(0).getRequest().getMethod());
+ assertTrue(((Patient) output.getEntry().get(0).getResource()).getActive());
+ assertEquals("Observation/456", output.getEntry().get(1).getFullUrl());
+ assertEquals("Observation/456", output.getEntry().get(1).getRequest().getUrl());
+ assertEquals(Bundle.HTTPVerb.PUT, output.getEntry().get(1).getRequest().getMethod());
+ assertEquals("Patient/123", ((Observation)output.getEntry().get(1).getResource()).getSubject().getReference());
+ assertEquals(Observation.ObservationStatus.AMENDED, ((Observation)output.getEntry().get(1).getResource()).getStatus());
+ }
+
+ @Test
+ public void testConvertBundleIntoTransaction_WithPrefix() {
+ Bundle input = createBundleWithPatientAndObservation();
+
+ Bundle output = BundleUtil.convertBundleIntoTransaction(ourCtx, input, "A");
+ assertEquals(Bundle.BundleType.TRANSACTION, output.getType());
+ assertEquals("Patient/A123", output.getEntry().get(0).getFullUrl());
+ assertEquals("Patient/A123", output.getEntry().get(0).getRequest().getUrl());
+ assertEquals(Bundle.HTTPVerb.PUT, output.getEntry().get(0).getRequest().getMethod());
+ assertTrue(((Patient) output.getEntry().get(0).getResource()).getActive());
+ assertEquals("Observation/A456", output.getEntry().get(1).getFullUrl());
+ assertEquals("Observation/A456", output.getEntry().get(1).getRequest().getUrl());
+ assertEquals(Bundle.HTTPVerb.PUT, output.getEntry().get(1).getRequest().getMethod());
+ assertEquals("Patient/A123", ((Observation)output.getEntry().get(1).getResource()).getSubject().getReference());
+ assertEquals(Observation.ObservationStatus.AMENDED, ((Observation)output.getEntry().get(1).getResource()).getStatus());
+ }
+
+ private static @Nonnull Bundle createBundleWithPatientAndObservation() {
+ Bundle input = new Bundle();
+ input.setType(Bundle.BundleType.COLLECTION);
+ Patient patient = new Patient();
+ patient.setActive(true);
+ patient.setId("123");
+ input.addEntry().setResource(patient);
+ Observation observation = new Observation();
+ observation.setId("456");
+ observation.setStatus(Observation.ObservationStatus.AMENDED);
+ observation.setSubject(new Reference("Patient/123"));
+ input.addEntry().setResource(observation);
+ return input;
+ }
+
+
@Nonnull
private static Bundle withBundle(Resource theResource) {
final Bundle bundle = new Bundle();