Skip to content

Commit 4d8ba46

Browse files
authored
Merge pull request #57 from MeasureAuthoringTool/MAT-10112
MAT-10112 generate composite measure bundle on test case list page
2 parents 4c16ea4 + 31af793 commit 4d8ba46

4 files changed

Lines changed: 101 additions & 20 deletions

File tree

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<modelVersion>4.0.0</modelVersion>
77
<groupId>gov.cms.madie.packaging</groupId>
88
<artifactId>packaging-utility</artifactId>
9-
<version>0.2.15-SNAPSHOT</version>
9+
<version>0.2.16-SNAPSHOT</version>
1010

1111
<name>packaging-utility</name>
1212
<description>A simple packaging-utility.</description>

src/main/java/gov/cms/madie/packaging/utils/PackagingUtility.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ public interface PackagingUtility {
1313
byte[] buildCompositeExport(
1414
String compositeBundle, List<Export> componentBundles, String exportFileName);
1515

16+
String buildCompositeMeasureBundle(String compositeBundle, List<Export> componentExports);
17+
1618
String getHumanReadableWithCSS(Bundle measureBundle);
1719

1820
String getHumanReadableWithCSS(String measureBundleJson);

src/main/java/gov/cms/madie/packaging/utils/qicore411/PackagingUtilityImpl.java

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import java.util.HashSet;
77
import java.util.List;
88
import java.util.Map;
9+
import java.util.Objects;
910
import java.util.Set;
1011
import java.util.stream.Collectors;
1112

@@ -60,35 +61,63 @@ public byte[] getZipBundle(Object o, String exportFileName) throws InternalServe
6061
@Override
6162
public byte[] buildCompositeExport(
6263
String compositeBundle, List<Export> componentExports, String exportFileName) {
63-
Bundle bundle =
64-
buildCompositeBundle(
65-
compositeBundle,
66-
componentExports.stream()
67-
.map(Export::getMeasureBundleJson)
68-
.collect(Collectors.toList()));
64+
Bundle bundle = mergeComponentAndCompositeBundles(compositeBundle, componentExports);
6965
if (bundle == null) {
7066
return null;
7167
}
7268
return getZipBundle(bundle, exportFileName, null);
7369
}
7470

75-
private Bundle buildCompositeBundle(String compositeBundle, List<String> componentBundles) {
71+
@Override
72+
public String buildCompositeMeasureBundle(String compositeBundle, List<Export> componentExports) {
73+
if (StringUtils.isBlank(compositeBundle)) {
74+
return null;
75+
}
76+
if (CollectionUtils.isEmpty(componentExports)) {
77+
return compositeBundle;
78+
}
79+
Bundle bundle = mergeComponentAndCompositeBundles(compositeBundle, componentExports);
80+
if (bundle == null) {
81+
return null;
82+
}
83+
return context.newJsonParser().setPrettyPrint(true).encodeResourceToString(bundle);
84+
}
85+
86+
/**
87+
* Core logic for merging composite and component bundles. Returns the merged Bundle object
88+
* directly.
89+
*/
90+
private Bundle mergeComponentAndCompositeBundles(
91+
String compositeBundle, List<Export> componentExports) {
7692
if (StringUtils.isBlank(compositeBundle)) {
7793
return null;
7894
}
7995

8096
IParser jsonParser = context.newJsonParser();
8197
Bundle bundle = (Bundle) jsonParser.parseResource(compositeBundle);
82-
if (CollectionUtils.isEmpty(componentBundles)) {
98+
99+
if (CollectionUtils.isEmpty(componentExports)) {
83100
return bundle;
84101
}
102+
103+
List<String> componentBundleJsons =
104+
componentExports.stream()
105+
.map(Export::getMeasureBundleJson)
106+
.filter(StringUtils::isNotBlank)
107+
.toList();
108+
109+
if (componentBundleJsons.isEmpty()) {
110+
return bundle;
111+
}
112+
85113
Set<String> existingNameVersions =
86114
bundle.getEntry().stream()
87115
.map(this::getNameVersionKey)
88-
.filter(java.util.Objects::nonNull)
116+
.filter(Objects::nonNull)
89117
.collect(Collectors.toCollection(HashSet::new));
90-
for (String componentBundle : componentBundles) {
91-
Bundle component = (Bundle) jsonParser.parseResource(componentBundle);
118+
119+
for (String componentBundleJson : componentBundleJsons) {
120+
Bundle component = (Bundle) jsonParser.parseResource(componentBundleJson);
92121
for (Bundle.BundleEntryComponent entry : component.getEntry()) {
93122
String key = getNameVersionKey(entry);
94123
if (key == null || existingNameVersions.add(key)) {

src/test/java/gov/cms/madie/measure/utilities/qicore411/PackagingUtilityImplTest.java

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -190,14 +190,6 @@ void testBuildCompositeExportNullCompositeBundle() {
190190
assertNull(result);
191191
}
192192

193-
@Test
194-
void testBuildCompositeExportBlankCompositeBundle() {
195-
PackagingUtilityImpl utility = new PackagingUtilityImpl();
196-
List<Export> componentExports = new ArrayList<>();
197-
byte[] result = utility.buildCompositeExport("", componentExports, "composite");
198-
assertNull(result);
199-
}
200-
201193
@Test
202194
void testBuildCompositeExportWithEmptyComponentExports() throws IOException {
203195
PackagingUtilityImpl utility = new PackagingUtilityImpl();
@@ -225,4 +217,62 @@ void testBuildCompositeExportWithComponentExports() throws IOException {
225217
assertThat(zipContents.containsKey("composite.json"), is(true));
226218
assertThat(zipContents.containsKey("composite.xml"), is(true));
227219
}
220+
221+
@Test
222+
void testBuildCompositeMeasureBundleNullCompositeBundle() {
223+
PackagingUtilityImpl utility = new PackagingUtilityImpl();
224+
String result = utility.buildCompositeMeasureBundle(null, new ArrayList<>());
225+
assertNull(result);
226+
}
227+
228+
@Test
229+
void testBuildCompositeMeasureBundleWithEmptyComponentExports() {
230+
PackagingUtilityImpl utility = new PackagingUtilityImpl();
231+
String result = utility.buildCompositeMeasureBundle(JsonBits.BUNDLE, new ArrayList<>());
232+
// When componentExports is empty, the original compositeBundle string is returned unchanged
233+
assertEquals(JsonBits.BUNDLE, result);
234+
}
235+
236+
@Test
237+
void testBuildCompositeMeasureBundleWithNullComponentExports() {
238+
PackagingUtilityImpl utility = new PackagingUtilityImpl();
239+
String result = utility.buildCompositeMeasureBundle(JsonBits.BUNDLE, null);
240+
// When componentExports is null, the original compositeBundle string is returned unchanged
241+
assertEquals(JsonBits.BUNDLE, result);
242+
}
243+
244+
@Test
245+
void testBuildCompositeMeasureBundleDeduplicatesEntries() {
246+
PackagingUtilityImpl utility = new PackagingUtilityImpl();
247+
Export componentExport = new Export();
248+
componentExport.setMeasureBundleJson(JsonBits.BUNDLE);
249+
List<Export> componentExports = List.of(componentExport);
250+
251+
String result = utility.buildCompositeMeasureBundle(JsonBits.BUNDLE, componentExports);
252+
assertNotNull(result);
253+
assertThat(result.contains("\"resourceType\": \"Bundle\""), is(true));
254+
255+
// Parse the result and verify entries were deduplicated (same name|version not duplicated)
256+
Bundle resultBundle = FhirContext.forR4().newJsonParser().parseResource(Bundle.class, result);
257+
long measureCount =
258+
resultBundle.getEntry().stream()
259+
.filter(e -> "Measure".equals(e.getResource().getResourceType().name()))
260+
.count();
261+
// Only one Measure entry since both bundles have same Measure name+version
262+
assertEquals(1, measureCount);
263+
}
264+
265+
@Test
266+
void testBuildCompositeMeasureBundleFiltersNullAndBlankBundleJson() {
267+
PackagingUtilityImpl utility = new PackagingUtilityImpl();
268+
Export componentWithNull = new Export();
269+
componentWithNull.setMeasureBundleJson(null);
270+
Export componentWithBlank = new Export();
271+
componentWithBlank.setMeasureBundleJson("");
272+
List<Export> componentExports = List.of(componentWithNull, componentWithBlank);
273+
274+
String result = utility.buildCompositeMeasureBundle(JsonBits.BUNDLE, componentExports);
275+
assertNotNull(result);
276+
assertThat(result.contains("\"resourceType\": \"Bundle\""), is(true));
277+
}
228278
}

0 commit comments

Comments
 (0)