diff --git a/.vscode/launch.json b/.vscode/launch.json index 9da8ef4d0c2..4d06bd3d9ea 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -84,6 +84,15 @@ "projectName": "matchbox-server", "vmArgs": "-Dspring.config.additional-location=file:/Users/oegger/Documents/github/matchbox/matchbox-server/target/test-classes/application-test-r5onr4.yaml", "cwd": "${workspaceFolder}/matchbox-server" + }, + { + "type": "java", + "name": "Launch Matchbox-Server (alis)", + "request": "launch", + "mainClass": "ca.uhn.fhir.jpa.starter.Application", + "projectName": "matchbox-server", + "vmArgs": "-Dspring.config.additional-location=file:with-alis/application.yaml", + "cwd": "${workspaceFolder}/matchbox-server" }, { "type": "java", "name": "Launch Matchbox-Server", diff --git a/docs/changelog.md b/docs/changelog.md index 4ce020f13e4..9e2ec9db7d6 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,7 +1,8 @@ -2024/04/xx Release 3.8.3 +2024/04/29 Release 3.8.3 - profile validation with different ig version issues, GUI & EVS Client [#225](https://github.com/ahdis/matchbox/issues/225) - improved the profile selection in the validation GUI +- FML: Side effect exception when updating a StructureMap [#227](https://github.com/ahdis/matchbox/issues/227) 2024/04/22 Release 3.8.2 diff --git a/matchbox-engine/pom.xml b/matchbox-engine/pom.xml index 85740e686b1..5bec77cae43 100644 --- a/matchbox-engine/pom.xml +++ b/matchbox-engine/pom.xml @@ -6,7 +6,7 @@ matchbox health.matchbox - 3.8.2 + 3.8.3 matchbox-engine diff --git a/matchbox-engine/src/main/java/ch/ahdis/matchbox/engine/MatchboxEngine.java b/matchbox-engine/src/main/java/ch/ahdis/matchbox/engine/MatchboxEngine.java index c7b103d6671..4d6ac33c7c8 100644 --- a/matchbox-engine/src/main/java/ch/ahdis/matchbox/engine/MatchboxEngine.java +++ b/matchbox-engine/src/main/java/ch/ahdis/matchbox/engine/MatchboxEngine.java @@ -254,6 +254,7 @@ public MatchboxEngine getEngine() throws MatchboxEngineCreationException { try { engine = new MatchboxEngine(this.fromNothing()); } catch (final IOException e) { throw new MatchboxEngineCreationException(e); } engine.setVersion(this.fhirVersion.toCode()); + engine.getContext().setAllowLoadingDuplicates(false); if (this.txServer == null) { engine.getContext().setCanRunWithoutTerminology(true); engine.getContext().setNoTerminologyServer(true); diff --git a/matchbox-engine/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java b/matchbox-engine/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java index 0cf36a66298..abd689b449b 100644 --- a/matchbox-engine/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java +++ b/matchbox-engine/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java @@ -56,6 +56,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWIS import org.hl7.fhir.exceptions.DefinitionException; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.TerminologyServiceException; +import org.hl7.fhir.r5.comparison.VersionComparisonAnnotation; import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; import org.hl7.fhir.r5.context.CanonicalResourceManager.CanonicalResourceProxy; import org.hl7.fhir.r5.context.ILoggingService.LogCategory; @@ -383,9 +384,16 @@ public void registerResourceFromPackage(CanonicalResourceProxy r, PackageInforma if (Utilities.existsInList(url, "http://hl7.org/fhir/SearchParameter/example")) { return; } + // matchbox patch for duplicate resources, see https://github.com/ahdis/matchbox/issues/227 + // org.hl7.fhir.r5.conformance.R5ExtensionsLoader.loadR5SpecialTypes(R5ExtensionsLoader.java:141) CanonicalResource ex = fetchResourceWithException(r.getType(), url); - throw new DefinitionException(formatMessage(I18nConstants.DUPLICATE_RESOURCE_, url, r.getVersion(), ex.getVersion(), - ex.fhirType())); + if (laterVersion(r.getVersion(), ex.getVersion())) { + logger.logMessage("Note replacing old version: " + formatMessage(I18nConstants.DUPLICATE_RESOURCE_, url, r.getVersion(), ex.getVersion(), ex.fhirType())); + dropResource(ex); + } else { + logger.logMessage("Note keeping newer version: " + formatMessage(I18nConstants.DUPLICATE_RESOURCE_, url, r.getVersion(), ex.getVersion(), ex.fhirType())); + return; + } } switch(r.getType()) { case "StructureDefinition": @@ -508,9 +516,16 @@ public void cacheResourceFromPackage(Resource r, PackageInformation packageInfo) if (Utilities.existsInList(url, "http://hl7.org/fhir/SearchParameter/example")) { return; } - CanonicalResource ex = (CanonicalResource) fetchResourceWithException(r.getClass(), url); - throw new DefinitionException(formatMessage(I18nConstants.DUPLICATE_RESOURCE_, url, ((CanonicalResource) r).getVersion(), ex.getVersion(), - ex.fhirType())); + // matchbox patch for duplicate resources, see https://github.com/ahdis/matchbox/issues/227 + // org.hl7.fhir.r5.conformance.R5ExtensionsLoader.loadR5SpecialTypes(R5ExtensionsLoader.java:141) + CanonicalResource ex = fetchResourceWithException(m.fhirType(), url); + if (laterVersion(m.getVersion(), ex.getVersion())) { + logger.logMessage("Note replacing old version: " + formatMessage(I18nConstants.DUPLICATE_RESOURCE_, url, m.getVersion(), ex.getVersion(), ex.fhirType())); + dropResource(ex); + } else { + logger.logMessage("Note keeping newer version: " + formatMessage(I18nConstants.DUPLICATE_RESOURCE_, url, m.getVersion(), ex.getVersion(), ex.fhirType())); + return; + } } if (r instanceof StructureDefinition) { StructureDefinition sd = (StructureDefinition) m; diff --git a/matchbox-frontend/package.json b/matchbox-frontend/package.json index ce00e5e8bf7..e496aaf3763 100644 --- a/matchbox-frontend/package.json +++ b/matchbox-frontend/package.json @@ -1,6 +1,6 @@ { "name": "matchbox", - "version": "3.8.2", + "version": "3.8.3", "license": "MIT", "scripts": { "ng": "ng", diff --git a/matchbox-server/pom.xml b/matchbox-server/pom.xml index 3f797a454f3..deedfb8dbc3 100644 --- a/matchbox-server/pom.xml +++ b/matchbox-server/pom.xml @@ -5,7 +5,7 @@ matchbox health.matchbox - 3.8.2 + 3.8.3 matchbox-server diff --git a/matchbox-server/src/main/java/ch/ahdis/matchbox/ConformancePackageResourceProvider.java b/matchbox-server/src/main/java/ch/ahdis/matchbox/ConformancePackageResourceProvider.java index 7a6b2a40d2b..22073f05a73 100644 --- a/matchbox-server/src/main/java/ch/ahdis/matchbox/ConformancePackageResourceProvider.java +++ b/matchbox-server/src/main/java/ch/ahdis/matchbox/ConformancePackageResourceProvider.java @@ -179,10 +179,12 @@ public ca.uhn.fhir.rest.api.server.IBundleProvider search(jakarta.servlet.http.H if (theUrl != null) { String url = theUrl.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().get(0).getValue(); R5 r = matchboxEngine.getContext().fetchResource(classR5,url); - resources.add(r); + if (r != null) + resources.add(r); } else { resources.addAll(matchboxEngine.getContext().fetchResourcesByType(classR5)); } + switch (getFhirVersion(this.cliContext.getFhirVersion())) { case "4.0.1": return new SimpleBundleProvider( resources.stream().map(VersionConvertorFactory_40_50::convertResource).collect(Collectors.toList())); diff --git a/matchbox-server/src/main/java/ch/ahdis/matchbox/IgLoaderFromJpaPackageCache.java b/matchbox-server/src/main/java/ch/ahdis/matchbox/IgLoaderFromJpaPackageCache.java index 6592521dddc..aff4746495c 100644 --- a/matchbox-server/src/main/java/ch/ahdis/matchbox/IgLoaderFromJpaPackageCache.java +++ b/matchbox-server/src/main/java/ch/ahdis/matchbox/IgLoaderFromJpaPackageCache.java @@ -34,9 +34,11 @@ import org.hl7.fhir.convertors.factory.VersionConvertorFactory_30_50; import org.hl7.fhir.convertors.factory.VersionConvertorFactory_40_50; import org.hl7.fhir.convertors.factory.VersionConvertorFactory_43_50; +import org.hl7.fhir.r4.model.ConceptMap.ConceptMapGroupComponent; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.instance.model.api.IBaseBinary; import org.hl7.fhir.r5.context.SimpleWorkerContext; +import org.hl7.fhir.r5.model.CanonicalResource; import org.hl7.fhir.r5.model.ImplementationGuide; import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.utilities.ByteProvider; @@ -104,6 +106,42 @@ public FhirContext getFhirContext(FhirVersionEnum theFhirVersion) { return myVersionToContext.computeIfAbsent(theFhirVersion, v -> new FhirContext(v)); } + private void cleanModifierExtensions(org.hl7.fhir.r5.model.ConceptMap r) { + for ( org.hl7.fhir.r5.model.ConceptMap.ConceptMapGroupComponent group :r.getGroup()) { + group.getElement().forEach(element -> { + element.getTarget().forEach(target -> { + target.getModifierExtension().clear(); + }); + }); + } + } + + private void cleanModifierExtensions(org.hl7.fhir.r5.model.StructureMap r) { + r.getContained().forEach(c -> { + if (c instanceof org.hl7.fhir.r5.model.ConceptMap) { + cleanModifierExtensions((org.hl7.fhir.r5.model.ConceptMap) c); + } + }); + } + + private void cleanModifierExtensions(org.hl7.fhir.r4.model.ConceptMap r) { + for ( ConceptMapGroupComponent group :r.getGroup()) { + group.getElement().forEach(element -> { + element.getTarget().forEach(target -> { + target.getModifierExtension().clear(); + }); + }); + } + } + + private void cleanModifierExtensions(org.hl7.fhir.r4.model.StructureMap r) { + r.getContained().forEach(c -> { + if (c instanceof org.hl7.fhir.r4.model.ConceptMap) { + cleanModifierExtensions((org.hl7.fhir.r4.model.ConceptMap) c); + } + }); + } + private org.hl7.fhir.r5.model.Resource loadPackageEntity(NpmPackageVersionResourceEntity contents) { try { final var binary = MatchboxServerUtils.getBinaryFromId(contents.getResourceBinary().getId(), myDaoRegistry); @@ -115,8 +153,12 @@ private org.hl7.fhir.r5.model.Resource loadPackageEntity(NpmPackageVersionResour return VersionConvertorFactory_30_50 .convertResource(new org.hl7.fhir.dstu3.formats.JsonParser().parse(resourceContents)); case R4: + org.hl7.fhir.r4.model.Resource r = new org.hl7.fhir.r4.formats.JsonParser().parse(resourceContents); + if (r instanceof org.hl7.fhir.r4.model.StructureMap ) { + cleanModifierExtensions((org.hl7.fhir.r4.model.StructureMap) r); + } return VersionConvertorFactory_40_50 - .convertResource(new org.hl7.fhir.r4.formats.JsonParser().parse(resourceContents)); + .convertResource(r); case R4B: return VersionConvertorFactory_43_50 .convertResource(new org.hl7.fhir.r4b.formats.JsonParser().parse(resourceContents)); @@ -224,7 +266,24 @@ public void loadIg(List igs, Map bina Resource r = null; try { r = loadResourceByVersion(npm.fhirVersion(), TextFile.streamToBytes(pi.load("package", s)), s); - this.getContext().cacheResource(r); + // https://github.com/ahdis/matchbox/issues/227 + if (r instanceof org.hl7.fhir.r5.model.StructureMap ) { + cleanModifierExtensions((org.hl7.fhir.r5.model.StructureMap) r); + } + if (r instanceof org.hl7.fhir.r5.model.ConceptMap ) { + cleanModifierExtensions((org.hl7.fhir.r5.model.ConceptMap) r); + } + if (r instanceof CanonicalResource) { + CanonicalResource m = (CanonicalResource) r; + String url = m.getUrl(); + if (this.getContext().hasResource(r.getClass(), url)) { + log.error("Duplicate canonical resource: " + r.getClass().getName() + " from package " +pi.name() + "#" + pi.version() + " with url " + url); + } else { + this.getContext().cacheResource(r); + } + } else { + log.error("Resource is not a CanonicalResource: " + r.getClass().getName() + " from package " +pi.name() + "#" + pi.version()); + } } catch (FHIRException e) { log.error(s, e); } catch (IOException e) { diff --git a/matchbox-server/with-alis/application.yaml b/matchbox-server/with-alis/application.yaml new file mode 100644 index 00000000000..4cef2515f1d --- /dev/null +++ b/matchbox-server/with-alis/application.yaml @@ -0,0 +1,33 @@ +server: + servlet: + context-path: /matchboxv3 +hapi: + fhir: + server_address: http://localhost:8080/matchboxv3/fhir + implementationguides: + fhir_r4_core: + name: hl7.fhir.r4.core + version: 4.0.1 + url: classpath:/hl7.fhir.r4.core.tgz + fhir_terminology: + name: hl7.terminology + version: 5.4.0 + url: classpath:/hl7.terminology#5.4.0.tgz + fhir_extensions: + name: hl7.fhir.uv.extensions.r4 + version: 1.0.0 + url: classpath:/hl7.fhir.uv.extensions.r4#1.0.0.tgz + hl7_fhir_uv_ips: + name: ch.fhir.ig.ch-alis + version: 0.2.0 + url: file:/Users/oegger/Documents/github/ch-alis/output/package.tgz + staticLocation: file:/apps/ +matchbox: + fhir: + context: + fhirVersion: 4.0.1 + txServer: http://tx.fhir.org + onlyOneEngine: true +spring: + datasource: + url: "jdbc:h2:mem:test" \ No newline at end of file diff --git a/pom.xml b/pom.xml index 2dcd1e3fd85..014dc1548b1 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ health.matchbox matchbox - 3.8.2 + 3.8.3 pom matchbox An open-source implementation to support testing and implementation of FHIR based solutions and map or