Add language validation (#2644)
* Add language validation * Add tests * Test fix
This commit is contained in:
parent
eec675457b
commit
26d030f93e
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
type: add
|
||||||
|
issue: 2644
|
||||||
|
title: "Support for validating BCP-47 (language) codes against the FHIR Languages and All-Languages ValueSets
|
||||||
|
has been improved."
|
|
@ -89,13 +89,22 @@ The following table lists vocabulary that is validated by this module:
|
||||||
<tr>
|
<tr>
|
||||||
<td>Languages (BCP-47)</td>
|
<td>Languages (BCP-47)</td>
|
||||||
<td>
|
<td>
|
||||||
ValueSet: <a href="http://hl7.org/fhir/ValueSet/mimetypes">(...)/ValueSet/mimetypes</a>
|
ValueSet: <a href="http://hl7.org/fhir/ValueSet/languages">(...)/ValueSet/languages</a>
|
||||||
|
<br/>
|
||||||
|
ValueSet: <a href="http://hl7.org/fhir/ValueSet/all-languages">(...)/ValueSet/all-languages</a>
|
||||||
<br/>
|
<br/>
|
||||||
CodeSystem: <code>urn:ietf:bcp:47</code>
|
CodeSystem: <code>urn:ietf:bcp:47</code>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
Codes are not validated, but are instead assumed to be correct. Improved validation should be
|
Codes are validated against the respective ValueSet. Support for two different ValueSets
|
||||||
added in the future, please get in touch if you would like to help.
|
is provided: The <a href="http://hl7.org/fhir/ValueSet/languages">languages</a>
|
||||||
|
ValueSet provides a collection of commonly used language codes. Only codes explicitly
|
||||||
|
referenced in this ValueSet are considered valid.
|
||||||
|
The <a href="http://hl7.org/fhir/ValueSet/languages">all-languages</a> ValueSet
|
||||||
|
accepts any valid BCP-47 code. Codes are validated using data supplied by
|
||||||
|
the
|
||||||
|
<a href="https://github.com/mattcg/language-subtag-registry">Language Subtype Registry</a>
|
||||||
|
project.
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
|
|
@ -73,6 +73,7 @@ public class JpaFhirRetrieveProvider extends SearchParamFhirRetrieveProvider {
|
||||||
// TODO: Once HAPI breaks this out from the server dependencies
|
// TODO: Once HAPI breaks this out from the server dependencies
|
||||||
// we can include it on its own.
|
// we can include it on its own.
|
||||||
ca.uhn.fhir.jpa.searchparam.SearchParameterMap hapiMap = new ca.uhn.fhir.jpa.searchparam.SearchParameterMap();
|
ca.uhn.fhir.jpa.searchparam.SearchParameterMap hapiMap = new ca.uhn.fhir.jpa.searchparam.SearchParameterMap();
|
||||||
|
hapiMap.setLoadSynchronous(true);
|
||||||
try {
|
try {
|
||||||
|
|
||||||
Method[] methods = hapiMap.getClass().getDeclaredMethods();
|
Method[] methods = hapiMap.getClass().getDeclaredMethods();
|
||||||
|
|
|
@ -1,13 +1,20 @@
|
||||||
package org.hl7.fhir.common.hapi.validation.support;
|
package org.hl7.fhir.common.hapi.validation.support;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.ConfigurationException;
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.context.support.ConceptValidationOptions;
|
import ca.uhn.fhir.context.support.ConceptValidationOptions;
|
||||||
import ca.uhn.fhir.context.support.IValidationSupport;
|
import ca.uhn.fhir.context.support.IValidationSupport;
|
||||||
import ca.uhn.fhir.context.support.ValidationSupportContext;
|
import ca.uhn.fhir.context.support.ValidationSupportContext;
|
||||||
import ca.uhn.fhir.util.ClasspathUtil;
|
import ca.uhn.fhir.util.ClasspathUtil;
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||||
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
import org.fhir.ucum.UcumEssenceService;
|
import org.fhir.ucum.UcumEssenceService;
|
||||||
import org.fhir.ucum.UcumException;
|
import org.fhir.ucum.UcumException;
|
||||||
|
import org.hl7.fhir.common.hapi.validation.validator.VersionSpecificWorkerContextWrapper;
|
||||||
import org.hl7.fhir.convertors.VersionConvertor_30_40;
|
import org.hl7.fhir.convertors.VersionConvertor_30_40;
|
||||||
import org.hl7.fhir.convertors.VersionConvertor_40_50;
|
import org.hl7.fhir.convertors.VersionConvertor_40_50;
|
||||||
import org.hl7.fhir.dstu2.model.ValueSet;
|
import org.hl7.fhir.dstu2.model.ValueSet;
|
||||||
|
@ -22,10 +29,12 @@ import java.io.InputStream;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.defaultString;
|
import static org.apache.commons.lang3.StringUtils.defaultString;
|
||||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
import static org.hl7.fhir.common.hapi.validation.support.SnapshotGeneratingValidationSupport.newVersionTypeConverter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This {@link IValidationSupport validation support module} can be used to validate codes against common
|
* This {@link IValidationSupport validation support module} can be used to validate codes against common
|
||||||
|
@ -38,6 +47,7 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
*/
|
*/
|
||||||
public class CommonCodeSystemsTerminologyService implements IValidationSupport {
|
public class CommonCodeSystemsTerminologyService implements IValidationSupport {
|
||||||
public static final String LANGUAGES_VALUESET_URL = "http://hl7.org/fhir/ValueSet/languages";
|
public static final String LANGUAGES_VALUESET_URL = "http://hl7.org/fhir/ValueSet/languages";
|
||||||
|
public static final String LANGUAGES_CODESYSTEM_URL = "urn:ietf:bcp:47";
|
||||||
public static final String MIMETYPES_VALUESET_URL = "http://hl7.org/fhir/ValueSet/mimetypes";
|
public static final String MIMETYPES_VALUESET_URL = "http://hl7.org/fhir/ValueSet/mimetypes";
|
||||||
public static final String MIMETYPES_CODESYSTEM_URL = "urn:ietf:bcp:13";
|
public static final String MIMETYPES_CODESYSTEM_URL = "urn:ietf:bcp:13";
|
||||||
public static final String CURRENCIES_CODESYSTEM_URL = "urn:iso:std:iso:4217";
|
public static final String CURRENCIES_CODESYSTEM_URL = "urn:iso:std:iso:4217";
|
||||||
|
@ -45,6 +55,7 @@ public class CommonCodeSystemsTerminologyService implements IValidationSupport {
|
||||||
public static final String COUNTRIES_CODESYSTEM_URL = "urn:iso:std:iso:3166";
|
public static final String COUNTRIES_CODESYSTEM_URL = "urn:iso:std:iso:3166";
|
||||||
public static final String UCUM_CODESYSTEM_URL = "http://unitsofmeasure.org";
|
public static final String UCUM_CODESYSTEM_URL = "http://unitsofmeasure.org";
|
||||||
public static final String UCUM_VALUESET_URL = "http://hl7.org/fhir/ValueSet/ucum-units";
|
public static final String UCUM_VALUESET_URL = "http://hl7.org/fhir/ValueSet/ucum-units";
|
||||||
|
public static final String ALL_LANGUAGES_VALUESET_URL = "http://hl7.org/fhir/ValueSet/all-languages";
|
||||||
private static final String USPS_CODESYSTEM_URL = "https://www.usps.com/";
|
private static final String USPS_CODESYSTEM_URL = "https://www.usps.com/";
|
||||||
private static final String USPS_VALUESET_URL = "http://hl7.org/fhir/us/core/ValueSet/us-core-usps-state";
|
private static final String USPS_VALUESET_URL = "http://hl7.org/fhir/us/core/ValueSet/us-core-usps-state";
|
||||||
private static final Logger ourLog = LoggerFactory.getLogger(CommonCodeSystemsTerminologyService.class);
|
private static final Logger ourLog = LoggerFactory.getLogger(CommonCodeSystemsTerminologyService.class);
|
||||||
|
@ -52,6 +63,10 @@ public class CommonCodeSystemsTerminologyService implements IValidationSupport {
|
||||||
private static Map<String, String> ISO_4217_CODES = Collections.unmodifiableMap(buildIso4217Codes());
|
private static Map<String, String> ISO_4217_CODES = Collections.unmodifiableMap(buildIso4217Codes());
|
||||||
private static Map<String, String> ISO_3166_CODES = Collections.unmodifiableMap(buildIso3166Codes());
|
private static Map<String, String> ISO_3166_CODES = Collections.unmodifiableMap(buildIso3166Codes());
|
||||||
private final FhirContext myFhirContext;
|
private final FhirContext myFhirContext;
|
||||||
|
private final VersionSpecificWorkerContextWrapper.IVersionTypeConverter myVersionConverter;
|
||||||
|
private volatile org.hl7.fhir.r5.model.ValueSet myLanguagesVs;
|
||||||
|
private volatile Map<String, String> myLanguagesLanugageMap;
|
||||||
|
private volatile Map<String, String> myLanguagesRegionMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
|
@ -60,6 +75,7 @@ public class CommonCodeSystemsTerminologyService implements IValidationSupport {
|
||||||
Validate.notNull(theFhirContext);
|
Validate.notNull(theFhirContext);
|
||||||
|
|
||||||
myFhirContext = theFhirContext;
|
myFhirContext = theFhirContext;
|
||||||
|
myVersionConverter = newVersionTypeConverter(myFhirContext.getVersion().getVersion());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -89,6 +105,52 @@ public class CommonCodeSystemsTerminologyService implements IValidationSupport {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LANGUAGES_VALUESET_URL:
|
case LANGUAGES_VALUESET_URL:
|
||||||
|
if (!LANGUAGES_CODESYSTEM_URL.equals(theCodeSystem) && !(theCodeSystem == null && theOptions.isInferSystem())) {
|
||||||
|
return new CodeValidationResult()
|
||||||
|
.setSeverity(IssueSeverity.ERROR)
|
||||||
|
.setMessage("Inappropriate CodeSystem URL \"" + theCodeSystem + "\" for ValueSet: " + theValueSetUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
IBaseResource languagesVs = myLanguagesVs;
|
||||||
|
if (languagesVs == null) {
|
||||||
|
languagesVs = theValidationSupportContext.getRootValidationSupport().fetchValueSet("http://hl7.org/fhir/ValueSet/languages");
|
||||||
|
myLanguagesVs = (org.hl7.fhir.r5.model.ValueSet) myVersionConverter.toCanonical(languagesVs);
|
||||||
|
}
|
||||||
|
Optional<org.hl7.fhir.r5.model.ValueSet.ConceptReferenceComponent> match = myLanguagesVs
|
||||||
|
.getCompose()
|
||||||
|
.getInclude()
|
||||||
|
.stream()
|
||||||
|
.flatMap(t -> t.getConcept().stream())
|
||||||
|
.filter(t -> theCode.equals(t.getCode()))
|
||||||
|
.findFirst();
|
||||||
|
if (match.isPresent()) {
|
||||||
|
return new CodeValidationResult()
|
||||||
|
.setCode(theCode)
|
||||||
|
.setDisplay(match.get().getDisplay());
|
||||||
|
} else {
|
||||||
|
return new CodeValidationResult()
|
||||||
|
.setSeverity(IssueSeverity.ERROR)
|
||||||
|
.setMessage("Code \"" + theCode + "\" is not in valueset: " + theValueSetUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
case ALL_LANGUAGES_VALUESET_URL:
|
||||||
|
if (!LANGUAGES_CODESYSTEM_URL.equals(theCodeSystem) && !(theCodeSystem == null && theOptions.isInferSystem())) {
|
||||||
|
return new CodeValidationResult()
|
||||||
|
.setSeverity(IssueSeverity.ERROR)
|
||||||
|
.setMessage("Inappropriate CodeSystem URL \"" + theCodeSystem + "\" for ValueSet: " + theValueSetUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
LookupCodeResult outcome = lookupLanguageCode(theCode);
|
||||||
|
if (outcome.isFound()) {
|
||||||
|
return new CodeValidationResult()
|
||||||
|
.setCode(theCode)
|
||||||
|
.setDisplay(outcome.getCodeDisplay());
|
||||||
|
} else {
|
||||||
|
return new CodeValidationResult()
|
||||||
|
.setSeverity(IssueSeverity.ERROR)
|
||||||
|
.setMessage("Code \"" + theCode + "\" is not in valueset: " + theValueSetUrl);
|
||||||
|
}
|
||||||
|
|
||||||
case MIMETYPES_VALUESET_URL:
|
case MIMETYPES_VALUESET_URL:
|
||||||
// This is a pretty naive implementation - Should be enhanced in future
|
// This is a pretty naive implementation - Should be enhanced in future
|
||||||
return new CodeValidationResult()
|
return new CodeValidationResult()
|
||||||
|
@ -141,6 +203,7 @@ public class CommonCodeSystemsTerminologyService implements IValidationSupport {
|
||||||
.setDisplay(lookupResult.getCodeDisplay());
|
.setDisplay(lookupResult.getCodeDisplay());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return validationResult;
|
return validationResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,6 +213,8 @@ public class CommonCodeSystemsTerminologyService implements IValidationSupport {
|
||||||
|
|
||||||
Map<String, String> map;
|
Map<String, String> map;
|
||||||
switch (theSystem) {
|
switch (theSystem) {
|
||||||
|
case LANGUAGES_CODESYSTEM_URL:
|
||||||
|
return lookupLanguageCode(theCode);
|
||||||
case UCUM_CODESYSTEM_URL:
|
case UCUM_CODESYSTEM_URL:
|
||||||
return lookupUcumCode(theCode);
|
return lookupUcumCode(theCode);
|
||||||
case MIMETYPES_CODESYSTEM_URL:
|
case MIMETYPES_CODESYSTEM_URL:
|
||||||
|
@ -186,6 +251,75 @@ public class CommonCodeSystemsTerminologyService implements IValidationSupport {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private LookupCodeResult lookupLanguageCode(String theCode) {
|
||||||
|
Map<String, String> languagesMap = myLanguagesLanugageMap;
|
||||||
|
Map<String, String> regionsMap = myLanguagesRegionMap;
|
||||||
|
if (languagesMap == null || regionsMap == null) {
|
||||||
|
|
||||||
|
ourLog.info("Loading BCP47 Language Registry");
|
||||||
|
|
||||||
|
String input = ClasspathUtil.loadResource("org/hl7/fhir/common/hapi/validation/support/registry.json");
|
||||||
|
ArrayNode map;
|
||||||
|
try {
|
||||||
|
map = (ArrayNode) new ObjectMapper().readTree(input);
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
throw new ConfigurationException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
languagesMap = new HashMap<>();
|
||||||
|
regionsMap = new HashMap<>();
|
||||||
|
|
||||||
|
for (int i = 0; i < map.size(); i++) {
|
||||||
|
ObjectNode next = (ObjectNode) map.get(i);
|
||||||
|
String type = next.get("Type").asText();
|
||||||
|
if ("language".equals(type)) {
|
||||||
|
String language = next.get("Subtag").asText();
|
||||||
|
ArrayNode descriptions = (ArrayNode) next.get("Description");
|
||||||
|
String description = null;
|
||||||
|
if (descriptions.size() > 0) {
|
||||||
|
description = descriptions.get(0).asText();
|
||||||
|
}
|
||||||
|
languagesMap.put(language, description);
|
||||||
|
}
|
||||||
|
if ("region".equals(type)) {
|
||||||
|
String region = next.get("Subtag").asText();
|
||||||
|
ArrayNode descriptions = (ArrayNode) next.get("Description");
|
||||||
|
String description = null;
|
||||||
|
if (descriptions.size() > 0) {
|
||||||
|
description = descriptions.get(0).asText();
|
||||||
|
}
|
||||||
|
regionsMap.put(region, description);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ourLog.info("Have {} languages and {} regions", languagesMap.size(), regionsMap.size());
|
||||||
|
|
||||||
|
myLanguagesLanugageMap = languagesMap;
|
||||||
|
myLanguagesRegionMap = regionsMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
int idx = StringUtils.indexOfAny(theCode, '-', '_');
|
||||||
|
String language = null;
|
||||||
|
String region = null;
|
||||||
|
if (idx > 0) {
|
||||||
|
language = languagesMap.get(theCode.substring(0, idx));
|
||||||
|
region = regionsMap.get(theCode.substring(idx + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
LookupCodeResult retVal = new LookupCodeResult();
|
||||||
|
retVal.setSearchedForCode(theCode);
|
||||||
|
retVal.setSearchedForSystem(LANGUAGES_CODESYSTEM_URL);
|
||||||
|
|
||||||
|
if (language != null && region != null) {
|
||||||
|
String display = language + " " + region;
|
||||||
|
retVal.setFound(true);
|
||||||
|
retVal.setCodeDisplay(display);
|
||||||
|
}
|
||||||
|
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
private LookupCodeResult lookupMimetypeCode(String theCode) {
|
private LookupCodeResult lookupMimetypeCode(String theCode) {
|
||||||
// This is a pretty naive implementation - Should be enhanced in future
|
// This is a pretty naive implementation - Should be enhanced in future
|
||||||
|
@ -270,6 +404,7 @@ public class CommonCodeSystemsTerminologyService implements IValidationSupport {
|
||||||
case UCUM_CODESYSTEM_URL:
|
case UCUM_CODESYSTEM_URL:
|
||||||
case MIMETYPES_CODESYSTEM_URL:
|
case MIMETYPES_CODESYSTEM_URL:
|
||||||
case USPS_CODESYSTEM_URL:
|
case USPS_CODESYSTEM_URL:
|
||||||
|
case LANGUAGES_CODESYSTEM_URL:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,6 +417,7 @@ public class CommonCodeSystemsTerminologyService implements IValidationSupport {
|
||||||
switch (theValueSetUrl) {
|
switch (theValueSetUrl) {
|
||||||
case CURRENCIES_VALUESET_URL:
|
case CURRENCIES_VALUESET_URL:
|
||||||
case LANGUAGES_VALUESET_URL:
|
case LANGUAGES_VALUESET_URL:
|
||||||
|
case ALL_LANGUAGES_VALUESET_URL:
|
||||||
case MIMETYPES_VALUESET_URL:
|
case MIMETYPES_VALUESET_URL:
|
||||||
case UCUM_VALUESET_URL:
|
case UCUM_VALUESET_URL:
|
||||||
case USPS_VALUESET_URL:
|
case USPS_VALUESET_URL:
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package org.hl7.fhir.common.hapi.validation.support;
|
package org.hl7.fhir.common.hapi.validation.support;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||||
import ca.uhn.fhir.context.support.IValidationSupport;
|
import ca.uhn.fhir.context.support.IValidationSupport;
|
||||||
import ca.uhn.fhir.context.support.ValidationSupportContext;
|
import ca.uhn.fhir.context.support.ValidationSupportContext;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
||||||
|
@ -18,6 +19,7 @@ import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
|
@ -49,26 +51,11 @@ public class SnapshotGeneratingValidationSupport implements IValidationSupport {
|
||||||
|
|
||||||
String inputUrl = null;
|
String inputUrl = null;
|
||||||
try {
|
try {
|
||||||
assert theInput.getStructureFhirVersionEnum() == myCtx.getVersion().getVersion();
|
FhirVersionEnum version = theInput.getStructureFhirVersionEnum();
|
||||||
|
assert version == myCtx.getVersion().getVersion();
|
||||||
VersionSpecificWorkerContextWrapper.IVersionTypeConverter converter;
|
|
||||||
switch (theInput.getStructureFhirVersionEnum()) {
|
|
||||||
case DSTU3:
|
|
||||||
converter = new VersionTypeConverterDstu3();
|
|
||||||
break;
|
|
||||||
case R4:
|
|
||||||
converter = new VersionTypeConverterR4();
|
|
||||||
break;
|
|
||||||
case R5:
|
|
||||||
converter = VersionSpecificWorkerContextWrapper.IDENTITY_VERSION_TYPE_CONVERTER;
|
|
||||||
break;
|
|
||||||
case DSTU2:
|
|
||||||
case DSTU2_HL7ORG:
|
|
||||||
case DSTU2_1:
|
|
||||||
default:
|
|
||||||
throw new IllegalStateException("Can not generate snapshot for version: " + theInput.getStructureFhirVersionEnum());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
VersionSpecificWorkerContextWrapper.IVersionTypeConverter converter = newVersionTypeConverter(version);
|
||||||
|
Validate.notNull(converter, "Can not generate snapshot for version: %s", version);
|
||||||
|
|
||||||
org.hl7.fhir.r5.model.StructureDefinition inputCanonical = (org.hl7.fhir.r5.model.StructureDefinition) converter.toCanonical(theInput);
|
org.hl7.fhir.r5.model.StructureDefinition inputCanonical = (org.hl7.fhir.r5.model.StructureDefinition) converter.toCanonical(theInput);
|
||||||
|
|
||||||
|
@ -103,7 +90,7 @@ public class SnapshotGeneratingValidationSupport implements IValidationSupport {
|
||||||
ProfileUtilities profileUtilities = new ProfileUtilities(context, messages, profileKnowledgeProvider);
|
ProfileUtilities profileUtilities = new ProfileUtilities(context, messages, profileKnowledgeProvider);
|
||||||
profileUtilities.generateSnapshot(baseCanonical, inputCanonical, theUrl, theWebUrl, theProfileName);
|
profileUtilities.generateSnapshot(baseCanonical, inputCanonical, theUrl, theWebUrl, theProfileName);
|
||||||
|
|
||||||
switch (theInput.getStructureFhirVersionEnum()) {
|
switch (version) {
|
||||||
case DSTU3:
|
case DSTU3:
|
||||||
org.hl7.fhir.dstu3.model.StructureDefinition generatedDstu3 = (org.hl7.fhir.dstu3.model.StructureDefinition) converter.fromCanonical(inputCanonical);
|
org.hl7.fhir.dstu3.model.StructureDefinition generatedDstu3 = (org.hl7.fhir.dstu3.model.StructureDefinition) converter.fromCanonical(inputCanonical);
|
||||||
((org.hl7.fhir.dstu3.model.StructureDefinition) theInput).getSnapshot().getElement().clear();
|
((org.hl7.fhir.dstu3.model.StructureDefinition) theInput).getSnapshot().getElement().clear();
|
||||||
|
@ -123,7 +110,7 @@ public class SnapshotGeneratingValidationSupport implements IValidationSupport {
|
||||||
case DSTU2_HL7ORG:
|
case DSTU2_HL7ORG:
|
||||||
case DSTU2_1:
|
case DSTU2_1:
|
||||||
default:
|
default:
|
||||||
throw new IllegalStateException("Can not generate snapshot for version: " + theInput.getStructureFhirVersionEnum());
|
throw new IllegalStateException("Can not generate snapshot for version: " + version);
|
||||||
}
|
}
|
||||||
|
|
||||||
return theInput;
|
return theInput;
|
||||||
|
@ -144,5 +131,27 @@ public class SnapshotGeneratingValidationSupport implements IValidationSupport {
|
||||||
return myCtx;
|
return myCtx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static VersionSpecificWorkerContextWrapper.IVersionTypeConverter newVersionTypeConverter(FhirVersionEnum version) {
|
||||||
|
VersionSpecificWorkerContextWrapper.IVersionTypeConverter converter;
|
||||||
|
switch (version) {
|
||||||
|
case DSTU3:
|
||||||
|
converter = new VersionTypeConverterDstu3();
|
||||||
|
break;
|
||||||
|
case R4:
|
||||||
|
converter = new VersionTypeConverterR4();
|
||||||
|
break;
|
||||||
|
case R5:
|
||||||
|
converter = VersionSpecificWorkerContextWrapper.IDENTITY_VERSION_TYPE_CONVERTER;
|
||||||
|
break;
|
||||||
|
case DSTU2:
|
||||||
|
case DSTU2_HL7ORG:
|
||||||
|
case DSTU2_1:
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return converter;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
This package contains the BCP47 Language Registry from
|
||||||
|
https://github.com/mattcg/language-subtag-registry
|
||||||
|
|
||||||
|
Used under the terms of the Open Data Commons Attribution License (ODC-BY).
|
File diff suppressed because it is too large
Load Diff
|
@ -5,8 +5,6 @@ import ca.uhn.fhir.context.FhirVersionEnum;
|
||||||
import ca.uhn.fhir.context.support.ConceptValidationOptions;
|
import ca.uhn.fhir.context.support.ConceptValidationOptions;
|
||||||
import ca.uhn.fhir.context.support.IValidationSupport;
|
import ca.uhn.fhir.context.support.IValidationSupport;
|
||||||
import ca.uhn.fhir.context.support.ValidationSupportContext;
|
import ca.uhn.fhir.context.support.ValidationSupportContext;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
|
||||||
|
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.r4.model.CodeSystem;
|
import org.hl7.fhir.r4.model.CodeSystem;
|
||||||
import org.hl7.fhir.r4.model.ValueSet;
|
import org.hl7.fhir.r4.model.ValueSet;
|
||||||
|
@ -14,11 +12,11 @@ import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
|
|
||||||
public class CommonCodeSystemsTerminologyServiceTest {
|
public class CommonCodeSystemsTerminologyServiceTest {
|
||||||
|
|
||||||
private CommonCodeSystemsTerminologyService mySvc;
|
private CommonCodeSystemsTerminologyService mySvc;
|
||||||
|
@ -32,25 +30,28 @@ public class CommonCodeSystemsTerminologyServiceTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUcum_LookupCode_Good() {
|
public void testUcum_LookupCode_Good() {
|
||||||
IValidationSupport.LookupCodeResult outcome = mySvc.lookupCode(new ValidationSupportContext(myCtx.getValidationSupport()), "http://unitsofmeasure.org", "Cel");
|
IValidationSupport.LookupCodeResult outcome = mySvc.lookupCode(newSupport(), "http://unitsofmeasure.org", "Cel");
|
||||||
|
assert outcome != null;
|
||||||
assertEquals(true, outcome.isFound());
|
assertEquals(true, outcome.isFound());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUcum_LookupCode_Good2() {
|
public void testUcum_LookupCode_Good2() {
|
||||||
IValidationSupport.LookupCodeResult outcome = mySvc.lookupCode(new ValidationSupportContext(myCtx.getValidationSupport()), "http://unitsofmeasure.org", "kg/m2");
|
IValidationSupport.LookupCodeResult outcome = mySvc.lookupCode(newSupport(), "http://unitsofmeasure.org", "kg/m2");
|
||||||
|
assert outcome != null;
|
||||||
assertEquals(true, outcome.isFound());
|
assertEquals(true, outcome.isFound());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUcum_LookupCode_Bad() {
|
public void testUcum_LookupCode_Bad() {
|
||||||
IValidationSupport.LookupCodeResult outcome = mySvc.lookupCode(new ValidationSupportContext(myCtx.getValidationSupport()), "http://unitsofmeasure.org", "AAAAA");
|
IValidationSupport.LookupCodeResult outcome = mySvc.lookupCode(newSupport(), "http://unitsofmeasure.org", "AAAAA");
|
||||||
|
assert outcome != null;
|
||||||
assertEquals(false, outcome.isFound());
|
assertEquals(false, outcome.isFound());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUcum_LookupCode_UnknownSystem() {
|
public void testUcum_LookupCode_UnknownSystem() {
|
||||||
IValidationSupport.LookupCodeResult outcome = mySvc.lookupCode(new ValidationSupportContext(myCtx.getValidationSupport()), "http://foo", "AAAAA");
|
IValidationSupport.LookupCodeResult outcome = mySvc.lookupCode(newSupport(), "http://foo", "AAAAA");
|
||||||
assertNull(outcome);
|
assertNull(outcome);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +59,8 @@ public class CommonCodeSystemsTerminologyServiceTest {
|
||||||
public void testUcum_ValidateCode_Good() {
|
public void testUcum_ValidateCode_Good() {
|
||||||
ValueSet vs = new ValueSet();
|
ValueSet vs = new ValueSet();
|
||||||
vs.setUrl("http://hl7.org/fhir/ValueSet/ucum-units");
|
vs.setUrl("http://hl7.org/fhir/ValueSet/ucum-units");
|
||||||
IValidationSupport.CodeValidationResult outcome = mySvc.validateCodeInValueSet(new ValidationSupportContext(myCtx.getValidationSupport()), new ConceptValidationOptions(), "http://unitsofmeasure.org", "mg", null, vs);
|
IValidationSupport.CodeValidationResult outcome = mySvc.validateCodeInValueSet(newSupport(), newOptions(), "http://unitsofmeasure.org", "mg", null, vs);
|
||||||
|
assert outcome != null;
|
||||||
assertEquals(true, outcome.isOk());
|
assertEquals(true, outcome.isOk());
|
||||||
assertEquals("(milligram)", outcome.getDisplay());
|
assertEquals("(milligram)", outcome.getDisplay());
|
||||||
}
|
}
|
||||||
|
@ -67,7 +69,8 @@ public class CommonCodeSystemsTerminologyServiceTest {
|
||||||
public void testUcum_ValidateCode_Good_SystemInferred() {
|
public void testUcum_ValidateCode_Good_SystemInferred() {
|
||||||
ValueSet vs = new ValueSet();
|
ValueSet vs = new ValueSet();
|
||||||
vs.setUrl("http://hl7.org/fhir/ValueSet/ucum-units");
|
vs.setUrl("http://hl7.org/fhir/ValueSet/ucum-units");
|
||||||
IValidationSupport.CodeValidationResult outcome = mySvc.validateCodeInValueSet(new ValidationSupportContext(myCtx.getValidationSupport()), new ConceptValidationOptions().setInferSystem(true), null, "mg", null, vs);
|
IValidationSupport.CodeValidationResult outcome = mySvc.validateCodeInValueSet(newSupport(), newOptions().setInferSystem(true), null, "mg", null, vs);
|
||||||
|
assert outcome != null;
|
||||||
assertEquals(true, outcome.isOk());
|
assertEquals(true, outcome.isOk());
|
||||||
assertEquals("(milligram)", outcome.getDisplay());
|
assertEquals("(milligram)", outcome.getDisplay());
|
||||||
}
|
}
|
||||||
|
@ -76,13 +79,76 @@ public class CommonCodeSystemsTerminologyServiceTest {
|
||||||
public void testUcum_ValidateCode_Bad() {
|
public void testUcum_ValidateCode_Bad() {
|
||||||
ValueSet vs = new ValueSet();
|
ValueSet vs = new ValueSet();
|
||||||
vs.setUrl("http://hl7.org/fhir/ValueSet/ucum-units");
|
vs.setUrl("http://hl7.org/fhir/ValueSet/ucum-units");
|
||||||
IValidationSupport.CodeValidationResult outcome = mySvc.validateCodeInValueSet(new ValidationSupportContext(myCtx.getValidationSupport()), new ConceptValidationOptions(), "http://unitsofmeasure.org", "aaaaa", null, vs);
|
IValidationSupport.CodeValidationResult outcome = mySvc.validateCodeInValueSet(newSupport(), newOptions(), "http://unitsofmeasure.org", "aaaaa", null, vs);
|
||||||
assertNull(outcome);
|
assertNull(outcome);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLanguagesLanguagesCs_GoodCode() {
|
||||||
|
IValidationSupport.CodeValidationResult outcome = mySvc.validateLookupCode(newSupport(), "en-CA", "urn:ietf:bcp:47");
|
||||||
|
assert outcome != null;
|
||||||
|
assertTrue(outcome.isOk());
|
||||||
|
assertEquals("English Canada", outcome.getDisplay());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLanguagesLanguagesCs_BadCode() {
|
||||||
|
IValidationSupport.CodeValidationResult outcome = mySvc.validateLookupCode(newSupport(), "en-FOO", "urn:ietf:bcp:47");
|
||||||
|
assertNull(outcome);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLanguages_CommonLanguagesVs_GoodCode() {
|
||||||
|
IValidationSupport.CodeValidationResult outcome = mySvc.validateCode(newSupport(), newOptions(), "urn:ietf:bcp:47", "en-US", null, "http://hl7.org/fhir/ValueSet/languages");
|
||||||
|
assert outcome != null;
|
||||||
|
assertTrue(outcome.isOk());
|
||||||
|
assertEquals("English (United States)", outcome.getDisplay());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLanguages_CommonLanguagesVs_BadCode() {
|
||||||
|
IValidationSupport.CodeValidationResult outcome = mySvc.validateCode(newSupport(), newOptions(), "urn:ietf:bcp:47", "FOO", null, "http://hl7.org/fhir/ValueSet/languages");
|
||||||
|
assert outcome != null;
|
||||||
|
assertFalse(outcome.isOk());
|
||||||
|
assertEquals("Code \"FOO\" is not in valueset: http://hl7.org/fhir/ValueSet/languages", outcome.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLanguages_CommonLanguagesVs_BadSystem() {
|
||||||
|
IValidationSupport.CodeValidationResult outcome = mySvc.validateCode(newSupport(), newOptions(), "FOO", "en-US", null, "http://hl7.org/fhir/ValueSet/languages");
|
||||||
|
assert outcome != null;
|
||||||
|
assertFalse(outcome.isOk());
|
||||||
|
assertEquals("Inappropriate CodeSystem URL \"FOO\" for ValueSet: http://hl7.org/fhir/ValueSet/languages", outcome.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLanguages_AllLanguagesVs_GoodCode() {
|
||||||
|
IValidationSupport.CodeValidationResult outcome = mySvc.validateCode(newSupport(), newOptions(), "urn:ietf:bcp:47", "en-US", null, "http://hl7.org/fhir/ValueSet/all-languages");
|
||||||
|
assert outcome != null;
|
||||||
|
assertTrue(outcome.isOk());
|
||||||
|
assertEquals("English United States", outcome.getDisplay());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLanguages_AllLanguagesVs_BadCode() {
|
||||||
|
IValidationSupport.CodeValidationResult outcome = mySvc.validateCode(newSupport(), newOptions(), "urn:ietf:bcp:47", "FOO", null, "http://hl7.org/fhir/ValueSet/all-languages");
|
||||||
|
assert outcome != null;
|
||||||
|
assertFalse(outcome.isOk());
|
||||||
|
assertEquals("Code \"FOO\" is not in valueset: http://hl7.org/fhir/ValueSet/all-languages", outcome.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLanguages_AllLanguagesVs_BadSystem() {
|
||||||
|
IValidationSupport.CodeValidationResult outcome = mySvc.validateCode(newSupport(), newOptions(), "FOO", "en-US", null, "http://hl7.org/fhir/ValueSet/all-languages");
|
||||||
|
assert outcome != null;
|
||||||
|
assertFalse(outcome.isOk());
|
||||||
|
assertEquals("Inappropriate CodeSystem URL \"FOO\" for ValueSet: http://hl7.org/fhir/ValueSet/all-languages", outcome.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFetchCodeSystemBuiltIn_Iso3166_R4() {
|
public void testFetchCodeSystemBuiltIn_Iso3166_R4() {
|
||||||
CodeSystem cs = (CodeSystem) mySvc.fetchCodeSystem(CommonCodeSystemsTerminologyService.COUNTRIES_CODESYSTEM_URL);
|
CodeSystem cs = (CodeSystem) mySvc.fetchCodeSystem(CommonCodeSystemsTerminologyService.COUNTRIES_CODESYSTEM_URL);
|
||||||
|
assert cs != null;
|
||||||
assertEquals(498, cs.getConcept().size());
|
assertEquals(498, cs.getConcept().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,6 +156,7 @@ public class CommonCodeSystemsTerminologyServiceTest {
|
||||||
public void testFetchCodeSystemBuiltIn_Iso3166_DSTU3() {
|
public void testFetchCodeSystemBuiltIn_Iso3166_DSTU3() {
|
||||||
CommonCodeSystemsTerminologyService svc = new CommonCodeSystemsTerminologyService(FhirContext.forCached(FhirVersionEnum.DSTU3));
|
CommonCodeSystemsTerminologyService svc = new CommonCodeSystemsTerminologyService(FhirContext.forCached(FhirVersionEnum.DSTU3));
|
||||||
org.hl7.fhir.dstu3.model.CodeSystem cs = (org.hl7.fhir.dstu3.model.CodeSystem) svc.fetchCodeSystem(CommonCodeSystemsTerminologyService.COUNTRIES_CODESYSTEM_URL);
|
org.hl7.fhir.dstu3.model.CodeSystem cs = (org.hl7.fhir.dstu3.model.CodeSystem) svc.fetchCodeSystem(CommonCodeSystemsTerminologyService.COUNTRIES_CODESYSTEM_URL);
|
||||||
|
assert cs != null;
|
||||||
assertEquals(498, cs.getConcept().size());
|
assertEquals(498, cs.getConcept().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,6 +164,7 @@ public class CommonCodeSystemsTerminologyServiceTest {
|
||||||
public void testFetchCodeSystemBuiltIn_Iso3166_R5() {
|
public void testFetchCodeSystemBuiltIn_Iso3166_R5() {
|
||||||
CommonCodeSystemsTerminologyService svc = new CommonCodeSystemsTerminologyService(FhirContext.forCached(FhirVersionEnum.R5));
|
CommonCodeSystemsTerminologyService svc = new CommonCodeSystemsTerminologyService(FhirContext.forCached(FhirVersionEnum.R5));
|
||||||
org.hl7.fhir.r5.model.CodeSystem cs = (org.hl7.fhir.r5.model.CodeSystem) svc.fetchCodeSystem(CommonCodeSystemsTerminologyService.COUNTRIES_CODESYSTEM_URL);
|
org.hl7.fhir.r5.model.CodeSystem cs = (org.hl7.fhir.r5.model.CodeSystem) svc.fetchCodeSystem(CommonCodeSystemsTerminologyService.COUNTRIES_CODESYSTEM_URL);
|
||||||
|
assert cs != null;
|
||||||
assertEquals(498, cs.getConcept().size());
|
assertEquals(498, cs.getConcept().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,6 +178,7 @@ public class CommonCodeSystemsTerminologyServiceTest {
|
||||||
@Test
|
@Test
|
||||||
public void testFetchCodeSystemBuiltIn_Iso_R4() {
|
public void testFetchCodeSystemBuiltIn_Iso_R4() {
|
||||||
CodeSystem cs = (CodeSystem) mySvc.fetchCodeSystem(CommonCodeSystemsTerminologyService.CURRENCIES_CODESYSTEM_URL);
|
CodeSystem cs = (CodeSystem) mySvc.fetchCodeSystem(CommonCodeSystemsTerminologyService.CURRENCIES_CODESYSTEM_URL);
|
||||||
|
assert cs != null;
|
||||||
assertEquals(182, cs.getConcept().size());
|
assertEquals(182, cs.getConcept().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,5 +199,13 @@ public class CommonCodeSystemsTerminologyServiceTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ValidationSupportContext newSupport() {
|
||||||
|
return new ValidationSupportContext(myCtx.getValidationSupport());
|
||||||
|
}
|
||||||
|
|
||||||
|
private ConceptValidationOptions newOptions() {
|
||||||
|
return new ConceptValidationOptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue