Resolve validation errors to ValueSet with UCUM (#1948)
* Add tests for validation errors * Work on validation errors * Bump core version * Fix validation errors * Test fixes * Add changelog * Test fix * Test fix * Test fix
This commit is contained in:
parent
9e19b87e67
commit
6fb6675b1e
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 1948
|
||||||
|
title: "When validating resources containing codes in a ValueSet that included UCUM codes, the validator would
|
||||||
|
incorrectly report that the code was valid even if it was not in the ValueSet. This has been corrected."
|
|
@ -89,7 +89,6 @@ import com.github.benmanes.caffeine.cache.Cache;
|
||||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.common.base.Stopwatch;
|
import com.google.common.base.Stopwatch;
|
||||||
import net.bytebuddy.implementation.bytecode.Throw;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
import org.apache.commons.lang3.time.DateUtils;
|
import org.apache.commons.lang3.time.DateUtils;
|
||||||
|
@ -625,7 +624,138 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
||||||
TermCodeSystem cs = myCodeSystemDao.findByCodeSystemUri(system);
|
TermCodeSystem cs = myCodeSystemDao.findByCodeSystemUri(system);
|
||||||
if (cs != null) {
|
if (cs != null) {
|
||||||
|
|
||||||
TermCodeSystemVersion csv = cs.getCurrentVersion();
|
return expandValueSetHandleIncludeOrExcludeUsingDatabase(theValueSetCodeAccumulator, theAddedCodes, theIncludeOrExclude, theAdd, theCodeCounter, theQueryIndex, theWantConceptOrNull, system, cs);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (theIncludeOrExclude.getConcept().size() > 0 && theWantConceptOrNull != null) {
|
||||||
|
if (defaultString(theIncludeOrExclude.getSystem()).equals(theWantConceptOrNull.getSystem())) {
|
||||||
|
if (theIncludeOrExclude.getConcept().stream().noneMatch(t -> t.getCode().equals(theWantConceptOrNull.getCode()))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No CodeSystem matching the URL found in the database.
|
||||||
|
CodeSystem codeSystemFromContext = fetchCanonicalCodeSystemFromCompleteContext(system);
|
||||||
|
if (codeSystemFromContext == null) {
|
||||||
|
|
||||||
|
// This is a last ditch effort.. We don't have a CodeSystem resource for the desired CS, and we don't have
|
||||||
|
// anything at all in the database that matches it. So let's try asking the validation support context
|
||||||
|
// just in case there is a registered service that knows how to handle this. This can happen, for example,
|
||||||
|
// if someone creates a valueset that includes UCUM codes, since we don't have a CodeSystem resource for those
|
||||||
|
// but CommonCodeSystemsTerminologyService can validate individual codes.
|
||||||
|
List<VersionIndependentConcept> includedConcepts = null;
|
||||||
|
if (theWantConceptOrNull != null) {
|
||||||
|
includedConcepts = new ArrayList<>();
|
||||||
|
includedConcepts.add(theWantConceptOrNull);
|
||||||
|
} else if (!theIncludeOrExclude.getConcept().isEmpty()) {
|
||||||
|
includedConcepts = theIncludeOrExclude
|
||||||
|
.getConcept()
|
||||||
|
.stream()
|
||||||
|
.map(t->new VersionIndependentConcept(theIncludeOrExclude.getSystem(), t.getCode()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (includedConcepts != null) {
|
||||||
|
int foundCount = 0;
|
||||||
|
for (VersionIndependentConcept next : includedConcepts) {
|
||||||
|
LookupCodeResult lookup = myValidationSupport.lookupCode(new ValidationSupportContext(myValidationSupport), next.getSystem(), next.getCode());
|
||||||
|
if (lookup != null && lookup.isFound()) {
|
||||||
|
addOrRemoveCode(theValueSetCodeAccumulator, theAddedCodes, theAdd, next.getSystem(), next.getCode(), lookup.getCodeDisplay());
|
||||||
|
foundCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foundCount == includedConcepts.size()) {
|
||||||
|
return false;
|
||||||
|
// ELSE, we'll continue below and throw an exception
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String msg = myContext.getLocalizer().getMessage(BaseTermReadSvcImpl.class, "expansionRefersToUnknownCs", system);
|
||||||
|
if (provideExpansionOptions(theExpansionOptions).isFailOnMissingCodeSystem()) {
|
||||||
|
throw new PreconditionFailedException(msg);
|
||||||
|
} else {
|
||||||
|
ourLog.warn(msg);
|
||||||
|
theValueSetCodeAccumulator.addMessage(msg);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!theIncludeOrExclude.getConcept().isEmpty()) {
|
||||||
|
for (ValueSet.ConceptReferenceComponent next : theIncludeOrExclude.getConcept()) {
|
||||||
|
String nextCode = next.getCode();
|
||||||
|
if (theWantConceptOrNull == null || theWantConceptOrNull.getCode().equals(nextCode)) {
|
||||||
|
if (isNoneBlank(system, nextCode) && !theAddedCodes.contains(system + "|" + nextCode)) {
|
||||||
|
|
||||||
|
CodeSystem.ConceptDefinitionComponent code = findCode(codeSystemFromContext.getConcept(), nextCode);
|
||||||
|
if (code != null) {
|
||||||
|
String display = code.getDisplay();
|
||||||
|
addOrRemoveCode(theValueSetCodeAccumulator, theAddedCodes, theAdd, system, nextCode, display);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
List<CodeSystem.ConceptDefinitionComponent> concept = codeSystemFromContext.getConcept();
|
||||||
|
addConceptsToList(theValueSetCodeAccumulator, theAddedCodes, system, concept, theAdd, theWantConceptOrNull);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (hasValueSet) {
|
||||||
|
|
||||||
|
for (CanonicalType nextValueSet : theIncludeOrExclude.getValueSet()) {
|
||||||
|
ourLog.debug("Starting {} expansion around ValueSet: {}", (theAdd ? "inclusion" : "exclusion"), nextValueSet.getValueAsString());
|
||||||
|
|
||||||
|
List<VersionIndependentConcept> expanded = expandValueSet(theExpansionOptions, nextValueSet.getValueAsString());
|
||||||
|
Map<String, TermCodeSystem> uriToCodeSystem = new HashMap<>();
|
||||||
|
|
||||||
|
for (VersionIndependentConcept nextConcept : expanded) {
|
||||||
|
if (theAdd) {
|
||||||
|
|
||||||
|
if (!uriToCodeSystem.containsKey(nextConcept.getSystem())) {
|
||||||
|
TermCodeSystem codeSystem = myCodeSystemDao.findByCodeSystemUri(nextConcept.getSystem());
|
||||||
|
uriToCodeSystem.put(nextConcept.getSystem(), codeSystem);
|
||||||
|
}
|
||||||
|
|
||||||
|
TermCodeSystem codeSystem = uriToCodeSystem.get(nextConcept.getSystem());
|
||||||
|
if (codeSystem != null) {
|
||||||
|
myConceptDao
|
||||||
|
.findByCodeSystemAndCode(codeSystem.getCurrentVersion(), nextConcept.getCode())
|
||||||
|
.ifPresent(concept ->
|
||||||
|
addCodeIfNotAlreadyAdded(theValueSetCodeAccumulator, theAddedCodes, concept, theAdd, theCodeCounter)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// This will happen if we're expanding against a built-in (part of FHIR) ValueSet that
|
||||||
|
// isn't actually in the database anywhere
|
||||||
|
Collection<TermConceptDesignation> emptyCollection = Collections.emptyList();
|
||||||
|
addCodeIfNotAlreadyAdded(theValueSetCodeAccumulator, theAddedCodes, emptyCollection, theAdd, theCodeCounter, nextConcept.getSystem(), nextConcept.getCode(), nextConcept.getDisplay());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isNoneBlank(nextConcept.getSystem(), nextConcept.getCode()) && !theAdd && theAddedCodes.remove(nextConcept.getSystem() + "|" + nextConcept.getCode())) {
|
||||||
|
theValueSetCodeAccumulator.excludeConcept(nextConcept.getSystem(), nextConcept.getCode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw new InvalidRequestException("ValueSet contains " + (theAdd ? "include" : "exclude") + " criteria with no system defined");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
private Boolean expandValueSetHandleIncludeOrExcludeUsingDatabase(IValueSetConceptAccumulator theValueSetCodeAccumulator, Set<String> theAddedCodes, ValueSet.ConceptSetComponent theIncludeOrExclude, boolean theAdd, AtomicInteger theCodeCounter, int theQueryIndex, VersionIndependentConcept theWantConceptOrNull, String theSystem, TermCodeSystem theCs) {
|
||||||
|
TermCodeSystemVersion csv = theCs.getCurrentVersion();
|
||||||
FullTextEntityManager em = org.hibernate.search.jpa.Search.getFullTextEntityManager(myEntityManager);
|
FullTextEntityManager em = org.hibernate.search.jpa.Search.getFullTextEntityManager(myEntityManager);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -633,7 +763,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
||||||
* since we're going to do it without the database.
|
* since we're going to do it without the database.
|
||||||
*/
|
*/
|
||||||
if (myFulltextSearchSvc == null) {
|
if (myFulltextSearchSvc == null) {
|
||||||
expandWithoutHibernateSearch(theValueSetCodeAccumulator, csv, theAddedCodes, theIncludeOrExclude, system, theAdd, theCodeCounter);
|
expandWithoutHibernateSearch(theValueSetCodeAccumulator, csv, theAddedCodes, theIncludeOrExclude, theSystem, theAdd, theCodeCounter);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -652,7 +782,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
||||||
/*
|
/*
|
||||||
* Filters
|
* Filters
|
||||||
*/
|
*/
|
||||||
handleFilters(bool, system, qb, theIncludeOrExclude);
|
handleFilters(bool, theSystem, qb, theIncludeOrExclude);
|
||||||
|
|
||||||
Query luceneQuery = bool.createQuery();
|
Query luceneQuery = bool.createQuery();
|
||||||
|
|
||||||
|
@ -741,88 +871,6 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
||||||
} else {
|
} else {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
|
||||||
// No CodeSystem matching the URL found in the database.
|
|
||||||
|
|
||||||
CodeSystem codeSystemFromContext = fetchCanonicalCodeSystemFromCompleteContext(system);
|
|
||||||
if (codeSystemFromContext == null) {
|
|
||||||
String msg = myContext.getLocalizer().getMessage(BaseTermReadSvcImpl.class, "expansionRefersToUnknownCs", system);
|
|
||||||
if (provideExpansionOptions(theExpansionOptions).isFailOnMissingCodeSystem()) {
|
|
||||||
throw new PreconditionFailedException(msg);
|
|
||||||
} else {
|
|
||||||
ourLog.warn(msg);
|
|
||||||
theValueSetCodeAccumulator.addMessage(msg);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!theIncludeOrExclude.getConcept().isEmpty()) {
|
|
||||||
for (ValueSet.ConceptReferenceComponent next : theIncludeOrExclude.getConcept()) {
|
|
||||||
String nextCode = next.getCode();
|
|
||||||
if (theWantConceptOrNull == null || theWantConceptOrNull.getCode().equals(nextCode)) {
|
|
||||||
if (isNoneBlank(system, nextCode) && !theAddedCodes.contains(system + "|" + nextCode)) {
|
|
||||||
|
|
||||||
CodeSystem.ConceptDefinitionComponent code = findCode(codeSystemFromContext.getConcept(), nextCode);
|
|
||||||
if (code != null) {
|
|
||||||
String display = code.getDisplay();
|
|
||||||
addOrRemoveCode(theValueSetCodeAccumulator, theAddedCodes, theAdd, system, nextCode, display);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
List<CodeSystem.ConceptDefinitionComponent> concept = codeSystemFromContext.getConcept();
|
|
||||||
addConceptsToList(theValueSetCodeAccumulator, theAddedCodes, system, concept, theAdd, theWantConceptOrNull);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (hasValueSet) {
|
|
||||||
|
|
||||||
for (CanonicalType nextValueSet : theIncludeOrExclude.getValueSet()) {
|
|
||||||
ourLog.debug("Starting {} expansion around ValueSet: {}", (theAdd ? "inclusion" : "exclusion"), nextValueSet.getValueAsString());
|
|
||||||
|
|
||||||
List<VersionIndependentConcept> expanded = expandValueSet(theExpansionOptions, nextValueSet.getValueAsString());
|
|
||||||
Map<String, TermCodeSystem> uriToCodeSystem = new HashMap<>();
|
|
||||||
|
|
||||||
for (VersionIndependentConcept nextConcept : expanded) {
|
|
||||||
if (theAdd) {
|
|
||||||
|
|
||||||
if (!uriToCodeSystem.containsKey(nextConcept.getSystem())) {
|
|
||||||
TermCodeSystem codeSystem = myCodeSystemDao.findByCodeSystemUri(nextConcept.getSystem());
|
|
||||||
uriToCodeSystem.put(nextConcept.getSystem(), codeSystem);
|
|
||||||
}
|
|
||||||
|
|
||||||
TermCodeSystem codeSystem = uriToCodeSystem.get(nextConcept.getSystem());
|
|
||||||
if (codeSystem != null) {
|
|
||||||
myConceptDao
|
|
||||||
.findByCodeSystemAndCode(codeSystem.getCurrentVersion(), nextConcept.getCode())
|
|
||||||
.ifPresent(concept ->
|
|
||||||
addCodeIfNotAlreadyAdded(theValueSetCodeAccumulator, theAddedCodes, concept, theAdd, theCodeCounter)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// This will happen if we're expanding against a built-in (part of FHIR) ValueSet that
|
|
||||||
// isn't actually in the database anywhere
|
|
||||||
Collection<TermConceptDesignation> emptyCollection = Collections.emptyList();
|
|
||||||
addCodeIfNotAlreadyAdded(theValueSetCodeAccumulator, theAddedCodes, emptyCollection, theAdd, theCodeCounter, nextConcept.getSystem(), nextConcept.getCode(), nextConcept.getDisplay());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (isNoneBlank(nextConcept.getSystem(), nextConcept.getCode()) && !theAdd && theAddedCodes.remove(nextConcept.getSystem() + "|" + nextConcept.getCode())) {
|
|
||||||
theValueSetCodeAccumulator.excludeConcept(nextConcept.getSystem(), nextConcept.getCode());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
throw new InvalidRequestException("ValueSet contains " + (theAdd ? "include" : "exclude") + " criteria with no system defined");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private @Nonnull
|
private @Nonnull
|
||||||
|
@ -1939,12 +1987,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public CodeValidationResult validateCodeInValueSet(ValidationSupportContext theValidationSupportContext, ConceptValidationOptions theOptions, String theCodeSystem, String theCode, String theDisplay, @Nonnull IBaseResource theValueSet) {
|
public CodeValidationResult validateCodeInValueSet(ValidationSupportContext theValidationSupportContext, ConceptValidationOptions theOptions, String theCodeSystem, String theCode, String theDisplay, @Nonnull IBaseResource theValueSet) {
|
||||||
|
invokeRunnableForUnitTest();
|
||||||
if (myInvokeOnNextCallForUnitTest != null) {
|
|
||||||
Runnable invokeOnNextCallForUnitTest = myInvokeOnNextCallForUnitTest;
|
|
||||||
myInvokeOnNextCallForUnitTest = null;
|
|
||||||
invokeOnNextCallForUnitTest.run();
|
|
||||||
}
|
|
||||||
|
|
||||||
IPrimitiveType<?> urlPrimitive = myContext.newTerser().getSingleValueOrNull(theValueSet, "url", IPrimitiveType.class);
|
IPrimitiveType<?> urlPrimitive = myContext.newTerser().getSingleValueOrNull(theValueSet, "url", IPrimitiveType.class);
|
||||||
String url = urlPrimitive.getValueAsString();
|
String url = urlPrimitive.getValueAsString();
|
||||||
|
@ -2115,6 +2158,17 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is only used for unit tests to test failure conditions
|
||||||
|
*/
|
||||||
|
static void invokeRunnableForUnitTest() {
|
||||||
|
if (myInvokeOnNextCallForUnitTest != null) {
|
||||||
|
Runnable invokeOnNextCallForUnitTest = myInvokeOnNextCallForUnitTest;
|
||||||
|
myInvokeOnNextCallForUnitTest = null;
|
||||||
|
invokeOnNextCallForUnitTest.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public static void setInvokeOnNextCallForUnitTest(Runnable theInvokeOnNextCallForUnitTest) {
|
public static void setInvokeOnNextCallForUnitTest(Runnable theInvokeOnNextCallForUnitTest) {
|
||||||
myInvokeOnNextCallForUnitTest = theInvokeOnNextCallForUnitTest;
|
myInvokeOnNextCallForUnitTest = theInvokeOnNextCallForUnitTest;
|
||||||
|
|
|
@ -101,6 +101,8 @@ public class TermReadSvcR4 extends BaseTermReadSvcImpl implements ITermReadSvcR4
|
||||||
@CoverageIgnore
|
@CoverageIgnore
|
||||||
@Override
|
@Override
|
||||||
public IValidationSupport.CodeValidationResult validateCode(ValidationSupportContext theValidationSupportContext, ConceptValidationOptions theOptions, String theCodeSystem, String theCode, String theDisplay, String theValueSetUrl) {
|
public IValidationSupport.CodeValidationResult validateCode(ValidationSupportContext theValidationSupportContext, ConceptValidationOptions theOptions, String theCodeSystem, String theCode, String theDisplay, String theValueSetUrl) {
|
||||||
|
invokeRunnableForUnitTest();
|
||||||
|
|
||||||
Optional<VersionIndependentConcept> codeOpt = Optional.empty();
|
Optional<VersionIndependentConcept> codeOpt = Optional.empty();
|
||||||
boolean haveValidated = false;
|
boolean haveValidated = false;
|
||||||
|
|
||||||
|
|
|
@ -145,7 +145,8 @@ public class FhirResourceDaoR4QueryCountTest extends BaseJpaR4Test {
|
||||||
// Validate once
|
// Validate once
|
||||||
myCaptureQueriesListener.clear();
|
myCaptureQueriesListener.clear();
|
||||||
myObservationDao.validate(obs, null, null, null, null, null, null);
|
myObservationDao.validate(obs, null, null, null, null, null, null);
|
||||||
assertEquals(9, myCaptureQueriesListener.getSelectQueriesForCurrentThread().size());
|
myCaptureQueriesListener.logSelectQueriesForCurrentThread();
|
||||||
|
assertEquals(10, myCaptureQueriesListener.getSelectQueriesForCurrentThread().size());
|
||||||
assertEquals(0, myCaptureQueriesListener.getUpdateQueriesForCurrentThread().size());
|
assertEquals(0, myCaptureQueriesListener.getUpdateQueriesForCurrentThread().size());
|
||||||
assertEquals(0, myCaptureQueriesListener.getInsertQueriesForCurrentThread().size());
|
assertEquals(0, myCaptureQueriesListener.getInsertQueriesForCurrentThread().size());
|
||||||
assertEquals(0, myCaptureQueriesListener.getDeleteQueriesForCurrentThread().size());
|
assertEquals(0, myCaptureQueriesListener.getDeleteQueriesForCurrentThread().size());
|
||||||
|
|
|
@ -5,6 +5,8 @@ import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||||
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
||||||
|
import ca.uhn.fhir.jpa.entity.TermValueSet;
|
||||||
|
import ca.uhn.fhir.jpa.entity.TermValueSetPreExpansionStatusEnum;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||||
import ca.uhn.fhir.jpa.term.BaseTermReadSvcImpl;
|
import ca.uhn.fhir.jpa.term.BaseTermReadSvcImpl;
|
||||||
import ca.uhn.fhir.jpa.term.api.ITermCodeSystemStorageSvc;
|
import ca.uhn.fhir.jpa.term.api.ITermCodeSystemStorageSvc;
|
||||||
|
@ -12,6 +14,8 @@ import ca.uhn.fhir.jpa.term.api.ITermReadSvc;
|
||||||
import ca.uhn.fhir.jpa.term.custom.CustomTerminologySet;
|
import ca.uhn.fhir.jpa.term.custom.CustomTerminologySet;
|
||||||
import ca.uhn.fhir.jpa.validation.JpaValidationSupportChain;
|
import ca.uhn.fhir.jpa.validation.JpaValidationSupportChain;
|
||||||
import ca.uhn.fhir.jpa.validation.ValidationSettings;
|
import ca.uhn.fhir.jpa.validation.ValidationSettings;
|
||||||
|
import ca.uhn.fhir.parser.LenientErrorHandler;
|
||||||
|
import ca.uhn.fhir.parser.StrictErrorHandler;
|
||||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||||
import ca.uhn.fhir.rest.api.ValidationModeEnum;
|
import ca.uhn.fhir.rest.api.ValidationModeEnum;
|
||||||
|
@ -91,6 +95,122 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
|
||||||
@Autowired
|
@Autowired
|
||||||
private ValidationSettings myValidationSettings;
|
private ValidationSettings myValidationSettings;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use a valueset that explicitly brings in some UCUM codes
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testValidateCodeInValueSetWithBuiltInCodeSystem() throws IOException {
|
||||||
|
myValueSetDao.create(loadResourceFromClasspath(ValueSet.class, "/r4/bl/bb-vs.json"));
|
||||||
|
myStructureDefinitionDao.create(loadResourceFromClasspath(StructureDefinition.class, "/r4/bl/bb-sd.json"));
|
||||||
|
|
||||||
|
runInTransaction(() -> {
|
||||||
|
TermValueSet vs = myTermValueSetDao.findByUrl("https://bb/ValueSet/BBDemographicAgeUnit").orElseThrow(() -> new IllegalArgumentException());
|
||||||
|
assertEquals(TermValueSetPreExpansionStatusEnum.NOT_EXPANDED, vs.getExpansionStatus());
|
||||||
|
});
|
||||||
|
|
||||||
|
OperationOutcome outcome;
|
||||||
|
|
||||||
|
// Use a code that's in the ValueSet
|
||||||
|
{
|
||||||
|
outcome = (OperationOutcome) myObservationDao.validate(loadResourceFromClasspath(Observation.class, "/r4/bl/bb-obs-code-in-valueset.json"), null, null, null, null, null, mySrd).getOperationOutcome();
|
||||||
|
String outcomeStr = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome);
|
||||||
|
ourLog.info("Validation outcome: {}", outcomeStr);
|
||||||
|
assertThat(outcomeStr, not(containsString("\"error\"")));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use a code that's not in the ValueSet
|
||||||
|
try {
|
||||||
|
outcome = (OperationOutcome) myObservationDao.validate(loadResourceFromClasspath(Observation.class, "/r4/bl/bb-obs-code-not-in-valueset.json"), null, null, null, null, null, mySrd).getOperationOutcome();
|
||||||
|
String outcomeStr = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome);
|
||||||
|
ourLog.info("Validation outcome: {}", outcomeStr);
|
||||||
|
fail();
|
||||||
|
} catch (PreconditionFailedException e) {
|
||||||
|
outcome = (OperationOutcome) e.getOperationOutcome();
|
||||||
|
String outcomeStr = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome);
|
||||||
|
ourLog.info("Validation outcome: {}", outcomeStr);
|
||||||
|
assertThat(outcomeStr, containsString("Could not confirm that the codes provided are in the value set https://bb/ValueSet/BBDemographicAgeUnit, and a code from this value set is required"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Before, the VS wasn't pre-expanded. Try again with it pre-expanded
|
||||||
|
runInTransaction(() -> {
|
||||||
|
TermValueSet vs = myTermValueSetDao.findByUrl("https://bb/ValueSet/BBDemographicAgeUnit").orElseThrow(() -> new IllegalArgumentException());
|
||||||
|
assertEquals(TermValueSetPreExpansionStatusEnum.NOT_EXPANDED, vs.getExpansionStatus());
|
||||||
|
});
|
||||||
|
|
||||||
|
myTermReadSvc.preExpandDeferredValueSetsToTerminologyTables();
|
||||||
|
|
||||||
|
runInTransaction(() -> {
|
||||||
|
TermValueSet vs = myTermValueSetDao.findByUrl("https://bb/ValueSet/BBDemographicAgeUnit").orElseThrow(() -> new IllegalArgumentException());
|
||||||
|
assertEquals(TermValueSetPreExpansionStatusEnum.EXPANDED, vs.getExpansionStatus());
|
||||||
|
});
|
||||||
|
|
||||||
|
// Use a code that's in the ValueSet
|
||||||
|
{
|
||||||
|
outcome = (OperationOutcome) myObservationDao.validate(loadResourceFromClasspath(Observation.class, "/r4/bl/bb-obs-code-in-valueset.json"), null, null, null, null, null, mySrd).getOperationOutcome();
|
||||||
|
String outcomeStr = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome);
|
||||||
|
ourLog.info("Validation outcome: {}", outcomeStr);
|
||||||
|
assertThat(outcomeStr, not(containsString("\"error\"")));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use a code that's not in the ValueSet
|
||||||
|
try {
|
||||||
|
outcome = (OperationOutcome) myObservationDao.validate(loadResourceFromClasspath(Observation.class, "/r4/bl/bb-obs-code-not-in-valueset.json"), null, null, null, null, null, mySrd).getOperationOutcome();
|
||||||
|
String outcomeStr = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome);
|
||||||
|
ourLog.info("Validation outcome: {}", outcomeStr);
|
||||||
|
fail();
|
||||||
|
} catch (PreconditionFailedException e) {
|
||||||
|
outcome = (OperationOutcome) e.getOperationOutcome();
|
||||||
|
String outcomeStr = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome);
|
||||||
|
ourLog.info("Validation outcome: {}", outcomeStr);
|
||||||
|
assertThat(outcomeStr, containsString("Could not confirm that the codes provided are in the value set https://bb/ValueSet/BBDemographicAgeUnit, and a code from this value set is required"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateCodeUsingQuantityBinding() throws IOException {
|
||||||
|
myValueSetDao.create(loadResourceFromClasspath(ValueSet.class, "/r4/bl/bb-vs.json"));
|
||||||
|
myStructureDefinitionDao.create(loadResourceFromClasspath(StructureDefinition.class, "/r4/bl/bb-sd.json"));
|
||||||
|
|
||||||
|
runInTransaction(() -> {
|
||||||
|
TermValueSet vs = myTermValueSetDao.findByUrl("https://bb/ValueSet/BBDemographicAgeUnit").orElseThrow(() -> new IllegalArgumentException());
|
||||||
|
assertEquals(TermValueSetPreExpansionStatusEnum.NOT_EXPANDED, vs.getExpansionStatus());
|
||||||
|
});
|
||||||
|
|
||||||
|
OperationOutcome outcome;
|
||||||
|
|
||||||
|
// Use the wrong datatype
|
||||||
|
try {
|
||||||
|
myFhirCtx.setParserErrorHandler(new LenientErrorHandler());
|
||||||
|
Observation resource = loadResourceFromClasspath(Observation.class, "/r4/bl/bb-obs-value-is-not-quantity2.json");
|
||||||
|
outcome = (OperationOutcome) myObservationDao.validate(resource, null, null, null, null, null, mySrd).getOperationOutcome();
|
||||||
|
String outcomeStr = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome);
|
||||||
|
ourLog.info("Validation outcome: {}", outcomeStr);
|
||||||
|
fail();
|
||||||
|
} catch (PreconditionFailedException e) {
|
||||||
|
outcome = (OperationOutcome) e.getOperationOutcome();
|
||||||
|
String outcomeStr = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome);
|
||||||
|
ourLog.info("Validation outcome: {}", outcomeStr);
|
||||||
|
assertThat(outcomeStr, containsString("\"error\""));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the wrong datatype
|
||||||
|
try {
|
||||||
|
myFhirCtx.setParserErrorHandler(new LenientErrorHandler());
|
||||||
|
Observation resource = loadResourceFromClasspath(Observation.class, "/r4/bl/bb-obs-value-is-not-quantity.json");
|
||||||
|
outcome = (OperationOutcome) myObservationDao.validate(resource, null, null, null, null, null, mySrd).getOperationOutcome();
|
||||||
|
String outcomeStr = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome);
|
||||||
|
ourLog.info("Validation outcome: {}", outcomeStr);
|
||||||
|
fail();
|
||||||
|
} catch (PreconditionFailedException e) {
|
||||||
|
outcome = (OperationOutcome) e.getOperationOutcome();
|
||||||
|
String outcomeStr = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome);
|
||||||
|
ourLog.info("Validation outcome: {}", outcomeStr);
|
||||||
|
assertThat(outcomeStr, containsString("The Profile \\\"https://bb/StructureDefinition/BBDemographicAge\\\" definition allows for the type Quantity but found type string"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a loinc valueset that expands to more results than the expander is willing to do
|
* Create a loinc valueset that expands to more results than the expander is willing to do
|
||||||
* in memory, and make sure we can still validate correctly, even if we're using
|
* in memory, and make sure we can still validate correctly, even if we're using
|
||||||
|
@ -413,10 +533,16 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
|
||||||
obs.getCode().getCodingFirstRep().setSystem("http://example.com/codesystem");
|
obs.getCode().getCodingFirstRep().setSystem("http://example.com/codesystem");
|
||||||
obs.getCode().getCodingFirstRep().setCode("foo-foo");
|
obs.getCode().getCodingFirstRep().setCode("foo-foo");
|
||||||
obs.getCode().getCodingFirstRep().setDisplay("Some Code");
|
obs.getCode().getCodingFirstRep().setDisplay("Some Code");
|
||||||
|
try {
|
||||||
outcome = (OperationOutcome) myObservationDao.validate(obs, null, null, null, ValidationModeEnum.CREATE, "http://example.com/structuredefinition", mySrd).getOperationOutcome();
|
outcome = (OperationOutcome) myObservationDao.validate(obs, null, null, null, ValidationModeEnum.CREATE, "http://example.com/structuredefinition", mySrd).getOperationOutcome();
|
||||||
ourLog.info("Outcome: {}", myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
|
ourLog.info("Outcome: {}", myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
|
||||||
assertEquals("Unknown code in fragment CodeSystem 'http://example.com/codesystem#foo-foo'", outcome.getIssueFirstRep().getDiagnostics());
|
fail();
|
||||||
assertEquals(OperationOutcome.IssueSeverity.WARNING, outcome.getIssueFirstRep().getSeverity());
|
} catch (PreconditionFailedException e) {
|
||||||
|
OperationOutcome oo = (OperationOutcome) e.getOperationOutcome();
|
||||||
|
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(oo));
|
||||||
|
assertEquals("None of the codes provided are in the value set http://example.com/valueset (http://example.com/valueset), and a code from this value set is required) (codes = http://example.com/codesystem#foo-foo)", oo.getIssueFirstRep().getDiagnostics());
|
||||||
|
assertEquals(OperationOutcome.IssueSeverity.ERROR, oo.getIssueFirstRep().getSeverity());
|
||||||
|
}
|
||||||
|
|
||||||
// Correct codesystem, Code in codesystem
|
// Correct codesystem, Code in codesystem
|
||||||
obs.getCode().getCodingFirstRep().setSystem("http://example.com/codesystem");
|
obs.getCode().getCodingFirstRep().setSystem("http://example.com/codesystem");
|
||||||
|
@ -610,6 +736,12 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testValidate_TermSvcHasNpe() {
|
public void testValidate_TermSvcHasNpe() {
|
||||||
|
|
||||||
|
CodeSystem cs = new CodeSystem();
|
||||||
|
cs.setUrl("http://FOO");
|
||||||
|
cs.setContent(CodeSystem.CodeSystemContentMode.NOTPRESENT);
|
||||||
|
myCodeSystemDao.create(cs);
|
||||||
|
|
||||||
BaseTermReadSvcImpl.setInvokeOnNextCallForUnitTest(() -> {
|
BaseTermReadSvcImpl.setInvokeOnNextCallForUnitTest(() -> {
|
||||||
throw new NullPointerException("MY ERROR");
|
throw new NullPointerException("MY ERROR");
|
||||||
});
|
});
|
||||||
|
@ -623,18 +755,15 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
|
||||||
obs.setStatus(ObservationStatus.FINAL);
|
obs.setStatus(ObservationStatus.FINAL);
|
||||||
obs.setValue(new StringType("This is the value"));
|
obs.setValue(new StringType("This is the value"));
|
||||||
|
|
||||||
OperationOutcome oo;
|
|
||||||
|
|
||||||
// Valid code
|
// Valid code
|
||||||
obs.getText().setStatus(Narrative.NarrativeStatus.GENERATED);
|
obs.getText().setStatus(Narrative.NarrativeStatus.GENERATED);
|
||||||
obs.getCode().getCodingFirstRep().setSystem("http://loinc.org").setCode("CODE99999").setDisplay("Display 3");
|
obs.getCode().getCodingFirstRep().setSystem("http://FOO").setCode("CODE99999").setDisplay("Display 3");
|
||||||
try {
|
|
||||||
validateAndReturnOutcome(obs);
|
|
||||||
fail();
|
|
||||||
} catch (NullPointerException e) {
|
|
||||||
assertEquals("MY ERROR", e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
OperationOutcome oo = validateAndReturnOutcome(obs);
|
||||||
|
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(oo));
|
||||||
|
assertEquals("Error MY ERROR validating Coding: java.lang.NullPointerException: MY ERROR", oo.getIssueFirstRep().getDiagnostics());
|
||||||
|
assertEquals(OperationOutcome.IssueSeverity.ERROR, oo.getIssueFirstRep().getSeverity());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -943,6 +1072,7 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
|
||||||
BaseTermReadSvcImpl.setInvokeOnNextCallForUnitTest(null);
|
BaseTermReadSvcImpl.setInvokeOnNextCallForUnitTest(null);
|
||||||
|
|
||||||
myValidationSettings.setLocalReferenceValidationDefaultPolicy(IResourceValidator.ReferenceValidationPolicy.IGNORE);
|
myValidationSettings.setLocalReferenceValidationDefaultPolicy(IResourceValidator.ReferenceValidationPolicy.IGNORE);
|
||||||
|
myFhirCtx.setParserErrorHandler(new StrictErrorHandler());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -198,6 +198,25 @@ public class NpmTestR4 extends BaseJpaR4Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInstallR4PackageWithNoDescription() throws Exception {
|
||||||
|
myDaoConfig.setAllowExternalReferences(true);
|
||||||
|
|
||||||
|
byte[] bytes = loadClasspathBytes("/packages/UK.Core.r4-1.1.0.tgz");
|
||||||
|
myFakeNpmServlet.myResponses.put("/UK.Core.r4/1.1.0", bytes);
|
||||||
|
|
||||||
|
PackageInstallationSpec spec = new PackageInstallationSpec().setName("UK.Core.r4").setVersion("1.1.0").setInstallMode(PackageInstallationSpec.InstallModeEnum.STORE_AND_INSTALL);
|
||||||
|
igInstaller.install(spec);
|
||||||
|
|
||||||
|
// Be sure no further communication with the server
|
||||||
|
JettyUtil.closeServer(myServer);
|
||||||
|
|
||||||
|
// Make sure we can fetch the package by ID and Version
|
||||||
|
NpmPackage pkg = myPackageCacheManager.loadPackage("UK.Core.r4", "1.1.0");
|
||||||
|
assertEquals(null, pkg.description());
|
||||||
|
assertEquals("UK.Core.r4", pkg.name());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLoadPackageMetadata() throws Exception {
|
public void testLoadPackageMetadata() throws Exception {
|
||||||
myDaoConfig.setAllowExternalReferences(true);
|
myDaoConfig.setAllowExternalReferences(true);
|
||||||
|
|
Binary file not shown.
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"code": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"code": "L7b8daLEuY",
|
||||||
|
"system": "https://bbl.health"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"meta": {
|
||||||
|
"profile": [
|
||||||
|
"https://bb/StructureDefinition/BBDemographicAge"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"resourceType": "Observation",
|
||||||
|
"status": "final",
|
||||||
|
"valueQuantity" : {
|
||||||
|
"system" : "http://unitsofmeasure.org",
|
||||||
|
"code" : "mo",
|
||||||
|
"value" : 8
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"code": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"code": "L7b8daLEuY",
|
||||||
|
"system": "https://bbl.health"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"meta": {
|
||||||
|
"profile": [
|
||||||
|
"https://bb/StructureDefinition/BBDemographicAge"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"resourceType": "Observation",
|
||||||
|
"status": "final",
|
||||||
|
"valueQuantity" : {
|
||||||
|
"system" : "http://unitsofmeasure.org",
|
||||||
|
"code" : "cm",
|
||||||
|
"value" : 8
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"meta": {
|
||||||
|
"profile": [
|
||||||
|
"https://bb/StructureDefinition/BBDemographicAge"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"code": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"code": "L7b8daLEuY",
|
||||||
|
"system": "https://bbl.health"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"resourceType": "Observation",
|
||||||
|
"status": "final",
|
||||||
|
"valueString" : "test"
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"meta": {
|
||||||
|
"profile": [
|
||||||
|
"https://bb/StructureDefinition/BBDemographicAge"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"code": {
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"code": "L7b8daLEuY",
|
||||||
|
"system": "https://bbl.health"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"resourceType": "Observation",
|
||||||
|
"status": "final",
|
||||||
|
"valueDecimal" : 1.23
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,42 @@
|
||||||
|
{
|
||||||
|
"resourceType": "ValueSet",
|
||||||
|
"id": "BBDemographicAgeUnit",
|
||||||
|
"text": {
|
||||||
|
"status": "generated",
|
||||||
|
"div": "<div xmlns=\"http://www.w3.org/1999/xhtml\"></div>"
|
||||||
|
},
|
||||||
|
"url": "https://bb/ValueSet/BBDemographicAgeUnit",
|
||||||
|
"name": "BBDemographicAgeUnit",
|
||||||
|
"title": "Babylon Demographic Age Unit",
|
||||||
|
"status": "draft",
|
||||||
|
"version": "20190731",
|
||||||
|
"experimental": false,
|
||||||
|
"description": "Age Unit",
|
||||||
|
"publisher": "Babylon Partners, Ltd.",
|
||||||
|
"immutable": false,
|
||||||
|
"compose": {
|
||||||
|
"include": [
|
||||||
|
{
|
||||||
|
"system": "http://unitsofmeasure.org",
|
||||||
|
"concept": [
|
||||||
|
{
|
||||||
|
"code": "a",
|
||||||
|
"display": "years"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "mo",
|
||||||
|
"display": "months"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "wk",
|
||||||
|
"display": "weeks"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "d",
|
||||||
|
"display": "days"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -38,6 +38,7 @@ import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamUri;
|
||||||
import ca.uhn.fhir.jpa.model.entity.SearchParamPresent;
|
import ca.uhn.fhir.jpa.model.entity.SearchParamPresent;
|
||||||
import ca.uhn.fhir.util.VersionEnum;
|
import ca.uhn.fhir.util.VersionEnum;
|
||||||
|
|
||||||
|
import javax.persistence.Column;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
@ -121,6 +122,9 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
|
||||||
pkgVerRes.addForeignKey("20200610.12", "FK_NPM_PKVR_RESID").toColumn("BINARY_RES_ID").references("HFJ_RESOURCE", "RES_ID");
|
pkgVerRes.addForeignKey("20200610.12", "FK_NPM_PKVR_RESID").toColumn("BINARY_RES_ID").references("HFJ_RESOURCE", "RES_ID");
|
||||||
pkgVerRes.addIndex("20200610.13", "IDX_PACKVERRES_URL").unique(false).withColumns("CANONICAL_URL");
|
pkgVerRes.addIndex("20200610.13", "IDX_PACKVERRES_URL").unique(false).withColumns("CANONICAL_URL");
|
||||||
|
|
||||||
|
pkgVerRes.modifyColumn("20200629.1", "PKG_DESC").nullable().withType(ColumnTypeEnum.STRING, 200);
|
||||||
|
pkgVerRes.modifyColumn("20200629.2", "DESC_UPPER").nullable().withType(ColumnTypeEnum.STRING, 200);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void init501() { //20200514 - present
|
private void init501() { //20200514 - present
|
||||||
|
|
|
@ -74,9 +74,9 @@ public class NpmPackageVersionEntity {
|
||||||
@Temporal(TemporalType.TIMESTAMP)
|
@Temporal(TemporalType.TIMESTAMP)
|
||||||
@Column(name = "SAVED_TIME", nullable = false)
|
@Column(name = "SAVED_TIME", nullable = false)
|
||||||
private Date mySavedTime;
|
private Date mySavedTime;
|
||||||
@Column(name = "PKG_DESC", nullable = false, length = 200)
|
@Column(name = "PKG_DESC", nullable = true, length = 200)
|
||||||
private String myDescription;
|
private String myDescription;
|
||||||
@Column(name = "DESC_UPPER", nullable = false, length = 200)
|
@Column(name = "DESC_UPPER", nullable = true, length = 200)
|
||||||
private String myDescriptionUpper;
|
private String myDescriptionUpper;
|
||||||
@Column(name = "CURRENT_VERSION", nullable = false)
|
@Column(name = "CURRENT_VERSION", nullable = false)
|
||||||
private boolean myCurrentVersion;
|
private boolean myCurrentVersion;
|
||||||
|
|
|
@ -415,6 +415,16 @@ public final class HapiWorkerContext extends I18nBase implements IWorkerContext
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getClientRetryCount() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IWorkerContext setClientRetryCount(int value) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
public static ConceptValidationOptions convertConceptValidationOptions(ValidationOptions theOptions) {
|
public static ConceptValidationOptions convertConceptValidationOptions(ValidationOptions theOptions) {
|
||||||
ConceptValidationOptions retVal = new ConceptValidationOptions();
|
ConceptValidationOptions retVal = new ConceptValidationOptions();
|
||||||
if (theOptions.isGuessSystem()) {
|
if (theOptions.isGuessSystem()) {
|
||||||
|
|
|
@ -23,6 +23,7 @@ import java.util.Map;
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
|
@ -36,8 +37,10 @@ import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
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 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 CURRENCIES_CODESYSTEM_URL = "urn:iso:std:iso:4217";
|
public static final String CURRENCIES_CODESYSTEM_URL = "urn:iso:std:iso:4217";
|
||||||
public static final String CURRENCIES_VALUESET_URL = "http://hl7.org/fhir/ValueSet/currencies";
|
public static final String CURRENCIES_VALUESET_URL = "http://hl7.org/fhir/ValueSet/currencies";
|
||||||
|
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";
|
||||||
private static final String USPS_CODESYSTEM_URL = "https://www.usps.com/";
|
private static final String USPS_CODESYSTEM_URL = "https://www.usps.com/";
|
||||||
|
@ -45,6 +48,7 @@ public class CommonCodeSystemsTerminologyService implements IValidationSupport {
|
||||||
private static final Logger ourLog = LoggerFactory.getLogger(CommonCodeSystemsTerminologyService.class);
|
private static final Logger ourLog = LoggerFactory.getLogger(CommonCodeSystemsTerminologyService.class);
|
||||||
private static Map<String, String> USPS_CODES = Collections.unmodifiableMap(buildUspsCodes());
|
private static Map<String, String> USPS_CODES = Collections.unmodifiableMap(buildUspsCodes());
|
||||||
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 final FhirContext myFhirContext;
|
private final FhirContext myFhirContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -144,7 +148,8 @@ public class CommonCodeSystemsTerminologyService implements IValidationSupport {
|
||||||
@Override
|
@Override
|
||||||
public LookupCodeResult lookupCode(ValidationSupportContext theValidationSupportContext, String theSystem, String theCode) {
|
public LookupCodeResult lookupCode(ValidationSupportContext theValidationSupportContext, String theSystem, String theCode) {
|
||||||
|
|
||||||
if (UCUM_CODESYSTEM_URL.equals(theSystem) && theValidationSupportContext.getRootValidationSupport().getFhirContext().getVersion().getVersion().isEqualOrNewerThan(FhirVersionEnum.DSTU3)) {
|
switch (theSystem) {
|
||||||
|
case UCUM_CODESYSTEM_URL:
|
||||||
|
|
||||||
InputStream input = ClasspathUtil.loadResourceAsStream("/ucum-essence.xml");
|
InputStream input = ClasspathUtil.loadResourceAsStream("/ucum-essence.xml");
|
||||||
try {
|
try {
|
||||||
|
@ -166,27 +171,81 @@ public class CommonCodeSystemsTerminologyService implements IValidationSupport {
|
||||||
} finally {
|
} finally {
|
||||||
ClasspathUtil.close(input);
|
ClasspathUtil.close(input);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case COUNTRIES_CODESYSTEM_URL:
|
||||||
|
|
||||||
|
String display = ISO_3166_CODES.get(theCode);
|
||||||
|
if (isNotBlank(display)) {
|
||||||
|
LookupCodeResult retVal = new LookupCodeResult();
|
||||||
|
retVal.setSearchedForCode(theCode);
|
||||||
|
retVal.setSearchedForSystem(theSystem);
|
||||||
|
retVal.setFound(true);
|
||||||
|
retVal.setCodeDisplay(display);
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MIMETYPES_CODESYSTEM_URL:
|
||||||
|
|
||||||
|
// This is a pretty naive implementation - Should be enhanced in future
|
||||||
|
LookupCodeResult retVal = new LookupCodeResult();
|
||||||
|
retVal.setSearchedForCode(theCode);
|
||||||
|
retVal.setSearchedForSystem(theSystem);
|
||||||
|
retVal.setFound(true);
|
||||||
|
return retVal;
|
||||||
|
|
||||||
|
default:
|
||||||
|
|
||||||
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
// If we get here it means we know the codesystem but the code was bad
|
||||||
|
LookupCodeResult retVal = new LookupCodeResult();
|
||||||
|
retVal.setSearchedForCode(theCode);
|
||||||
|
retVal.setSearchedForSystem(theSystem);
|
||||||
|
retVal.setFound(false);
|
||||||
|
return retVal;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isCodeSystemSupported(ValidationSupportContext theValidationSupportContext, String theSystem) {
|
public boolean isCodeSystemSupported(ValidationSupportContext theValidationSupportContext, String theSystem) {
|
||||||
|
|
||||||
switch (theSystem) {
|
switch (theSystem) {
|
||||||
|
case COUNTRIES_CODESYSTEM_URL:
|
||||||
case UCUM_CODESYSTEM_URL:
|
case UCUM_CODESYSTEM_URL:
|
||||||
|
case MIMETYPES_CODESYSTEM_URL:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValueSetSupported(ValidationSupportContext theValidationSupportContext, String theValueSetUrl) {
|
||||||
|
|
||||||
public String getValueSetUrl(@Nonnull IBaseResource theValueSet) {
|
switch (theValueSetUrl) {
|
||||||
|
case CURRENCIES_VALUESET_URL:
|
||||||
|
case LANGUAGES_VALUESET_URL:
|
||||||
|
case MIMETYPES_VALUESET_URL:
|
||||||
|
case UCUM_VALUESET_URL:
|
||||||
|
case USPS_VALUESET_URL:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FhirContext getFhirContext() {
|
||||||
|
return myFhirContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getValueSetUrl(@Nonnull IBaseResource theValueSet) {
|
||||||
String url;
|
String url;
|
||||||
switch (getFhirContext().getVersion().getVersion()) {
|
switch (theValueSet.getStructureFhirVersionEnum()) {
|
||||||
case DSTU2: {
|
case DSTU2: {
|
||||||
url = ((ca.uhn.fhir.model.dstu2.resource.ValueSet) theValueSet).getUrl();
|
url = ((ca.uhn.fhir.model.dstu2.resource.ValueSet) theValueSet).getUrl();
|
||||||
break;
|
break;
|
||||||
|
@ -209,16 +268,11 @@ public class CommonCodeSystemsTerminologyService implements IValidationSupport {
|
||||||
}
|
}
|
||||||
case DSTU2_1:
|
case DSTU2_1:
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Can not handle version: " + getFhirContext().getVersion().getVersion());
|
throw new IllegalArgumentException("Can not handle version: " + theValueSet.getStructureFhirVersionEnum());
|
||||||
}
|
}
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public FhirContext getFhirContext() {
|
|
||||||
return myFhirContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static HashMap<String, String> buildUspsCodes() {
|
private static HashMap<String, String> buildUspsCodes() {
|
||||||
HashMap<String, String> uspsCodes = new HashMap<>();
|
HashMap<String, String> uspsCodes = new HashMap<>();
|
||||||
uspsCodes.put("AK", "Alaska");
|
uspsCodes.put("AK", "Alaska");
|
||||||
|
@ -471,4 +525,259 @@ public class CommonCodeSystemsTerminologyService implements IValidationSupport {
|
||||||
return iso4217Codes;
|
return iso4217Codes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static HashMap<String, String> buildIso3166Codes() {
|
||||||
|
HashMap<String, String> codes = new HashMap<>();
|
||||||
|
codes.put("AF", "Afghanistan");
|
||||||
|
codes.put("AX", "Åland Islands");
|
||||||
|
codes.put("AL", "Albania");
|
||||||
|
codes.put("DZ", "Algeria");
|
||||||
|
codes.put("AS", "American Samoa");
|
||||||
|
codes.put("AD", "Andorra");
|
||||||
|
codes.put("AO", "Angola");
|
||||||
|
codes.put("AI", "Anguilla");
|
||||||
|
codes.put("AQ", "Antarctica");
|
||||||
|
codes.put("AG", "Antigua & Barbuda");
|
||||||
|
codes.put("AR", "Argentina");
|
||||||
|
codes.put("AM", "Armenia");
|
||||||
|
codes.put("AW", "Aruba");
|
||||||
|
codes.put("AU", "Australia");
|
||||||
|
codes.put("AT", "Austria");
|
||||||
|
codes.put("AZ", "Azerbaijan");
|
||||||
|
codes.put("BS", "Bahamas");
|
||||||
|
codes.put("BH", "Bahrain");
|
||||||
|
codes.put("BD", "Bangladesh");
|
||||||
|
codes.put("BB", "Barbados");
|
||||||
|
codes.put("BY", "Belarus");
|
||||||
|
codes.put("BE", "Belgium");
|
||||||
|
codes.put("BZ", "Belize");
|
||||||
|
codes.put("BJ", "Benin");
|
||||||
|
codes.put("BM", "Bermuda");
|
||||||
|
codes.put("BT", "Bhutan");
|
||||||
|
codes.put("BO", "Bolivia");
|
||||||
|
codes.put("BA", "Bosnia & Herzegovina");
|
||||||
|
codes.put("BW", "Botswana");
|
||||||
|
codes.put("BV", "Bouvet Island");
|
||||||
|
codes.put("BR", "Brazil");
|
||||||
|
codes.put("IO", "British Indian Ocean Territory");
|
||||||
|
codes.put("VG", "British Virgin Islands");
|
||||||
|
codes.put("BN", "Brunei");
|
||||||
|
codes.put("BG", "Bulgaria");
|
||||||
|
codes.put("BF", "Burkina Faso");
|
||||||
|
codes.put("BI", "Burundi");
|
||||||
|
codes.put("KH", "Cambodia");
|
||||||
|
codes.put("CM", "Cameroon");
|
||||||
|
codes.put("CA", "Canada");
|
||||||
|
codes.put("CV", "Cape Verde");
|
||||||
|
codes.put("BQ", "Caribbean Netherlands");
|
||||||
|
codes.put("KY", "Cayman Islands");
|
||||||
|
codes.put("CF", "Central African Republic");
|
||||||
|
codes.put("TD", "Chad");
|
||||||
|
codes.put("CL", "Chile");
|
||||||
|
codes.put("CN", "China");
|
||||||
|
codes.put("CX", "Christmas Island");
|
||||||
|
codes.put("CC", "Cocos (Keeling) Islands");
|
||||||
|
codes.put("CO", "Colombia");
|
||||||
|
codes.put("KM", "Comoros");
|
||||||
|
codes.put("CG", "Congo - Brazzaville");
|
||||||
|
codes.put("CD", "Congo - Kinshasa");
|
||||||
|
codes.put("CK", "Cook Islands");
|
||||||
|
codes.put("CR", "Costa Rica");
|
||||||
|
codes.put("CI", "Côte d’Ivoire");
|
||||||
|
codes.put("HR", "Croatia");
|
||||||
|
codes.put("CU", "Cuba");
|
||||||
|
codes.put("CW", "Curaçao");
|
||||||
|
codes.put("CY", "Cyprus");
|
||||||
|
codes.put("CZ", "Czechia");
|
||||||
|
codes.put("DK", "Denmark");
|
||||||
|
codes.put("DJ", "Djibouti");
|
||||||
|
codes.put("DM", "Dominica");
|
||||||
|
codes.put("DO", "Dominican Republic");
|
||||||
|
codes.put("EC", "Ecuador");
|
||||||
|
codes.put("EG", "Egypt");
|
||||||
|
codes.put("SV", "El Salvador");
|
||||||
|
codes.put("GQ", "Equatorial Guinea");
|
||||||
|
codes.put("ER", "Eritrea");
|
||||||
|
codes.put("EE", "Estonia");
|
||||||
|
codes.put("SZ", "Eswatini");
|
||||||
|
codes.put("ET", "Ethiopia");
|
||||||
|
codes.put("FK", "Falkland Islands");
|
||||||
|
codes.put("FO", "Faroe Islands");
|
||||||
|
codes.put("FJ", "Fiji");
|
||||||
|
codes.put("FI", "Finland");
|
||||||
|
codes.put("FR", "France");
|
||||||
|
codes.put("GF", "French Guiana");
|
||||||
|
codes.put("PF", "French Polynesia");
|
||||||
|
codes.put("TF", "French Southern Territories");
|
||||||
|
codes.put("GA", "Gabon");
|
||||||
|
codes.put("GM", "Gambia");
|
||||||
|
codes.put("GE", "Georgia");
|
||||||
|
codes.put("DE", "Germany");
|
||||||
|
codes.put("GH", "Ghana");
|
||||||
|
codes.put("GI", "Gibraltar");
|
||||||
|
codes.put("GR", "Greece");
|
||||||
|
codes.put("GL", "Greenland");
|
||||||
|
codes.put("GD", "Grenada");
|
||||||
|
codes.put("GP", "Guadeloupe");
|
||||||
|
codes.put("GU", "Guam");
|
||||||
|
codes.put("GT", "Guatemala");
|
||||||
|
codes.put("GG", "Guernsey");
|
||||||
|
codes.put("GN", "Guinea");
|
||||||
|
codes.put("GW", "Guinea-Bissau");
|
||||||
|
codes.put("GY", "Guyana");
|
||||||
|
codes.put("HT", "Haiti");
|
||||||
|
codes.put("HM", "Heard & McDonald Islands");
|
||||||
|
codes.put("HN", "Honduras");
|
||||||
|
codes.put("HK", "Hong Kong SAR China");
|
||||||
|
codes.put("HU", "Hungary");
|
||||||
|
codes.put("IS", "Iceland");
|
||||||
|
codes.put("IN", "India");
|
||||||
|
codes.put("ID", "Indonesia");
|
||||||
|
codes.put("IR", "Iran");
|
||||||
|
codes.put("IQ", "Iraq");
|
||||||
|
codes.put("IE", "Ireland");
|
||||||
|
codes.put("IM", "Isle of Man");
|
||||||
|
codes.put("IL", "Israel");
|
||||||
|
codes.put("IT", "Italy");
|
||||||
|
codes.put("JM", "Jamaica");
|
||||||
|
codes.put("JP", "Japan");
|
||||||
|
codes.put("JE", "Jersey");
|
||||||
|
codes.put("JO", "Jordan");
|
||||||
|
codes.put("KZ", "Kazakhstan");
|
||||||
|
codes.put("KE", "Kenya");
|
||||||
|
codes.put("KI", "Kiribati");
|
||||||
|
codes.put("KW", "Kuwait");
|
||||||
|
codes.put("KG", "Kyrgyzstan");
|
||||||
|
codes.put("LA", "Laos");
|
||||||
|
codes.put("LV", "Latvia");
|
||||||
|
codes.put("LB", "Lebanon");
|
||||||
|
codes.put("LS", "Lesotho");
|
||||||
|
codes.put("LR", "Liberia");
|
||||||
|
codes.put("LY", "Libya");
|
||||||
|
codes.put("LI", "Liechtenstein");
|
||||||
|
codes.put("LT", "Lithuania");
|
||||||
|
codes.put("LU", "Luxembourg");
|
||||||
|
codes.put("MO", "Macao SAR China");
|
||||||
|
codes.put("MG", "Madagascar");
|
||||||
|
codes.put("MW", "Malawi");
|
||||||
|
codes.put("MY", "Malaysia");
|
||||||
|
codes.put("MV", "Maldives");
|
||||||
|
codes.put("ML", "Mali");
|
||||||
|
codes.put("MT", "Malta");
|
||||||
|
codes.put("MH", "Marshall Islands");
|
||||||
|
codes.put("MQ", "Martinique");
|
||||||
|
codes.put("MR", "Mauritania");
|
||||||
|
codes.put("MU", "Mauritius");
|
||||||
|
codes.put("YT", "Mayotte");
|
||||||
|
codes.put("MX", "Mexico");
|
||||||
|
codes.put("FM", "Micronesia");
|
||||||
|
codes.put("MD", "Moldova");
|
||||||
|
codes.put("MC", "Monaco");
|
||||||
|
codes.put("MN", "Mongolia");
|
||||||
|
codes.put("ME", "Montenegro");
|
||||||
|
codes.put("MS", "Montserrat");
|
||||||
|
codes.put("MA", "Morocco");
|
||||||
|
codes.put("MZ", "Mozambique");
|
||||||
|
codes.put("MM", "Myanmar (Burma)");
|
||||||
|
codes.put("NA", "Namibia");
|
||||||
|
codes.put("NR", "Nauru");
|
||||||
|
codes.put("NP", "Nepal");
|
||||||
|
codes.put("NL", "Netherlands");
|
||||||
|
codes.put("NC", "New Caledonia");
|
||||||
|
codes.put("NZ", "New Zealand");
|
||||||
|
codes.put("NI", "Nicaragua");
|
||||||
|
codes.put("NE", "Niger");
|
||||||
|
codes.put("NG", "Nigeria");
|
||||||
|
codes.put("NU", "Niue");
|
||||||
|
codes.put("NF", "Norfolk Island");
|
||||||
|
codes.put("KP", "North Korea");
|
||||||
|
codes.put("MK", "North Macedonia");
|
||||||
|
codes.put("MP", "Northern Mariana Islands");
|
||||||
|
codes.put("NO", "Norway");
|
||||||
|
codes.put("OM", "Oman");
|
||||||
|
codes.put("PK", "Pakistan");
|
||||||
|
codes.put("PW", "Palau");
|
||||||
|
codes.put("PS", "Palestinian Territories");
|
||||||
|
codes.put("PA", "Panama");
|
||||||
|
codes.put("PG", "Papua New Guinea");
|
||||||
|
codes.put("PY", "Paraguay");
|
||||||
|
codes.put("PE", "Peru");
|
||||||
|
codes.put("PH", "Philippines");
|
||||||
|
codes.put("PN", "Pitcairn Islands");
|
||||||
|
codes.put("PL", "Poland");
|
||||||
|
codes.put("PT", "Portugal");
|
||||||
|
codes.put("PR", "Puerto Rico");
|
||||||
|
codes.put("QA", "Qatar");
|
||||||
|
codes.put("RE", "Réunion");
|
||||||
|
codes.put("RO", "Romania");
|
||||||
|
codes.put("RU", "Russia");
|
||||||
|
codes.put("RW", "Rwanda");
|
||||||
|
codes.put("WS", "Samoa");
|
||||||
|
codes.put("SM", "San Marino");
|
||||||
|
codes.put("ST", "São Tomé & Príncipe");
|
||||||
|
codes.put("SA", "Saudi Arabia");
|
||||||
|
codes.put("SN", "Senegal");
|
||||||
|
codes.put("RS", "Serbia");
|
||||||
|
codes.put("SC", "Seychelles");
|
||||||
|
codes.put("SL", "Sierra Leone");
|
||||||
|
codes.put("SG", "Singapore");
|
||||||
|
codes.put("SX", "Sint Maarten");
|
||||||
|
codes.put("SK", "Slovakia");
|
||||||
|
codes.put("SI", "Slovenia");
|
||||||
|
codes.put("SB", "Solomon Islands");
|
||||||
|
codes.put("SO", "Somalia");
|
||||||
|
codes.put("ZA", "South Africa");
|
||||||
|
codes.put("GS", "South Georgia & South Sandwich Islands");
|
||||||
|
codes.put("KR", "South Korea");
|
||||||
|
codes.put("SS", "South Sudan");
|
||||||
|
codes.put("ES", "Spain");
|
||||||
|
codes.put("LK", "Sri Lanka");
|
||||||
|
codes.put("BL", "St. Barthélemy");
|
||||||
|
codes.put("SH", "St. Helena");
|
||||||
|
codes.put("KN", "St. Kitts & Nevis");
|
||||||
|
codes.put("LC", "St. Lucia");
|
||||||
|
codes.put("MF", "St. Martin");
|
||||||
|
codes.put("PM", "St. Pierre & Miquelon");
|
||||||
|
codes.put("VC", "St. Vincent & Grenadines");
|
||||||
|
codes.put("SD", "Sudan");
|
||||||
|
codes.put("SR", "Suriname");
|
||||||
|
codes.put("SJ", "Svalbard & Jan Mayen");
|
||||||
|
codes.put("SE", "Sweden");
|
||||||
|
codes.put("CH", "Switzerland");
|
||||||
|
codes.put("SY", "Syria");
|
||||||
|
codes.put("TW", "Taiwan");
|
||||||
|
codes.put("TJ", "Tajikistan");
|
||||||
|
codes.put("TZ", "Tanzania");
|
||||||
|
codes.put("TH", "Thailand");
|
||||||
|
codes.put("TL", "Timor-Leste");
|
||||||
|
codes.put("TG", "Togo");
|
||||||
|
codes.put("TK", "Tokelau");
|
||||||
|
codes.put("TO", "Tonga");
|
||||||
|
codes.put("TT", "Trinidad & Tobago");
|
||||||
|
codes.put("TN", "Tunisia");
|
||||||
|
codes.put("TR", "Turkey");
|
||||||
|
codes.put("TM", "Turkmenistan");
|
||||||
|
codes.put("TC", "Turks & Caicos Islands");
|
||||||
|
codes.put("TV", "Tuvalu");
|
||||||
|
codes.put("UM", "U.S. Outlying Islands");
|
||||||
|
codes.put("VI", "U.S. Virgin Islands");
|
||||||
|
codes.put("UG", "Uganda");
|
||||||
|
codes.put("UA", "Ukraine");
|
||||||
|
codes.put("AE", "United Arab Emirates");
|
||||||
|
codes.put("GB", "United Kingdom");
|
||||||
|
codes.put("US", "United States");
|
||||||
|
codes.put("UY", "Uruguay");
|
||||||
|
codes.put("UZ", "Uzbekistan");
|
||||||
|
codes.put("VU", "Vanuatu");
|
||||||
|
codes.put("VA", "Vatican City");
|
||||||
|
codes.put("VE", "Venezuela");
|
||||||
|
codes.put("VN", "Vietnam");
|
||||||
|
codes.put("WF", "Wallis & Futuna");
|
||||||
|
codes.put("EH", "Western Sahara");
|
||||||
|
codes.put("YE", "Yemen");
|
||||||
|
codes.put("ZM", "Zambia");
|
||||||
|
codes.put("ZW", "Zimbabwe");
|
||||||
|
return codes;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,7 +119,8 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CodeValidationResult validateCodeInValueSet(ValidationSupportContext theValidationSupportContext, ConceptValidationOptions theOptions, String theCodeSystem, String theCode, String theDisplay, @Nonnull IBaseResource theValueSet) {
|
public CodeValidationResult
|
||||||
|
validateCodeInValueSet(ValidationSupportContext theValidationSupportContext, ConceptValidationOptions theOptions, String theCodeSystem, String theCode, String theDisplay, @Nonnull IBaseResource theValueSet) {
|
||||||
org.hl7.fhir.r5.model.ValueSet expansion = expandValueSetToCanonical(theValidationSupportContext, theValueSet, theCodeSystem, theCode);
|
org.hl7.fhir.r5.model.ValueSet expansion = expandValueSetToCanonical(theValidationSupportContext, theValueSet, theCodeSystem, theCode);
|
||||||
if (expansion == null) {
|
if (expansion == null) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -439,9 +440,10 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean ableToHandleCode = false;
|
boolean ableToHandleCode = false;
|
||||||
if (codeSystem == null) {
|
if (codeSystem == null || codeSystem.getContent() == CodeSystem.CodeSystemContentMode.NOTPRESENT) {
|
||||||
|
|
||||||
if (theWantCode != null) {
|
if (theWantCode != null) {
|
||||||
|
if (theValidationSupportContext.getRootValidationSupport().isCodeSystemSupported(theValidationSupportContext, system)) {
|
||||||
LookupCodeResult lookup = theValidationSupportContext.getRootValidationSupport().lookupCode(theValidationSupportContext, system, theWantCode);
|
LookupCodeResult lookup = theValidationSupportContext.getRootValidationSupport().lookupCode(theValidationSupportContext, system, theWantCode);
|
||||||
if (lookup != null && lookup.isFound()) {
|
if (lookup != null && lookup.isFound()) {
|
||||||
CodeSystem.ConceptDefinitionComponent conceptDefinition = new CodeSystem.ConceptDefinitionComponent()
|
CodeSystem.ConceptDefinitionComponent conceptDefinition = new CodeSystem.ConceptDefinitionComponent()
|
||||||
|
@ -453,25 +455,18 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
|
||||||
ableToHandleCode = true;
|
ableToHandleCode = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
ableToHandleCode = true;
|
ableToHandleCode = true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ableToHandleCode) {
|
if (!ableToHandleCode) {
|
||||||
throw new ExpansionCouldNotBeCompletedInternallyException();
|
throw new ExpansionCouldNotBeCompletedInternallyException();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (codeSystem != null) {
|
if (codeSystem != null && codeSystem.getContent() != CodeSystem.CodeSystemContentMode.NOTPRESENT) {
|
||||||
|
|
||||||
if (codeSystem.getContent() == CodeSystem.CodeSystemContentMode.NOTPRESENT) {
|
|
||||||
throw new ExpansionCouldNotBeCompletedInternallyException();
|
|
||||||
}
|
|
||||||
|
|
||||||
addCodes(system, codeSystem.getConcept(), nextCodeList, wantCodes);
|
addCodes(system, codeSystem.getConcept(), nextCodeList, wantCodes);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -231,6 +231,7 @@ public class ValidationSupportChain implements IValidationSupport {
|
||||||
@Override
|
@Override
|
||||||
public CodeValidationResult validateCode(ValidationSupportContext theValidationSupportContext, ConceptValidationOptions theOptions, String theCodeSystem, String theCode, String theDisplay, String theValueSetUrl) {
|
public CodeValidationResult validateCode(ValidationSupportContext theValidationSupportContext, ConceptValidationOptions theOptions, String theCodeSystem, String theCode, String theDisplay, String theValueSetUrl) {
|
||||||
for (IValidationSupport next : myChain) {
|
for (IValidationSupport next : myChain) {
|
||||||
|
if (isBlank(theValueSetUrl) || next.isValueSetSupported(theValidationSupportContext, theValueSetUrl)) {
|
||||||
if (theOptions.isInferSystem() || (theCodeSystem != null && next.isCodeSystemSupported(theValidationSupportContext, theCodeSystem))) {
|
if (theOptions.isInferSystem() || (theCodeSystem != null && next.isCodeSystemSupported(theValidationSupportContext, theCodeSystem))) {
|
||||||
CodeValidationResult retVal = next.validateCode(theValidationSupportContext, theOptions, theCodeSystem, theCode, theDisplay, theValueSetUrl);
|
CodeValidationResult retVal = next.validateCode(theValidationSupportContext, theOptions, theCodeSystem, theCode, theDisplay, theValueSetUrl);
|
||||||
if (retVal != null) {
|
if (retVal != null) {
|
||||||
|
@ -238,13 +239,15 @@ public class ValidationSupportChain implements IValidationSupport {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CodeValidationResult validateCodeInValueSet(ValidationSupportContext theValidationSupportContext, ConceptValidationOptions theOptions, String theCodeSystem, String theCode, String theDisplay, @Nonnull IBaseResource theValueSet) {
|
public CodeValidationResult validateCodeInValueSet(ValidationSupportContext theValidationSupportContext, ConceptValidationOptions theOptions, String theCodeSystem, String theCode, String theDisplay, @Nonnull IBaseResource theValueSet) {
|
||||||
for (IValidationSupport next : myChain) {
|
for (IValidationSupport next : myChain) {
|
||||||
if (theOptions.isInferSystem() || (theCodeSystem != null && next.isCodeSystemSupported(theValidationSupportContext, theCodeSystem))) {
|
String url = CommonCodeSystemsTerminologyService.getValueSetUrl(theValueSet);
|
||||||
|
if (isBlank(url) || next.isValueSetSupported(theValidationSupportContext, url)) {
|
||||||
CodeValidationResult retVal = next.validateCodeInValueSet(theValidationSupportContext, theOptions, theCodeSystem, theCode, theDisplay, theValueSet);
|
CodeValidationResult retVal = next.validateCodeInValueSet(theValidationSupportContext, theOptions, theCodeSystem, theCode, theDisplay, theValueSet);
|
||||||
if (retVal != null) {
|
if (retVal != null) {
|
||||||
return retVal;
|
return retVal;
|
||||||
|
|
|
@ -131,6 +131,16 @@ public class VersionSpecificWorkerContextWrapper extends I18nBase implements IWo
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getClientRetryCount() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IWorkerContext setClientRetryCount(int value) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void generateSnapshot(StructureDefinition input) throws FHIRException {
|
public void generateSnapshot(StructureDefinition input) throws FHIRException {
|
||||||
if (input.hasSnapshot()) {
|
if (input.hasSnapshot()) {
|
||||||
|
|
|
@ -167,6 +167,18 @@ public class FhirInstanceValidatorDstu3Test {
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// when(mockSupport.isValueSetSupported(any(), nullable(String.class))).thenAnswer(new Answer<Boolean>() {
|
||||||
|
// @Override
|
||||||
|
// public Boolean answer(InvocationOnMock theInvocation) {
|
||||||
|
// String url = (String) theInvocation.getArguments()[1];
|
||||||
|
// boolean retVal = myValueSets.containsKey(url);
|
||||||
|
// return retVal;
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
when(mockSupport.fetchValueSet(any())).thenAnswer(t->{
|
||||||
|
String url = t.getArgument(0, String.class);
|
||||||
|
return myValueSets.get(url);
|
||||||
|
});
|
||||||
when(mockSupport.fetchResource(nullable(Class.class), nullable(String.class))).thenAnswer(new Answer<IBaseResource>() {
|
when(mockSupport.fetchResource(nullable(Class.class), nullable(String.class))).thenAnswer(new Answer<IBaseResource>() {
|
||||||
@Override
|
@Override
|
||||||
public IBaseResource answer(InvocationOnMock theInvocation) throws Throwable {
|
public IBaseResource answer(InvocationOnMock theInvocation) throws Throwable {
|
||||||
|
@ -212,7 +224,7 @@ public class FhirInstanceValidatorDstu3Test {
|
||||||
if (myValidConcepts.contains(system + "___" + code)) {
|
if (myValidConcepts.contains(system + "___" + code)) {
|
||||||
retVal = new IValidationSupport.CodeValidationResult().setCode(code);
|
retVal = new IValidationSupport.CodeValidationResult().setCode(code);
|
||||||
} else if (myValidSystems.contains(system)) {
|
} else if (myValidSystems.contains(system)) {
|
||||||
return new IValidationSupport.CodeValidationResult().setSeverityCode(ValidationMessage.IssueSeverity.WARNING.toCode()).setMessage("Unknown code: " + system + " / " + code);
|
return new IValidationSupport.CodeValidationResult().setSeverityCode(ValidationMessage.IssueSeverity.ERROR.toCode()).setMessage("Unknown code");
|
||||||
} else if (myCodeSystems.containsKey(system)) {
|
} else if (myCodeSystems.containsKey(system)) {
|
||||||
CodeSystem cs = myCodeSystems.get(system);
|
CodeSystem cs = myCodeSystems.get(system);
|
||||||
Optional<ConceptDefinitionComponent> found = cs.getConcept().stream().filter(t -> t.getCode().equals(code)).findFirst();
|
Optional<ConceptDefinitionComponent> found = cs.getConcept().stream().filter(t -> t.getCode().equals(code)).findFirst();
|
||||||
|
@ -1035,8 +1047,8 @@ public class FhirInstanceValidatorDstu3Test {
|
||||||
ValidationResult output = myVal.validateWithResult(input);
|
ValidationResult output = myVal.validateWithResult(input);
|
||||||
List<SingleValidationMessage> errors = logResultsAndReturnAll(output);
|
List<SingleValidationMessage> errors = logResultsAndReturnAll(output);
|
||||||
|
|
||||||
assertThat(errors.toString(), containsString("warning"));
|
assertEquals(ResultSeverityEnum.ERROR, errors.get(0).getSeverity());
|
||||||
assertThat(errors.toString(), containsString("Unknown code: http://loinc.org / 12345"));
|
assertEquals("Unknown code for \"http://loinc.org#12345\"", errors.get(0).getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -1058,7 +1070,6 @@ public class FhirInstanceValidatorDstu3Test {
|
||||||
assertThat(errors.toString(), containsString("Element 'Observation.subject': minimum required = 1, but only found 0"));
|
assertThat(errors.toString(), containsString("Element 'Observation.subject': minimum required = 1, but only found 0"));
|
||||||
assertThat(errors.toString(), containsString("Element 'Observation.context': max allowed = 0, but found 1"));
|
assertThat(errors.toString(), containsString("Element 'Observation.context': max allowed = 0, but found 1"));
|
||||||
assertThat(errors.toString(), containsString("Element 'Observation.device': minimum required = 1, but only found 0"));
|
assertThat(errors.toString(), containsString("Element 'Observation.device': minimum required = 1, but only found 0"));
|
||||||
assertThat(errors.toString(), containsString(""));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -1150,7 +1161,7 @@ public class FhirInstanceValidatorDstu3Test {
|
||||||
ValidationResult output = myVal.validateWithResult(input);
|
ValidationResult output = myVal.validateWithResult(input);
|
||||||
List<SingleValidationMessage> errors = logResultsAndReturnAll(output);
|
List<SingleValidationMessage> errors = logResultsAndReturnAll(output);
|
||||||
assertThat(errors.toString(), errors.size(), greaterThan(0));
|
assertThat(errors.toString(), errors.size(), greaterThan(0));
|
||||||
assertEquals("Unknown code: http://acme.org / 9988877", errors.get(0).getMessage());
|
assertEquals("Unknown code for \"http://acme.org#9988877\"", errors.get(0).getMessage());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1186,7 +1197,7 @@ public class FhirInstanceValidatorDstu3Test {
|
||||||
ValidationResult output = myVal.validateWithResult(input);
|
ValidationResult output = myVal.validateWithResult(input);
|
||||||
List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output);
|
List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output);
|
||||||
assertEquals(1, errors.size());
|
assertEquals(1, errors.size());
|
||||||
assertEquals("Unknown code: http://loinc.org / 1234", errors.get(0).getMessage());
|
assertEquals("Unknown code for \"http://loinc.org#1234\"", errors.get(0).getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -1038,6 +1038,8 @@ public class QuestionnaireResponseValidatorDstu3Test {
|
||||||
options.getCompose().addInclude().setSystem("http://codesystems.com/system2").addConcept().setCode("code2");
|
options.getCompose().addInclude().setSystem("http://codesystems.com/system2").addConcept().setCode("code2");
|
||||||
when(myValSupport.fetchResource(eq(ValueSet.class), eq("http://somevalueset"))).thenReturn(options);
|
when(myValSupport.fetchResource(eq(ValueSet.class), eq("http://somevalueset"))).thenReturn(options);
|
||||||
|
|
||||||
|
when(myValSupport.isValueSetSupported(any(), eq("http://somevalueset"))).thenReturn(true);
|
||||||
|
|
||||||
when(myValSupport.validateCodeInValueSet(any(), any(), eq("http://codesystems.com/system"), eq("code0"), any(), any(IBaseResource.class))).thenReturn(new IValidationSupport.CodeValidationResult().setCode("code0"));
|
when(myValSupport.validateCodeInValueSet(any(), any(), eq("http://codesystems.com/system"), eq("code0"), any(), any(IBaseResource.class))).thenReturn(new IValidationSupport.CodeValidationResult().setCode("code0"));
|
||||||
|
|
||||||
QuestionnaireResponse qa;
|
QuestionnaireResponse qa;
|
||||||
|
|
|
@ -206,7 +206,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
|
||||||
if (myValidConcepts.contains(system + "___" + code)) {
|
if (myValidConcepts.contains(system + "___" + code)) {
|
||||||
retVal = new IValidationSupport.CodeValidationResult().setCode(code);
|
retVal = new IValidationSupport.CodeValidationResult().setCode(code);
|
||||||
} else if (myValidSystems.contains(system)) {
|
} else if (myValidSystems.contains(system)) {
|
||||||
return new IValidationSupport.CodeValidationResult().setSeverityCode(ValidationMessage.IssueSeverity.WARNING.toCode()).setMessage("Unknown code: " + system + " / " + code);
|
return new IValidationSupport.CodeValidationResult().setSeverityCode(ValidationMessage.IssueSeverity.ERROR.toCode()).setMessage("Unknown code");
|
||||||
} else {
|
} else {
|
||||||
retVal = myDefaultValidationSupport.validateCode(new ValidationSupportContext(myDefaultValidationSupport), options, system, code, display, valueSetUrl);
|
retVal = myDefaultValidationSupport.validateCode(new ValidationSupportContext(myDefaultValidationSupport), options, system, code, display, valueSetUrl);
|
||||||
}
|
}
|
||||||
|
@ -1110,8 +1110,8 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
|
||||||
ValidationResult output = myVal.validateWithResult(input);
|
ValidationResult output = myVal.validateWithResult(input);
|
||||||
List<SingleValidationMessage> errors = logResultsAndReturnAll(output);
|
List<SingleValidationMessage> errors = logResultsAndReturnAll(output);
|
||||||
|
|
||||||
assertThat(errors.toString(), containsString("warning"));
|
assertEquals(ResultSeverityEnum.ERROR, errors.get(0).getSeverity());
|
||||||
assertThat(errors.toString(), containsString("Unknown code: http://loinc.org / 12345"));
|
assertEquals("Unknown code for \"http://loinc.org#12345\"", errors.get(0).getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -1266,7 +1266,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
|
||||||
ValidationResult output = myVal.validateWithResult(input);
|
ValidationResult output = myVal.validateWithResult(input);
|
||||||
List<SingleValidationMessage> errors = logResultsAndReturnAll(output);
|
List<SingleValidationMessage> errors = logResultsAndReturnAll(output);
|
||||||
assertThat(errors.toString(), errors.size(), greaterThan(0));
|
assertThat(errors.toString(), errors.size(), greaterThan(0));
|
||||||
assertEquals("Unknown code: http://acme.org / 9988877", errors.get(0).getMessage());
|
assertEquals("Unknown code for \"http://acme.org#9988877\"", errors.get(0).getMessage());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1304,7 +1304,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
|
||||||
ValidationResult output = myVal.validateWithResult(input);
|
ValidationResult output = myVal.validateWithResult(input);
|
||||||
List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output);
|
List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output);
|
||||||
assertEquals(1, errors.size());
|
assertEquals(1, errors.size());
|
||||||
assertEquals("Unknown code: http://loinc.org / 1234", errors.get(0).getMessage());
|
assertEquals("Unknown code for \"http://loinc.org#1234\"", errors.get(0).getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -9,6 +9,7 @@ import ca.uhn.fhir.validation.FhirValidator;
|
||||||
import ca.uhn.fhir.validation.ResultSeverityEnum;
|
import ca.uhn.fhir.validation.ResultSeverityEnum;
|
||||||
import ca.uhn.fhir.validation.SingleValidationMessage;
|
import ca.uhn.fhir.validation.SingleValidationMessage;
|
||||||
import ca.uhn.fhir.validation.ValidationResult;
|
import ca.uhn.fhir.validation.ValidationResult;
|
||||||
|
import org.hl7.fhir.common.hapi.validation.support.CommonCodeSystemsTerminologyService;
|
||||||
import org.hl7.fhir.common.hapi.validation.support.InMemoryTerminologyServerValidationSupport;
|
import org.hl7.fhir.common.hapi.validation.support.InMemoryTerminologyServerValidationSupport;
|
||||||
import org.hl7.fhir.common.hapi.validation.support.ValidationSupportChain;
|
import org.hl7.fhir.common.hapi.validation.support.ValidationSupportChain;
|
||||||
import org.hl7.fhir.common.hapi.validation.validator.FhirInstanceValidator;
|
import org.hl7.fhir.common.hapi.validation.validator.FhirInstanceValidator;
|
||||||
|
@ -61,7 +62,7 @@ public class QuestionnaireResponseValidatorR4Test {
|
||||||
myVal.setValidateAgainstStandardSchema(false);
|
myVal.setValidateAgainstStandardSchema(false);
|
||||||
myVal.setValidateAgainstStandardSchematron(false);
|
myVal.setValidateAgainstStandardSchematron(false);
|
||||||
|
|
||||||
ValidationSupportChain validationSupport = new ValidationSupportChain(myDefaultValidationSupport, myValSupport, new InMemoryTerminologyServerValidationSupport(ourCtx));
|
ValidationSupportChain validationSupport = new ValidationSupportChain(myDefaultValidationSupport, myValSupport, new InMemoryTerminologyServerValidationSupport(ourCtx), new CommonCodeSystemsTerminologyService(ourCtx));
|
||||||
myInstanceVal = new FhirInstanceValidator(validationSupport);
|
myInstanceVal = new FhirInstanceValidator(validationSupport);
|
||||||
|
|
||||||
myVal.registerValidatorModule(myInstanceVal);
|
myVal.registerValidatorModule(myInstanceVal);
|
||||||
|
|
|
@ -163,7 +163,7 @@ public class FhirInstanceValidatorR5Test {
|
||||||
if (myValidConcepts.contains(system + "___" + code)) {
|
if (myValidConcepts.contains(system + "___" + code)) {
|
||||||
retVal = new IValidationSupport.CodeValidationResult().setCode(code);
|
retVal = new IValidationSupport.CodeValidationResult().setCode(code);
|
||||||
} else if (myValidSystems.contains(system)) {
|
} else if (myValidSystems.contains(system)) {
|
||||||
return new IValidationSupport.CodeValidationResult().setSeverity(IValidationSupport.IssueSeverity.WARNING).setMessage("Unknown code: " + system + " / " + code);
|
return new IValidationSupport.CodeValidationResult().setSeverity(IValidationSupport.IssueSeverity.ERROR).setMessage("Unknown code");
|
||||||
} else {
|
} else {
|
||||||
retVal = myDefaultValidationSupport.validateCode(new ValidationSupportContext(myDefaultValidationSupport), options, system, code, display, valueSetUrl);
|
retVal = myDefaultValidationSupport.validateCode(new ValidationSupportContext(myDefaultValidationSupport), options, system, code, display, valueSetUrl);
|
||||||
}
|
}
|
||||||
|
@ -754,8 +754,8 @@ public class FhirInstanceValidatorR5Test {
|
||||||
ValidationResult output = myVal.validateWithResult(input);
|
ValidationResult output = myVal.validateWithResult(input);
|
||||||
List<SingleValidationMessage> errors = logResultsAndReturnAll(output);
|
List<SingleValidationMessage> errors = logResultsAndReturnAll(output);
|
||||||
|
|
||||||
assertThat(errors.toString(), containsString("warning"));
|
assertEquals(ResultSeverityEnum.ERROR, errors.get(0).getSeverity());
|
||||||
assertThat(errors.toString(), containsString("Unknown code: http://loinc.org / 12345"));
|
assertEquals("Unknown code for \"http://loinc.org#12345\"", errors.get(0).getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -877,7 +877,7 @@ public class FhirInstanceValidatorR5Test {
|
||||||
ValidationResult output = myVal.validateWithResult(input);
|
ValidationResult output = myVal.validateWithResult(input);
|
||||||
List<SingleValidationMessage> errors = logResultsAndReturnAll(output);
|
List<SingleValidationMessage> errors = logResultsAndReturnAll(output);
|
||||||
assertThat(errors.toString(), errors.size(), greaterThan(0));
|
assertThat(errors.toString(), errors.size(), greaterThan(0));
|
||||||
assertEquals("Unknown code: http://acme.org / 9988877", errors.get(0).getMessage());
|
assertEquals("Unknown code for \"http://acme.org#9988877\"", errors.get(0).getMessage());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -915,7 +915,7 @@ public class FhirInstanceValidatorR5Test {
|
||||||
ValidationResult output = myVal.validateWithResult(input);
|
ValidationResult output = myVal.validateWithResult(input);
|
||||||
List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output);
|
List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output);
|
||||||
assertEquals(1, errors.size());
|
assertEquals(1, errors.size());
|
||||||
assertEquals("Unknown code: http://loinc.org / 1234", errors.get(0).getMessage());
|
assertEquals("Unknown code for \"http://loinc.org#1234\"", errors.get(0).getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -9,6 +9,7 @@ import ca.uhn.fhir.validation.FhirValidator;
|
||||||
import ca.uhn.fhir.validation.ResultSeverityEnum;
|
import ca.uhn.fhir.validation.ResultSeverityEnum;
|
||||||
import ca.uhn.fhir.validation.SingleValidationMessage;
|
import ca.uhn.fhir.validation.SingleValidationMessage;
|
||||||
import ca.uhn.fhir.validation.ValidationResult;
|
import ca.uhn.fhir.validation.ValidationResult;
|
||||||
|
import org.hl7.fhir.common.hapi.validation.support.CommonCodeSystemsTerminologyService;
|
||||||
import org.hl7.fhir.common.hapi.validation.support.InMemoryTerminologyServerValidationSupport;
|
import org.hl7.fhir.common.hapi.validation.support.InMemoryTerminologyServerValidationSupport;
|
||||||
import org.hl7.fhir.common.hapi.validation.support.ValidationSupportChain;
|
import org.hl7.fhir.common.hapi.validation.support.ValidationSupportChain;
|
||||||
import org.hl7.fhir.common.hapi.validation.validator.FhirInstanceValidator;
|
import org.hl7.fhir.common.hapi.validation.validator.FhirInstanceValidator;
|
||||||
|
@ -65,7 +66,7 @@ public class QuestionnaireResponseValidatorR5Test {
|
||||||
myVal.setValidateAgainstStandardSchema(false);
|
myVal.setValidateAgainstStandardSchema(false);
|
||||||
myVal.setValidateAgainstStandardSchematron(false);
|
myVal.setValidateAgainstStandardSchematron(false);
|
||||||
|
|
||||||
ValidationSupportChain validationSupport = new ValidationSupportChain(myDefaultValidationSupport, myValSupport, new InMemoryTerminologyServerValidationSupport(ourCtx));
|
ValidationSupportChain validationSupport = new ValidationSupportChain(myDefaultValidationSupport, myValSupport, new InMemoryTerminologyServerValidationSupport(ourCtx), new CommonCodeSystemsTerminologyService(ourCtx));
|
||||||
myInstanceVal = new FhirInstanceValidator(validationSupport);
|
myInstanceVal = new FhirInstanceValidator(validationSupport);
|
||||||
|
|
||||||
myVal.registerValidatorModule(myInstanceVal);
|
myVal.registerValidatorModule(myInstanceVal);
|
||||||
|
|
2
pom.xml
2
pom.xml
|
@ -674,7 +674,7 @@
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
|
|
||||||
<fhir_core_version>5.0.7-SNAPSHOT</fhir_core_version>
|
<fhir_core_version>5.0.9</fhir_core_version>
|
||||||
<ucum_version>1.0.2</ucum_version>
|
<ucum_version>1.0.2</ucum_version>
|
||||||
|
|
||||||
<surefire_jvm_args>-Dfile.encoding=UTF-8 -Xmx2048m</surefire_jvm_args>
|
<surefire_jvm_args>-Dfile.encoding=UTF-8 -Xmx2048m</surefire_jvm_args>
|
||||||
|
|
Loading…
Reference in New Issue