Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions docs/changelog.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
2025 Release 4.0.16
2026/01/07 Release 4.0.16

- adapt test and map for (440)
- adapt test and map for (#440)
- update org.hl7.fhir.core 6.7.10 (#448)
- support validating CodeableConcept in internal tx (448)
- support validating CodeableConcept in internal tx (#448)
- FHIR R4 validation error with R5 extension (#424)
- Fix THO loading: Unknown code '26' in the CodeSystem 'http://terminology.hl7.org/CodeSystem/object-role' version '4.0.1' (#452)
- Remove auto install ig's (did not handle -ballot versions)

2025/11/03 Release 4.0.15

Expand Down
2 changes: 1 addition & 1 deletion jmeter/test.http
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Content-Type: application/fhir+json
{
"attachment" : {
"language" : "de-CH"
^ }
}
}
]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ public MatchboxEngine getEngineR4() throws MatchboxEngineCreationException {
log.info("loaded hl7.fhir.r4.core#4.0.1 from classpath");
engine.setVersion(FhirPublication.R4.toCode());
try {
engine.loadPackage(this.getNpmPackageStream(PACKAGE_R4_TERMINOLOGY));
engine.loadPackage(this.getNpmPackageStream(PACKAGE_R4_TERMINOLOGY65));
engine.loadPackage(this.getNpmPackageStream(PACKAGE_R4_UV_EXTENSIONS));
if (this.withXVersion) {
this.removeStructureMaps(engine);
Expand Down Expand Up @@ -330,7 +330,7 @@ public MatchboxEngine getEngineR4B() throws MatchboxEngineCreationException {
log.info("loaded hl7.fhir.r4b.core#4.3.0 from classpath");
engine.setVersion(FhirPublication.R4B.toCode());
try {
engine.loadPackage(this.getNpmPackageStream(PACKAGE_R4_TERMINOLOGY));
engine.loadPackage(this.getNpmPackageStream(PACKAGE_R4_TERMINOLOGY65));
engine.loadPackage(this.getNpmPackageStream(PACKAGE_R4_UV_EXTENSIONS));
if (this.withXVersion) {
this.removeStructureMaps(engine);
Expand Down Expand Up @@ -375,7 +375,7 @@ public MatchboxEngine getEngineR5() throws MatchboxEngineCreationException {
log.info("loaded hl7.fhir.r5.core#5.0.0 from classpath");
engine.setVersion(FhirPublication.R5.toCode());
try {
engine.loadPackage(this.getNpmPackageStream(PACKAGE_R5_TERMINOLOGY));
engine.loadPackage(this.getNpmPackageStream(PACKAGE_R5_TERMINOLOGY65));
engine.loadPackage(this.getNpmPackageStream(PACKAGE_R5_UV_EXTENSIONS));
if (this.withXVersion) {
this.removeStructureMaps(engine);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,9 @@ public int compare(T arg1, T arg2) {
protected ContextUtilities cutils;
private List<String> suppressedMappings;

// matchbox patch https://github.com/ahdis/matchbox/issues/425
private Locale locale;

protected BaseWorkerContext() throws FileNotFoundException, IOException, FHIRException {
setValidationMessageLanguage(getLocale());
clock = new TimeTracker();
Expand Down Expand Up @@ -437,6 +440,7 @@ protected void copy(BaseWorkerContext other) {
cachingAllowed = other.cachingAllowed;
suppressedMappings = other.suppressedMappings;
cutils.setSuppressedMappings(other.suppressedMappings);
locale = other.locale; // matchbox patch https://github.com/ahdis/matchbox/issues/425
}
}

Expand Down Expand Up @@ -613,18 +617,21 @@ public void cacheResourceFromPackage(Resource r, PackageInformation packageInfo)
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)
// matchbox patch for duplicate resources, see https://github.com/ahdis/matchbox/issues/227 and issues/452
CanonicalResource ex = fetchResourceWithException(m.fhirType(), url);
if (ex.getVersion() != null && m.getVersion() != null && laterVersion(m.getVersion(), ex.getVersion())) {
boolean forceDrop = false;
if (url.startsWith("http://terminology.hl7.org/") && ex.getVersion()!=null && ex.getSourcePackage()!=null && ex.getVersion().equals(ex.getSourcePackage().getVersion()) ) {
forceDrop = true;
}
if (forceDrop || (ex.getVersion() != null && m.getVersion() != null && laterVersion(m.getVersion(), ex.getVersion()))) {
logger.logDebugMessage(LogCategory.INIT,
"Note replacing old version: "
"Note replacing existing version (is older): "
+ formatMessage(I18nConstants.DUPLICATE_RESOURCE_, url,
m.getVersion(), ex.getVersion(), ex.fhirType()));
m.getVersion(), ex.getVersion(), ex.fhirType()) + (forceDrop ? "forced" : ""));
dropResource(ex);
} else {
logger.logDebugMessage(LogCategory.INIT,
"Note keeping newer version: "
"Note keeping existing version (is newer): "
+ formatMessage(I18nConstants.DUPLICATE_RESOURCE_,
url,
m.getVersion(),
Expand Down Expand Up @@ -3779,7 +3786,23 @@ public <T extends Resource> List<T> fetchResourceVersions(Class<T> class_, Strin
}

public void setLocale(Locale locale) {
super.setLocale(locale);
// matchbox patch https://github.com/ahdis/matchbox/issues/425
if (this.locale == null) {
this.locale = locale;
super.setLocale(locale);
} else {
if (!this.locale.equals(locale)) {
this.locale = locale;
super.setLocale(locale);
if (locale != null) {
log.info("changing locale to" + locale.toLanguageTag());
} else {
log.info("resetting locale");
}
}
}
// END matchbox patch

if (locale == null) {
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ public void loadIg(List<ImplementationGuide> igs, Map<String, ByteProvider> bina
switch (FhirVersionEnum.forVersionString(this.getVersion())) {
case R4, R4B -> {
if (src.startsWith("hl7.terminology#6.5.0")) {
log.info("Requesting to load '{}', loading '{}' instead'", src, PACKAGE_R4_TERMINOLOGY);
log.info("Requesting to load '{}', loading '{}' instead'", src, PACKAGE_R4_TERMINOLOGY65);
loadIg(igs, binaries, PACKAGE_R4_TERMINOLOGY65, recursive);
return;
}
Expand All @@ -197,7 +197,7 @@ public void loadIg(List<ImplementationGuide> igs, Map<String, ByteProvider> bina
}
case R5 -> {
if (src.startsWith("hl7.terminology#6.5.0")) {
log.info("Requesting to load '{}', loading from classpath '{}' instead'", src, PACKAGE_R5_TERMINOLOGY);
log.info("Requesting to load '{}', loading from classpath '{}' instead'", src, PACKAGE_R5_TERMINOLOGY65);
loadIg(igs, binaries, PACKAGE_R5_TERMINOLOGY65, recursive);
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,11 +166,6 @@ public IBaseResource validate(final HttpServletRequest theRequest) {
}
}

// Check if the IG should be auto-installed
if (!cliContext.isHttpReadOnly()) {
this.ensureIgIsInstalled(theRequest.getParameter("ig"), theRequest.getParameter("profile"));
}

if (theRequest.getParameter("profile") == null) {
return this.getOoForError("The 'profile' parameter must be provided");
}
Expand Down Expand Up @@ -389,89 +384,6 @@ private IBaseResource getOoForError(final @NonNull String message) {
return VersionConvertorFactory_40_50.convertResource(oo);
}

private void ensureIgIsInstalled(@Nullable final String ig,
final String profile) {
if (ig != null) {
// Easy case, the IG is known
final var parts = ig.split("#");
if (!this.igProvider.has(parts[0], parts[1])) {
log.debug("Auto-installing the IG '{}' version '{}'", parts[0], parts[1]);
this.igProvider.installFromInternetRegistry(parts[0], parts[1]);
}
return;
}

if (profile.startsWith("http://hl7.org/fhir/")) {
log.debug("Profile '{}' is a core FHIR profile, no need to install an IG", profile);
return;
}

// Harder case, only the profile is known
final var parts = profile.split("\\|");
final String canonical;
final String version;
if (parts.length == 2) {
final Boolean found = new TransactionTemplate(this.myTxManager)
.execute(tx -> this.myPackageVersionResourceDao.getPackageVersionByCanonicalAndVersion(parts[0], parts[1]).isPresent());
if (found != null && found) {
// The profile was found in the database, the IG is installed
return;
}
canonical = parts[0];
version = parts[1];
} else {
canonical = profile;
version = null;
}

// The profile was not found in the database, we need to search for the IG that contains it
final var gson = new Gson();
final var igSearchUrl =
"https://packages.simplifier.net/catalog?canonical=%s&prerelease=false".formatted(URLEncoder.encode(canonical, StandardCharsets.UTF_8));
final SimplifierPackage[] packages;
try (final CloseableHttpClient httpclient = HttpClients.createDefault()) {
final var httpget = new HttpGet(igSearchUrl);
packages = httpclient.execute(httpget, response ->
gson.fromJson(new InputStreamReader(response.getEntity().getContent()), SimplifierPackage[].class));
} catch (final Exception e) {
log.error("Error while searching for IGs", e);
return;
}

if (packages == null || packages.length == 0) {
return;
}
log.debug("Found {} IGs for profile '{}', checking the first one ('{}')", packages.length, profile,
packages[0].getName());
if (version != null) {
// This might not be always true, but it's a good heuristic: let's use the profile version as the IG version
this.igProvider.installFromInternetRegistry(packages[0].getName(), version);
return;
}
// We have to search for the latest profile version
final var versionSearchUrl = "https://packages.simplifier.net/" + packages[0].getName();
final SimplifierPackageVersionsObject versionsObject;
try (final CloseableHttpClient httpclient = HttpClients.createDefault()) {
final var httpget = new HttpGet(versionSearchUrl);
versionsObject = httpclient.execute(httpget, response ->
gson.fromJson(new InputStreamReader(response.getEntity().getContent()), SimplifierPackageVersionsObject.class));
} catch (final Exception e) {
log.error("Error while searching for IG versions", e);
return;
}

if (versionsObject == null || versionsObject.getVersions() == null || versionsObject.getVersions().isEmpty()) {
return;
}

final var latestVersion = versionsObject.getVersions().keySet().toArray()[ versionsObject.getVersions().size()-1].toString();
try {
this.igProvider.installFromInternetRegistry(packages[0].getName(), latestVersion);
} catch (final Exception e) {
log.error("Error while installing IG version", e);
}
}

public static List<ValidationMessage> doValidate(final MatchboxEngine engine,
String content,
final EncodingEnum encoding,
Expand Down
Loading