Validate code changes and new tests.

This commit is contained in:
ianmarshall 2020-09-24 18:51:47 -04:00
parent e5daea17b7
commit 5fe46be41c
18 changed files with 2472 additions and 501 deletions

View File

@ -100,7 +100,11 @@ public class FhirResourceDaoCodeSystemDstu3 extends BaseHapiFhirResourceDao<Code
String system;
if (haveCoding) {
code = theCoding.getCode();
if (theCoding.hasVersion()) {
system = theCoding.getSystem() + "|" + theCoding.getVersion();
} else {
system = theCoding.getSystem();
}
} else {
code = theCode.getValue();
system = theSystem.getValue();

View File

@ -95,7 +95,11 @@ public class FhirResourceDaoCodeSystemR4 extends BaseHapiFhirResourceDao<CodeSys
String system;
if (haveCoding) {
code = theCoding.getCode();
if (theCoding.hasVersion()) {
system = theCoding.getSystem() + "|" + theCoding.getVersion();
} else {
system = theCoding.getSystem();
}
} else {
code = theCode.getValue();
system = theSystem.getValue();

View File

@ -97,7 +97,11 @@ public class FhirResourceDaoCodeSystemR5 extends BaseHapiFhirResourceDao<CodeSys
String system;
if (haveCoding) {
code = theCoding.getCode();
if (theCoding.hasVersion()) {
system = theCoding.getSystem() + "|" + theCoding.getVersion();
} else {
system = theCoding.getSystem();
}
} else {
code = theCode.getValue();
system = theSystem.getValue();

View File

@ -144,8 +144,10 @@ public class BaseJpaResourceProviderValueSetDstu3 extends JpaResourceProviderDst
@IdParam(optional = true) IdType theId,
@OperationParam(name = "identifier", min = 0, max = 1) UriType theValueSetIdentifier,
@OperationParam(name = "url", min = 0, max = 1) UriType theValueSetUrl,
@OperationParam(name = "valueSetVersion", min = 0, max = 1) StringType theValueSetVersion,
@OperationParam(name = "code", min = 0, max = 1) CodeType theCode,
@OperationParam(name = "system", min = 0, max = 1) UriType theSystem,
@OperationParam(name = "systemVersion", min = 0, max = 1) StringType theSystemVersion,
@OperationParam(name = "display", min = 0, max = 1) StringType theDisplay,
@OperationParam(name = "coding", min = 0, max = 1) Coding theCoding,
@OperationParam(name = "codeableConcept", min = 0, max = 1) CodeableConcept theCodeableConcept,
@ -160,7 +162,19 @@ public class BaseJpaResourceProviderValueSetDstu3 extends JpaResourceProviderDst
startRequest(theServletRequest);
try {
IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> dao = (IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept>) getDao();
IValidationSupport.CodeValidationResult result = dao.validateCode(url, theId, theCode, theSystem, theDisplay, theCoding, theCodeableConcept, theRequestDetails);
UriType valueSetIdentifier;
if (theValueSetVersion != null) {
valueSetIdentifier = new UriType(theValueSetUrl.getValue() + "|" + theValueSetVersion);
} else {
valueSetIdentifier = theValueSetUrl;
}
UriType codeSystemIdentifier;
if (theSystemVersion != null) {
codeSystemIdentifier = new UriType(theSystem.getValue() + "|" + theSystemVersion);
} else {
codeSystemIdentifier = theSystem;
}
IValidationSupport.CodeValidationResult result = dao.validateCode(valueSetIdentifier, theId, theCode, codeSystemIdentifier, theDisplay, theCoding, theCodeableConcept, theRequestDetails);
return (Parameters) BaseJpaResourceProviderValueSetDstu2.toValidateCodeResult(getContext(), result);
} finally {
endRequest(theServletRequest);

View File

@ -66,9 +66,6 @@ public class BaseJpaResourceProviderCodeSystemR4 extends JpaResourceProviderR4<C
IValidationSupport.LookupCodeResult result;
if (theVersion != null) {
result = dao.lookupCode(theCode, new UriType(theSystem.getValue() + "|" + theVersion), theCoding, theRequestDetails);
} else if (theCoding != null && theCoding.hasVersion()) {
Coding codingWithVersion = new Coding(theCoding.getSystem() + "|" + theCoding.getVersion(), theCoding.getCode(), theCoding.getDisplay());
result = dao.lookupCode(theCode, theSystem, codingWithVersion, theRequestDetails);
} else {
result = dao.lookupCode(theCode, theSystem, theCoding, theRequestDetails);
}
@ -104,12 +101,6 @@ public class BaseJpaResourceProviderCodeSystemR4 extends JpaResourceProviderR4<C
if (theVersion != null) {
theSystem = new UriType(theSystem.asStringValue() + "|" + theVersion.toString());
}
if (theCodingA != null && theCodingA.hasVersion()) {
theCodingA.setSystem(theCodingA.getSystemElement().asStringValue() + "|" + theCodingA.getVersion());
}
if (theCodingB != null && theCodingB.hasVersion()) {
theCodingB.setSystem(theCodingB.getSystemElement().asStringValue() + "|" + theCodingB.getVersion());
}
result = dao.subsumes(theCodeA, theCodeB, theSystem, theCodingA, theCodingB, theRequestDetails);
return (Parameters) result.toParameters(theRequestDetails.getFhirContext());
} finally {

View File

@ -135,8 +135,10 @@ public class BaseJpaResourceProviderValueSetR4 extends JpaResourceProviderR4<Val
HttpServletRequest theServletRequest,
@IdParam(optional = true) IdType theId,
@OperationParam(name = "url", min = 0, max = 1) UriType theValueSetUrl,
@OperationParam(name = "valueSetVersion", min = 0, max = 1) StringType theValueSetVersion,
@OperationParam(name = "code", min = 0, max = 1) CodeType theCode,
@OperationParam(name = "system", min = 0, max = 1) UriType theSystem,
@OperationParam(name = "systemVersion", min = 0, max = 1) StringType theSystemVersion,
@OperationParam(name = "display", min = 0, max = 1) StringType theDisplay,
@OperationParam(name = "coding", min = 0, max = 1) Coding theCoding,
@OperationParam(name = "codeableConcept", min = 0, max = 1) CodeableConcept theCodeableConcept,
@ -146,7 +148,19 @@ public class BaseJpaResourceProviderValueSetR4 extends JpaResourceProviderR4<Val
startRequest(theServletRequest);
try {
IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> dao = (IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept>) getDao();
IValidationSupport.CodeValidationResult result = dao.validateCode(theValueSetUrl, theId, theCode, theSystem, theDisplay, theCoding, theCodeableConcept, theRequestDetails);
UriType valueSetIdentifier;
if (theValueSetVersion != null) {
valueSetIdentifier = new UriType(theValueSetUrl.getValue() + "|" + theValueSetVersion);
} else {
valueSetIdentifier = theValueSetUrl;
}
UriType codeSystemIdentifier;
if (theSystemVersion != null) {
codeSystemIdentifier = new UriType(theSystem.getValue() + "|" + theSystemVersion);
} else {
codeSystemIdentifier = theSystem;
}
IValidationSupport.CodeValidationResult result = dao.validateCode(valueSetIdentifier, theId, theCode, codeSystemIdentifier, theDisplay, theCoding, theCodeableConcept, theRequestDetails);
return (Parameters) BaseJpaResourceProviderValueSetDstu2.toValidateCodeResult(getContext(), result);
} finally {
endRequest(theServletRequest);

View File

@ -66,9 +66,6 @@ public class BaseJpaResourceProviderCodeSystemR5 extends JpaResourceProviderR5<C
IValidationSupport.LookupCodeResult result;
if (theVersion != null) {
result = dao.lookupCode(theCode, new UriType(theSystem.getValue() + "|" + theVersion), theCoding, theRequestDetails);
} else if (theCoding != null && theCoding.hasVersion()) {
Coding codingWithVersion = new Coding(theCoding.getSystem() + "|" + theCoding.getVersion(), theCoding.getCode(), theCoding.getDisplay());
result = dao.lookupCode(theCode, theSystem, codingWithVersion, theRequestDetails);
} else {
result = dao.lookupCode(theCode, theSystem, theCoding, theRequestDetails);
}
@ -104,12 +101,6 @@ public class BaseJpaResourceProviderCodeSystemR5 extends JpaResourceProviderR5<C
if (theVersion != null) {
theSystem = new UriType(theSystem.asStringValue() + "|" + theVersion.toString());
}
if (theCodingA != null && theCodingA.hasVersion()) {
theCodingA.setSystem(theCodingA.getSystemElement().asStringValue() + "|" + theCodingA.getVersion());
}
if (theCodingB != null && theCodingB.hasVersion()) {
theCodingB.setSystem(theCodingB.getSystemElement().asStringValue() + "|" + theCodingB.getVersion());
}
result = dao.subsumes(theCodeA, theCodeB, theSystem, theCodingA, theCodingB, theRequestDetails);
return (Parameters) result.toParameters(theRequestDetails.getFhirContext());
} finally {

View File

@ -44,7 +44,7 @@ public class BaseJpaResourceProviderValueSetR5 extends JpaResourceProviderR5<Val
@IdParam(optional = true) IdType theId,
@OperationParam(name = "valueSet", min = 0, max = 1) ValueSet theValueSet,
@OperationParam(name = "url", min = 0, max = 1) UriType theUrl,
@OperationParam(name = "valueSetVersion", min = 0, max = 1) org.hl7.fhir.r4.model.StringType theValueSetVersion,
@OperationParam(name = "valueSetVersion", min = 0, max = 1) StringType theValueSetVersion,
@OperationParam(name = "filter", min = 0, max = 1) StringType theFilter,
@OperationParam(name = "offset", min = 0, max = 1) IntegerType theOffset,
@OperationParam(name = "count", min = 0, max = 1) IntegerType theCount,
@ -135,8 +135,10 @@ public class BaseJpaResourceProviderValueSetR5 extends JpaResourceProviderR5<Val
HttpServletRequest theServletRequest,
@IdParam(optional = true) IdType theId,
@OperationParam(name = "url", min = 0, max = 1) UriType theValueSetUrl,
@OperationParam(name = "valueSetVersion", min = 0, max = 1) StringType theValueSetVersion,
@OperationParam(name = "code", min = 0, max = 1) CodeType theCode,
@OperationParam(name = "system", min = 0, max = 1) UriType theSystem,
@OperationParam(name = "systemVersion", min = 0, max = 1) StringType theSystemVersion,
@OperationParam(name = "display", min = 0, max = 1) StringType theDisplay,
@OperationParam(name = "coding", min = 0, max = 1) Coding theCoding,
@OperationParam(name = "codeableConcept", min = 0, max = 1) CodeableConcept theCodeableConcept,
@ -146,7 +148,19 @@ public class BaseJpaResourceProviderValueSetR5 extends JpaResourceProviderR5<Val
startRequest(theServletRequest);
try {
IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> dao = (IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept>) getDao();
IValidationSupport.CodeValidationResult result = dao.validateCode(theValueSetUrl, theId, theCode, theSystem, theDisplay, theCoding, theCodeableConcept, theRequestDetails);
UriType valueSetIdentifier;
if (theValueSetVersion != null) {
valueSetIdentifier = new UriType(theValueSetUrl.getValue() + "|" + theValueSetVersion);
} else {
valueSetIdentifier = theValueSetUrl;
}
UriType codeSystemIdentifier;
if (theSystemVersion != null) {
codeSystemIdentifier = new UriType(theSystem.getValue() + "|" + theSystemVersion);
} else {
codeSystemIdentifier = theSystem;
}
IValidationSupport.CodeValidationResult result = dao.validateCode(valueSetIdentifier, theId, theCode, codeSystemIdentifier, theDisplay, theCoding, theCodeableConcept, theRequestDetails);
return (Parameters) BaseJpaResourceProviderValueSetDstu2.toValidateCodeResult(getContext(), result);
} finally {
endRequest(theServletRequest);

View File

@ -651,22 +651,22 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
*/
private Boolean expandValueSetHandleIncludeOrExclude(@Nullable ValueSetExpansionOptions theExpansionOptions, IValueSetConceptAccumulator theValueSetCodeAccumulator, Set<String> theAddedCodes, ValueSet.ConceptSetComponent theIncludeOrExclude, boolean theAdd, AtomicInteger theCodeCounter, int theQueryIndex, VersionIndependentConcept theWantConceptOrNull) {
String system = theIncludeOrExclude.getSystem();
boolean hasSystem = isNotBlank(system);
String includeOrExcludeSystemUrl = theIncludeOrExclude.getSystem();
boolean hasSystem = isNotBlank(includeOrExcludeSystemUrl);
boolean hasValueSet = theIncludeOrExclude.getValueSet().size() > 0;
if (hasSystem) {
if (theWantConceptOrNull != null && theWantConceptOrNull.getSystem() != null && !system.equals(theWantConceptOrNull.getSystem())) {
if (theWantConceptOrNull != null && theWantConceptOrNull.getSystem() != null && !includeOrExcludeSystemUrl.equals(theWantConceptOrNull.getSystem())) {
return false;
}
ourLog.debug("Starting {} expansion around CodeSystem: {}", (theAdd ? "inclusion" : "exclusion"), system);
ourLog.debug("Starting {} expansion around CodeSystem: {}", (theAdd ? "inclusion" : "exclusion"), includeOrExcludeSystemUrl);
TermCodeSystem cs = myCodeSystemDao.findByCodeSystemUri(system);
TermCodeSystem cs = myCodeSystemDao.findByCodeSystemUri(includeOrExcludeSystemUrl);
if (cs != null) {
return expandValueSetHandleIncludeOrExcludeUsingDatabase(theValueSetCodeAccumulator, theAddedCodes, theIncludeOrExclude, theAdd, theCodeCounter, theQueryIndex, theWantConceptOrNull, system, cs);
return expandValueSetHandleIncludeOrExcludeUsingDatabase(theValueSetCodeAccumulator, theAddedCodes, theIncludeOrExclude, theAdd, theCodeCounter, theQueryIndex, theWantConceptOrNull, includeOrExcludeSystemUrl, cs);
} else {
@ -679,7 +679,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
}
// No CodeSystem matching the URL found in the database.
CodeSystem codeSystemFromContext = fetchCanonicalCodeSystemFromCompleteContext(system);
CodeSystem codeSystemFromContext = fetchCanonicalCodeSystemFromCompleteContext(includeOrExcludeSystemUrl);
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
@ -704,7 +704,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
for (VersionIndependentConcept next : includedConcepts) {
String nextSystem = next.getSystem();
if (nextSystem == null) {
nextSystem = system;
nextSystem = includeOrExcludeSystemUrl;
}
LookupCodeResult lookup = myValidationSupport.lookupCode(new ValidationSupportContext(provideValidationSupport()), nextSystem, next.getCode());
@ -720,7 +720,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
}
}
String msg = myContext.getLocalizer().getMessage(BaseTermReadSvcImpl.class, "expansionRefersToUnknownCs", system);
String msg = myContext.getLocalizer().getMessage(BaseTermReadSvcImpl.class, "expansionRefersToUnknownCs", includeOrExcludeSystemUrl);
if (provideExpansionOptions(theExpansionOptions).isFailOnMissingCodeSystem()) {
throw new PreconditionFailedException(msg);
} else {
@ -735,12 +735,12 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
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)) {
if (isNoneBlank(includeOrExcludeSystemUrl, nextCode) && !theAddedCodes.contains(includeOrExcludeSystemUrl + "|" + nextCode)) {
CodeSystem.ConceptDefinitionComponent code = findCode(codeSystemFromContext.getConcept(), nextCode);
if (code != null) {
String display = code.getDisplay();
addOrRemoveCode(theValueSetCodeAccumulator, theAddedCodes, theAdd, system, nextCode, display);
addOrRemoveCode(theValueSetCodeAccumulator, theAddedCodes, theAdd, includeOrExcludeSystemUrl, nextCode, display);
}
}
@ -748,7 +748,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
}
} else {
List<CodeSystem.ConceptDefinitionComponent> concept = codeSystemFromContext.getConcept();
addConceptsToList(theValueSetCodeAccumulator, theAddedCodes, system, concept, theAdd, theWantConceptOrNull);
addConceptsToList(theValueSetCodeAccumulator, theAddedCodes, includeOrExcludeSystemUrl, concept, theAdd, theWantConceptOrNull);
}
return false;
@ -841,13 +841,13 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
/*
* Filters
*/
String canonicalSystem;
String codeSystemIdentifier;
if (codeSystemVersion != null) {
canonicalSystem = theSystem + "|" + codeSystemVersion;
codeSystemIdentifier = theSystem + "|" + codeSystemVersion;
} else {
canonicalSystem = theSystem;
codeSystemIdentifier = theSystem;
}
handleFilters(bool, canonicalSystem, qb, theIncludeOrExclude);
handleFilters(bool, codeSystemIdentifier, qb, theIncludeOrExclude);
Query luceneQuery = bool.createQuery();
@ -956,15 +956,15 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
}
}
private void handleFilters(BooleanJunction<?> theBool, String theCanonicalSystem, QueryBuilder theQb, ValueSet.ConceptSetComponent theIncludeOrExclude) {
private void handleFilters(BooleanJunction<?> theBool, String theCodeSystemIdentifier, QueryBuilder theQb, ValueSet.ConceptSetComponent theIncludeOrExclude) {
if (theIncludeOrExclude.getFilter().size() > 0) {
for (ValueSet.ConceptSetFilterComponent nextFilter : theIncludeOrExclude.getFilter()) {
handleFilter(theCanonicalSystem, theQb, theBool, nextFilter);
handleFilter(theCodeSystemIdentifier, theQb, theBool, nextFilter);
}
}
}
private void handleFilter(String theSystem, QueryBuilder theQb, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) {
private void handleFilter(String theCodeSystemIdentifier, QueryBuilder theQb, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) {
if (isBlank(theFilter.getValue()) && theFilter.getOp() == null && isBlank(theFilter.getProperty())) {
return;
}
@ -980,23 +980,23 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
break;
case "concept":
case "code":
handleFilterConceptAndCode(theSystem, theQb, theBool, theFilter);
handleFilterConceptAndCode(theCodeSystemIdentifier, theQb, theBool, theFilter);
break;
case "parent":
case "child":
isCodeSystemLoingOrThrowInvalidRequestException(theSystem, theFilter.getProperty());
isCodeSystemLoingOrThrowInvalidRequestException(theCodeSystemIdentifier, theFilter.getProperty());
handleFilterLoincParentChild(theBool, theFilter);
break;
case "ancestor":
isCodeSystemLoingOrThrowInvalidRequestException(theSystem, theFilter.getProperty());
handleFilterLoincAncestor(theSystem, theBool, theFilter);
isCodeSystemLoingOrThrowInvalidRequestException(theCodeSystemIdentifier, theFilter.getProperty());
handleFilterLoincAncestor(theCodeSystemIdentifier, theBool, theFilter);
break;
case "descendant":
isCodeSystemLoingOrThrowInvalidRequestException(theSystem, theFilter.getProperty());
handleFilterLoincDescendant(theSystem, theBool, theFilter);
isCodeSystemLoingOrThrowInvalidRequestException(theCodeSystemIdentifier, theFilter.getProperty());
handleFilterLoincDescendant(theCodeSystemIdentifier, theBool, theFilter);
break;
case "copyright":
isCodeSystemLoingOrThrowInvalidRequestException(theSystem, theFilter.getProperty());
isCodeSystemLoingOrThrowInvalidRequestException(theCodeSystemIdentifier, theFilter.getProperty());
handleFilterLoincCopyright(theBool, theFilter);
break;
default:
@ -1005,8 +1005,8 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
}
}
private void isCodeSystemLoingOrThrowInvalidRequestException(String theSystem, String theProperty) {
String systemUrl = getSystemFromCanonicalUrl(theSystem);
private void isCodeSystemLoingOrThrowInvalidRequestException(String theSystemIdentifier, String theProperty) {
String systemUrl = getUrlFromIdentifier(theSystemIdentifier);
if (!isCodeSystemLoinc(systemUrl)) {
throw new InvalidRequestException("Invalid filter, property " + theProperty + " is LOINC-specific and cannot be used with system: " + systemUrl);
}
@ -1435,12 +1435,12 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
}
@Nullable
private TermCodeSystemVersion getCurrentCodeSystemVersion(String theUri) {
String myVersion = getVersionFromCanonicalUrl(theUri);
String key = theUri;
private TermCodeSystemVersion getCurrentCodeSystemVersion(String theCodeSystemIdentifier) {
String myVersion = getVersionFromIdentifier(theCodeSystemIdentifier);
String key = theCodeSystemIdentifier;
TermCodeSystemVersion retVal = myCodeSystemCurrentVersionCache.get(key.toString(), t -> myTxTemplate.execute(tx -> {
TermCodeSystemVersion csv = null;
TermCodeSystem cs = myCodeSystemDao.findByCodeSystemUri(getSystemFromCanonicalUrl(theUri));
TermCodeSystem cs = myCodeSystemDao.findByCodeSystemUri(getUrlFromIdentifier(theCodeSystemIdentifier));
if (cs != null) {
if (myVersion != null) {
csv = myCodeSystemVersionDao.findByCodeSystemPidAndVersion(cs.getPid(), myVersion);
@ -1460,7 +1460,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
return retVal;
}
private String getVersionFromCanonicalUrl(String theUri) {
private String getVersionFromIdentifier(String theUri) {
String retVal = null;
if (StringUtils.isNotEmpty((theUri))) {
int versionSeparator = theUri.lastIndexOf('|');
@ -1471,7 +1471,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
return retVal;
}
private String getSystemFromCanonicalUrl(String theUri) {
private String getUrlFromIdentifier(String theUri) {
String retVal = theUri;
if (StringUtils.isNotEmpty((theUri))){
int versionSeparator = theUri.lastIndexOf('|');
@ -1777,15 +1777,15 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
}
@Override
public CodeValidationResult validateCode(ConceptValidationOptions theOptions, IIdType theValueSetId, String theValueSetUrl, String theSystem, String theCode, String theDisplay, IBaseDatatype theCoding, IBaseDatatype theCodeableConcept) {
public CodeValidationResult validateCode(ConceptValidationOptions theOptions, IIdType theValueSetId, String theValueSetIdentifier, String theCodeSystemIdentifierToValidate, String theCodeToValidate, String theDisplayToValidate, IBaseDatatype theCodingToValidate, IBaseDatatype theCodeableConceptToValidate) {
CodeableConcept codeableConcept = toCanonicalCodeableConcept(theCodeableConcept);
CodeableConcept codeableConcept = toCanonicalCodeableConcept(theCodeableConceptToValidate);
boolean haveCodeableConcept = codeableConcept != null && codeableConcept.getCoding().size() > 0;
Coding coding = toCanonicalCoding(theCoding);
boolean haveCoding = coding != null && coding.isEmpty() == false;
Coding canonicalCodingToValidate = toCanonicalCoding(theCodingToValidate);
boolean haveCoding = canonicalCodingToValidate != null && canonicalCodingToValidate.isEmpty() == false;
boolean haveCode = theCode != null && theCode.isEmpty() == false;
boolean haveCode = theCodeToValidate != null && theCodeToValidate.isEmpty() == false;
if (!haveCodeableConcept && !haveCoding && !haveCode) {
throw new InvalidRequestException("No code, coding, or codeableConcept provided to validate");
@ -1794,38 +1794,54 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
throw new InvalidRequestException("$validate-code can only validate (system AND code) OR (coding) OR (codeableConcept)");
}
boolean haveIdentifierParam = isNotBlank(theValueSetUrl);
String valueSetUrl;
boolean haveIdentifierParam = isNotBlank(theValueSetIdentifier);
String valueSetIdentifier;
if (theValueSetId != null) {
IBaseResource valueSet = myDaoRegistry.getResourceDao("ValueSet").read(theValueSetId);
valueSetUrl = CommonCodeSystemsTerminologyService.getValueSetUrl(valueSet);
StringBuilder valueSetIdentifierBuilder = new StringBuilder(CommonCodeSystemsTerminologyService.getValueSetUrl(valueSet));
String valueSetVersion = CommonCodeSystemsTerminologyService.getValueSetVersion(valueSet);
if (valueSetVersion != null) {
valueSetIdentifierBuilder.append("|").append(valueSetVersion);
}
valueSetIdentifier = valueSetIdentifierBuilder.toString();
} else if (haveIdentifierParam) {
valueSetUrl = theValueSetUrl;
valueSetIdentifier = theValueSetIdentifier;
} else {
throw new InvalidRequestException("Either ValueSet ID or ValueSet identifier or system and code must be provided. Unable to validate.");
}
ValidationSupportContext validationContext = new ValidationSupportContext(provideValidationSupport());
String code = theCode;
String system = theSystem;
String display = theDisplay;
String codeValueToValidate = theCodeToValidate;
String codeSystemIdentifierValueToValidate = theCodeSystemIdentifierToValidate;
String codeDisplayValueToValidate = theDisplayToValidate;
if (haveCodeableConcept) {
for (int i = 0; i < codeableConcept.getCoding().size(); i++) {
Coding nextCoding = codeableConcept.getCoding().get(i);
CodeValidationResult nextValidation = validateCode(validationContext, theOptions, nextCoding.getSystem(), nextCoding.getCode(), nextCoding.getDisplay(), valueSetUrl);
String codeSystemIdentifier;
if (nextCoding.hasVersion()) {
codeSystemIdentifier = nextCoding.getSystem() + "|" + nextCoding.getVersion();
} else {
codeSystemIdentifier = nextCoding.getSystem();
}
CodeValidationResult nextValidation = validateCode(validationContext, theOptions, codeSystemIdentifier, nextCoding.getCode(), nextCoding.getDisplay(), valueSetIdentifier);
if (nextValidation.isOk() || i == codeableConcept.getCoding().size() - 1) {
return nextValidation;
}
}
} else if (haveCoding) {
system = coding.getSystem();
code = coding.getCode();
display = coding.getDisplay();
if (canonicalCodingToValidate.hasVersion()) {
codeSystemIdentifierValueToValidate = canonicalCodingToValidate.getSystem() + "|" + canonicalCodingToValidate.getVersion();
} else {
codeSystemIdentifierValueToValidate = canonicalCodingToValidate.getSystem();
}
codeValueToValidate = canonicalCodingToValidate.getCode();
codeDisplayValueToValidate = canonicalCodingToValidate.getDisplay();
}
return validateCode(validationContext, theOptions, system, code, display, valueSetUrl);
return validateCode(validationContext, theOptions, codeSystemIdentifierValueToValidate, codeValueToValidate, codeDisplayValueToValidate, valueSetIdentifier);
}
private boolean isNotSafeToPreExpandValueSets() {
@ -1914,22 +1930,22 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
throw new InvalidRequestException("Unable to test subsumption across different code system versions");
}
String codeACanonicalUrl;
String codeASystemIdentifier;
if (StringUtils.isNotEmpty(conceptA.getSystemVersion())) {
codeACanonicalUrl = conceptA.getSystem() + "|" + conceptA.getSystemVersion();
codeASystemIdentifier = conceptA.getSystem() + "|" + conceptA.getSystemVersion();
} else {
codeACanonicalUrl = conceptA.getSystem();
codeASystemIdentifier = conceptA.getSystem();
}
TermConcept codeA = findCode(codeACanonicalUrl, conceptA.getCode())
TermConcept codeA = findCode(codeASystemIdentifier, conceptA.getCode())
.orElseThrow(() -> new InvalidRequestException("Unknown code: " + conceptA));
String codeBCanonicalUrl;
String codeBSystemIdentifier;
if (StringUtils.isNotEmpty(conceptB.getSystemVersion())) {
codeBCanonicalUrl = conceptB.getSystem() + "|" + conceptB.getSystemVersion();
codeBSystemIdentifier = conceptB.getSystem() + "|" + conceptB.getSystemVersion();
} else {
codeBCanonicalUrl = conceptB.getSystem();
codeBSystemIdentifier = conceptB.getSystem();
}
TermConcept codeB = findCode(codeBCanonicalUrl, conceptB.getCode())
TermConcept codeB = findCode(codeBSystemIdentifier, conceptB.getCode())
.orElseThrow(() -> new InvalidRequestException("Unknown code: " + conceptB));
FullTextEntityManager em = org.hibernate.search.jpa.Search.getFullTextEntityManager(myEntityManager);
@ -2405,6 +2421,9 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
@Nullable
protected abstract Coding toCanonicalCoding(@Nullable IBaseDatatype theCoding);
@Nullable
protected abstract Coding toCanonicalCoding(@Nullable IBaseCoding theCoding);
@Nullable
protected abstract CodeableConcept toCanonicalCodeableConcept(@Nullable IBaseDatatype theCodeableConcept);
@ -2496,14 +2515,15 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
}
@NotNull
private VersionIndependentConcept toConcept(IPrimitiveType<String> theCodeType, IPrimitiveType<String> theSystemType, IBaseCoding theCodingType) {
private VersionIndependentConcept toConcept(IPrimitiveType<String> theCodeType, IPrimitiveType<String> theCodeSystemIdentifierType, IBaseCoding theCodingType) {
String code = theCodeType != null ? theCodeType.getValueAsString() : null;
String system = theSystemType != null ? getSystemFromCanonicalUrl(theSystemType.getValueAsString()): null;
String systemVersion = theSystemType != null ? getVersionFromCanonicalUrl(theSystemType.getValueAsString()): null;
String system = theCodeSystemIdentifierType != null ? getUrlFromIdentifier(theCodeSystemIdentifierType.getValueAsString()): null;
String systemVersion = theCodeSystemIdentifierType != null ? getVersionFromIdentifier(theCodeSystemIdentifierType.getValueAsString()): null;
if (theCodingType != null) {
code = theCodingType.getCode();
system = getSystemFromCanonicalUrl(theCodingType.getSystem());
systemVersion = getVersionFromCanonicalUrl(theCodingType.getSystem());
Coding canonicalizedCoding = toCanonicalCoding(theCodingType);
code = canonicalizedCoding.getCode();
system = canonicalizedCoding.getSystem();
systemVersion = canonicalizedCoding.getVersion();
}
return new VersionIndependentConcept(system, code, null, systemVersion);
}

View File

@ -27,6 +27,7 @@ import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.model.dstu2.composite.CodeableConceptDt;
import ca.uhn.fhir.model.dstu2.composite.CodingDt;
import ca.uhn.fhir.util.VersionIndependentConcept;
import org.hl7.fhir.instance.model.api.IBaseCoding;
import org.hl7.fhir.instance.model.api.IBaseDatatype;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.model.CodeSystem;
@ -148,6 +149,17 @@ public class TermReadSvcDstu2 extends BaseTermReadSvcImpl {
return retVal;
}
@Nullable
@Override
protected Coding toCanonicalCoding(@Nullable IBaseCoding theCoding) {
Coding retVal = null;
if (theCoding != null) {
CodingDt coding = (CodingDt) theCoding;
retVal = new Coding(coding.getSystem(), coding.getCode(), coding.getDisplay());
}
return retVal;
}
@Nullable
@Override
protected CodeableConcept toCanonicalCodeableConcept(@Nullable IBaseDatatype theCodeableConcept) {
@ -157,7 +169,7 @@ public class TermReadSvcDstu2 extends BaseTermReadSvcImpl {
CodeableConceptDt cc = (CodeableConceptDt) theCodeableConcept;
outcome.setText(cc.getText());
for (CodingDt next : cc.getCoding()) {
outcome.addCoding(toCanonicalCoding(next));
outcome.addCoding(toCanonicalCoding((IBaseDatatype)next));
}
}
return outcome;

View File

@ -20,6 +20,7 @@ import org.hl7.fhir.dstu3.model.CodeableConcept;
import org.hl7.fhir.dstu3.model.Coding;
import org.hl7.fhir.dstu3.model.ValueSet;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.instance.model.api.IBaseCoding;
import org.hl7.fhir.instance.model.api.IBaseDatatype;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.utilities.validation.ValidationOptions;
@ -112,6 +113,12 @@ public class TermReadSvcDstu3 extends BaseTermReadSvcImpl implements IValidation
return VersionConvertor_30_40.convertCoding((org.hl7.fhir.dstu3.model.Coding) theCoding);
}
@Override
@Nullable
protected org.hl7.fhir.r4.model.Coding toCanonicalCoding(IBaseCoding theCoding) {
return VersionConvertor_30_40.convertCoding((org.hl7.fhir.dstu3.model.Coding) theCoding);
}
@Override
@Nullable
protected org.hl7.fhir.r4.model.CodeableConcept toCanonicalCodeableConcept(IBaseDatatype theCoding) {

View File

@ -8,6 +8,7 @@ import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.term.api.ITermReadSvcR4;
import ca.uhn.fhir.jpa.term.ex.ExpansionTooCostlyException;
import org.hl7.fhir.instance.model.api.IBaseCoding;
import org.hl7.fhir.instance.model.api.IBaseDatatype;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.model.CodeSystem;
@ -107,6 +108,11 @@ public class TermReadSvcR4 extends BaseTermReadSvcImpl implements ITermReadSvcR4
return (Coding) theCoding;
}
@Override
protected Coding toCanonicalCoding(IBaseCoding theCoding) {
return (Coding) theCoding;
}
@Override
protected CodeableConcept toCanonicalCodeableConcept(IBaseDatatype theCodeableConcept) {
return (CodeableConcept) theCodeableConcept;

View File

@ -12,6 +12,7 @@ import ca.uhn.fhir.jpa.term.ex.ExpansionTooCostlyException;
import ca.uhn.fhir.util.ValidateUtil;
import org.hl7.fhir.convertors.VersionConvertor_40_50;
import org.hl7.fhir.convertors.conv40_50.CodeSystem40_50;
import org.hl7.fhir.instance.model.api.IBaseCoding;
import org.hl7.fhir.instance.model.api.IBaseDatatype;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r5.model.CodeSystem;
@ -111,6 +112,12 @@ public class TermReadSvcR5 extends BaseTermReadSvcImpl implements IValidationSup
return VersionConvertor_40_50.convertCoding((Coding) theCoding);
}
@Override
@Nullable
protected org.hl7.fhir.r4.model.Coding toCanonicalCoding(IBaseCoding theCoding) {
return VersionConvertor_40_50.convertCoding((Coding) theCoding);
}
@Override
@Nullable
protected org.hl7.fhir.r4.model.CodeableConcept toCanonicalCodeableConcept(IBaseDatatype theCoding) {

View File

@ -29,6 +29,10 @@ import org.hl7.fhir.dstu3.model.ValueSet;
import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent;
import org.hl7.fhir.dstu3.model.ValueSet.FilterOperator;
import org.hl7.fhir.dstu3.model.codesystems.HttpVerb;
import org.hl7.fhir.dstu3.model.BooleanType;
import org.hl7.fhir.dstu3.model.CodeType;
import org.hl7.fhir.dstu3.model.CodeableConcept;
import org.hl7.fhir.dstu3.model.Coding;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.springframework.data.domain.PageRequest;
@ -49,6 +53,7 @@ import static org.hamcrest.Matchers.containsStringIgnoringCase;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.stringContainsInOrder;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
@ -116,21 +121,16 @@ public class ResourceProviderDstu3ValueSetVersionedTest extends BaseResourceProv
private void loadAndPersistValueSet() throws IOException {
ValueSet valueSet = loadResourceFromClasspath(ValueSet.class, "/extensional-case-3-vs.xml");
persistTwoVersionsOfValueSet(valueSet, HttpVerb.POST);
}
@SuppressWarnings("EnumSwitchStatementWhichMissesCases")
private void persistTwoVersionsOfValueSet(ValueSet theValueSet, HttpVerb theVerb) {
theValueSet.setVersion("1");
theValueSet.setId("ValueSet/vs1");
theValueSet.getCompose().getInclude().get(0).setVersion("1");
myExtensionalVsId_v1 = persistSingleValueSet(theValueSet, theVerb);
valueSet.setVersion("1");
valueSet.setId("ValueSet/vs1");
valueSet.getCompose().getInclude().get(0).setVersion("1");
myExtensionalVsId_v1 = persistSingleValueSet(valueSet, HttpVerb.POST);
myExtensionalVsIdOnResourceTable_v1 = myValueSetDao.readEntity(myExtensionalVsId_v1, null).getId();
theValueSet.setVersion("2");
theValueSet.setId("ValueSet/vs2");
theValueSet.getCompose().getInclude().get(0).setVersion("2");
myExtensionalVsId_v2 = persistSingleValueSet(theValueSet, theVerb);
valueSet.setVersion("2");
valueSet.setId("ValueSet/vs2");
valueSet.getCompose().getInclude().get(0).setVersion("2");
myExtensionalVsId_v2 = persistSingleValueSet(valueSet, HttpVerb.POST);
myExtensionalVsIdOnResourceTable_v2 = myValueSetDao.readEntity(myExtensionalVsId_v2, null).getId();
}
@ -138,6 +138,8 @@ public class ResourceProviderDstu3ValueSetVersionedTest extends BaseResourceProv
private IIdType persistSingleValueSet(ValueSet theValueSet, HttpVerb theVerb) {
final IIdType[] vsId = new IIdType[1];
switch (theVerb) {
case GET:
break;
case POST:
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
@Override
@ -154,6 +156,8 @@ public class ResourceProviderDstu3ValueSetVersionedTest extends BaseResourceProv
}
});
break;
case DELETE:
case NULL:
default:
throw new IllegalArgumentException("HTTP verb is not supported: " + theVerb);
}
@ -1053,7 +1057,7 @@ public class ResourceProviderDstu3ValueSetVersionedTest extends BaseResourceProv
TermValueSetConcept concept = termValueSet.getConcepts().get(0);
ourLog.info("Concept:\n" + concept.toString());
assertEquals("http://acme.org", concept.getSystem());
assertEquals("http://acme.org|1", concept.getSystem());
assertEquals("8450-9", concept.getCode());
assertEquals("Systolic blood pressure--expiration", concept.getDisplay());
assertEquals(2, concept.getDesignations().size());
@ -1075,7 +1079,7 @@ public class ResourceProviderDstu3ValueSetVersionedTest extends BaseResourceProv
concept = termValueSet.getConcepts().get(1);
ourLog.info("Concept:\n" + concept.toString());
assertEquals("http://acme.org", concept.getSystem());
assertEquals("http://acme.org|1", concept.getSystem());
assertEquals("11378-7", concept.getCode());
assertEquals("Systolic blood pressure at First encounter", concept.getDisplay());
assertEquals(0, concept.getDesignations().size());
@ -1085,7 +1089,7 @@ public class ResourceProviderDstu3ValueSetVersionedTest extends BaseResourceProv
concept = termValueSet.getConcepts().get(22);
ourLog.info("Concept:\n" + concept.toString());
assertEquals("http://acme.org", concept.getSystem());
assertEquals("http://acme.org|1", concept.getSystem());
assertEquals("8491-3", concept.getCode());
assertEquals("Systolic blood pressure 1 hour minimum", concept.getDisplay());
assertEquals(1, concept.getDesignations().size());
@ -1100,7 +1104,7 @@ public class ResourceProviderDstu3ValueSetVersionedTest extends BaseResourceProv
concept = termValueSet.getConcepts().get(23);
ourLog.info("Concept:\n" + concept.toString());
assertEquals("http://acme.org", concept.getSystem());
assertEquals("http://acme.org|1", concept.getSystem());
assertEquals("8492-1", concept.getCode());
assertEquals("Systolic blood pressure 8 hour minimum", concept.getDisplay());
assertEquals(0, concept.getDesignations().size());
@ -1126,7 +1130,7 @@ public class ResourceProviderDstu3ValueSetVersionedTest extends BaseResourceProv
TermValueSetConcept concept = termValueSet.getConcepts().get(0);
ourLog.info("Concept:\n" + concept.toString());
assertEquals("http://acme.org", concept.getSystem());
assertEquals("http://acme.org|2", concept.getSystem());
assertEquals("8450-9", concept.getCode());
assertEquals("Systolic blood pressure--expiration v2", concept.getDisplay());
assertEquals(2, concept.getDesignations().size());
@ -1148,7 +1152,7 @@ public class ResourceProviderDstu3ValueSetVersionedTest extends BaseResourceProv
concept = termValueSet.getConcepts().get(1);
ourLog.info("Concept:\n" + concept.toString());
assertEquals("http://acme.org", concept.getSystem());
assertEquals("http://acme.org|2", concept.getSystem());
assertEquals("11378-7", concept.getCode());
assertEquals("Systolic blood pressure at First encounter v2", concept.getDisplay());
assertEquals(0, concept.getDesignations().size());
@ -1158,7 +1162,7 @@ public class ResourceProviderDstu3ValueSetVersionedTest extends BaseResourceProv
concept = termValueSet.getConcepts().get(22);
ourLog.info("Concept:\n" + concept.toString());
assertEquals("http://acme.org", concept.getSystem());
assertEquals("http://acme.org|2", concept.getSystem());
assertEquals("8491-3", concept.getCode());
assertEquals("Systolic blood pressure 1 hour minimum v2", concept.getDisplay());
assertEquals(1, concept.getDesignations().size());
@ -1173,161 +1177,16 @@ public class ResourceProviderDstu3ValueSetVersionedTest extends BaseResourceProv
concept = termValueSet.getConcepts().get(23);
ourLog.info("Concept:\n" + concept.toString());
assertEquals("http://acme.org", concept.getSystem());
assertEquals("http://acme.org|2", concept.getSystem());
assertEquals("8492-1", concept.getCode());
assertEquals("Systolic blood pressure 8 hour minimum v2", concept.getDisplay());
assertEquals(0, concept.getDesignations().size());
assertEquals(23, concept.getOrder());
});
}
/*
@Test
public void testValidateCodeOperationByCodeAndSystemInstance() throws Exception {
loadAndPersistCodeSystemAndValueSet();
Parameters respParam = ourClient
.operation()
.onInstance(myExtensionalVsId_v1)
.named("validate-code")
.withParameter(Parameters.class, "code", new CodeType("8495-4"))
.andParameter("system", new UriType("http://acme.org"))
.execute();
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertEquals(true, ((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
}
@Test
public void testValidateCodeOperationByCodeAndSystemInstanceOnType() throws IOException {
createLocalCs();
createLocalVsWithIncludeConcept();
String url = ourServerBase +
"/ValueSet/" + myLocalValueSetId_v1.getIdPart() + "/$validate-code?system=" +
UrlUtil.escapeUrlParam(URL_MY_CODE_SYSTEM) +
"&code=AA";
HttpGet request = new HttpGet(url);
request.addHeader("Accept", "application/fhir+json");
try (CloseableHttpResponse response = ourHttpClient.execute(request)) {
String respString = IOUtils.toString(response.getEntity().getContent(), Charsets.UTF_8);
ourLog.info(respString);
Parameters respParam = myFhirCtx.newJsonParser().parseResource(Parameters.class, respString);
assertTrue(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
}
}
@Test
public void testValidateCodeOperationByCodeAndSystemInstanceOnInstance() throws IOException {
createLocalCs();
createLocalVsWithIncludeConcept();
String url = ourServerBase +
"/ValueSet/" + myLocalValueSetId_v1.getIdPart() + "/$validate-code?system=" +
UrlUtil.escapeUrlParam(URL_MY_CODE_SYSTEM) +
"&code=AA";
ourLog.info("* Requesting: {}", url);
HttpGet request = new HttpGet(url);
request.addHeader("Accept", "application/fhir+json");
try (CloseableHttpResponse response = ourHttpClient.execute(request)) {
String respString = IOUtils.toString(response.getEntity().getContent(), Charsets.UTF_8);
ourLog.info(respString);
Parameters respParam = myFhirCtx.newJsonParser().parseResource(Parameters.class, respString);
assertTrue(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
}
}
@Test
public void testValidateCodeOperationByCodeAndSystemType() throws Exception {
loadAndPersistCodeSystemAndValueSet();
Parameters respParam = ourClient
.operation()
.onInstance(myExtensionalVsId_v1)
.named("validate-code")
.withParameter(Parameters.class, "code", new CodeType("8450-9"))
.andParameter("system", new UriType("http://acme.org"))
.execute();
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertEquals(true, ((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
}
@Test
public void testValidateCodeOperationNoValueSetProvided() throws Exception {
loadAndPersistCodeSystemAndValueSet();
try {
ourClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "code", new CodeType("8450-9"))
.andParameter("system", new UriType("http://acme.org"))
.execute();
fail();
} catch (InvalidRequestException e) {
assertEquals("HTTP 400 Bad Request: Either ValueSet ID or ValueSet identifier or system and code must be provided. Unable to validate.", e.getMessage());
}
}
@Test
public void testValidateCodeOperationOnInstanceWithIsAExpansion() throws IOException {
CodeSystem cs = new CodeSystem();
cs.setUrl("http://mycs");
cs.setContent(CodeSystemContentMode.COMPLETE);
cs.setHierarchyMeaning(CodeSystem.CodeSystemHierarchyMeaning.ISA);
cs.setStatus(Enumerations.PublicationStatus.ACTIVE);
ConceptDefinitionComponent parentA = cs.addConcept().setCode("ParentA").setDisplay("Parent A");
parentA.addConcept().setCode("ChildAA").setDisplay("Child AA");
myCodeSystemDao.create(cs);
ValueSet vs = new ValueSet();
vs.setUrl("http://myvs");
vs.getCompose()
.addInclude()
.setSystem("http://mycs")
.addFilter()
.setOp(FilterOperator.ISA)
.setProperty("concept")
.setValue("ParentA");
IIdType vsId = myValueSetDao.create(vs).getId().toUnqualifiedVersionless();
HttpGet expandGet = new HttpGet(ourServerBase + "/ValueSet/" + vsId.getIdPart() + "/$expand?_pretty=true");
try (CloseableHttpResponse status = ourHttpClient.execute(expandGet)) {
String response = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8);
ourLog.info("Response: {}", response);
}
HttpGet validateCodeGet = new HttpGet(ourServerBase + "/ValueSet/" + vsId.getIdPart() + "/$validate-code?system=http://mycs&code=ChildAA&_pretty=true");
try (CloseableHttpResponse status = ourHttpClient.execute(validateCodeGet)) {
String response = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8);
ourLog.info("Response: {}", response);
Parameters output = myFhirCtx.newXmlParser().parseResource(Parameters.class, response);
assertEquals(true, output.getParameterBool("result"));
}
HttpGet validateCodeGet2 = new HttpGet(ourServerBase + "/ValueSet/" + vsId.getIdPart() + "/$validate-code?system=http://mycs&code=FOO&_pretty=true");
try (CloseableHttpResponse status = ourHttpClient.execute(validateCodeGet2)) {
String response = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8);
ourLog.info("Response: {}", response);
Parameters output = myFhirCtx.newXmlParser().parseResource(Parameters.class, response);
assertEquals(false, output.getParameterBool("result"));
}
}
*/
@Test
public void testCreateDuplicatValueSetVersion() {
public void testCreateDuplicateValueSetVersion() {
createExternalCsAndLocalVs();
try {
persistLocalVs(createLocalVs(URL_MY_CODE_SYSTEM, "1"));
@ -1338,6 +1197,284 @@ public class ResourceProviderDstu3ValueSetVersionedTest extends BaseResourceProv
}
@Test
public void testValidateCodeOperationByCodeAndSystem() throws Exception {
loadAndPersistCodeSystemAndValueSet();
// With correct system version specified. Should pass.
Parameters respParam = ourClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "code", new CodeType("8495-4"))
.andParameter("system", new UriType("http://acme.org"))
.andParameter("systemVersion", new StringType("1"))
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("1"))
.execute();
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertTrue(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
respParam = ourClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "code", new CodeType("8495-4"))
.andParameter("system", new UriType("http://acme.org"))
.andParameter("systemVersion", new StringType("2"))
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("2"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertTrue(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
// With incorrect version specified. Should fail.
respParam = ourClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "code", new CodeType("8495-4"))
.andParameter("system", new UriType("http://acme.org"))
.andParameter("systemVersion", new StringType("1"))
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("2"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertFalse(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
respParam = ourClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "code", new CodeType("8495-4"))
.andParameter("system", new UriType("http://acme.org"))
.andParameter("systemVersion", new StringType("2"))
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("1"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertFalse(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
}
@Test
public void testValidateCodeOperationOnInstanceByCodeAndSystem() throws Exception {
loadAndPersistCodeSystemAndValueSet();
// With correct system version specified. Should pass.
Parameters respParam = ourClient
.operation()
.onInstance(myExtensionalVsId_v1)
.named("validate-code")
.withParameter(Parameters.class, "code", new CodeType("8495-4"))
.andParameter("system", new UriType("http://acme.org"))
.andParameter("systemVersion", new StringType("1"))
.execute();
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertTrue(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
respParam = ourClient
.operation()
.onInstance(myExtensionalVsId_v2)
.named("validate-code")
.withParameter(Parameters.class, "code", new CodeType("8495-4"))
.andParameter("system", new UriType("http://acme.org"))
.andParameter("systemVersion", new StringType("2"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertTrue(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
// With incorrect version specified. Should fail.
respParam = ourClient
.operation()
.onInstance(myExtensionalVsId_v1)
.named("validate-code")
.withParameter(Parameters.class, "code", new CodeType("8495-4"))
.andParameter("system", new UriType("http://acme.org"))
.andParameter("systemVersion", new StringType("2"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertFalse(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
respParam = ourClient
.operation()
.onInstance(myExtensionalVsId_v2)
.named("validate-code")
.withParameter(Parameters.class, "code", new CodeType("8495-4"))
.andParameter("system", new UriType("http://acme.org"))
.andParameter("systemVersion", new StringType("1"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertFalse(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
}
@Test
public void testValidateCodeOperationByCoding() throws Exception {
loadAndPersistCodeSystemAndValueSet();
Coding codingToValidate_v1 = new Coding("http://acme.org", "8495-4", "Systolic blood pressure 24 hour minimum");
codingToValidate_v1.setVersion("1");
Coding codingToValidate_v2 = new Coding("http://acme.org", "8495-4", "Systolic blood pressure 24 hour minimum v2");
codingToValidate_v2.setVersion("2");
// With correct system version specified. Should pass.
Parameters respParam = ourClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "coding", codingToValidate_v1)
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("1"))
.execute();
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertTrue(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
respParam = ourClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "coding", codingToValidate_v2)
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("2"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertTrue(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
// With incorrect version specified. Should fail.
respParam = ourClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "coding", codingToValidate_v1)
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("2"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertFalse(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
respParam = ourClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "coding", codingToValidate_v2)
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("1"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertFalse(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
}
@Test
public void testValidateCodeOperationByCodeableConcept() throws Exception {
loadAndPersistCodeSystemAndValueSet();
Coding codingToValidate = new Coding("http://acme.org", "8495-4", "Systolic blood pressure 24 hour minimum");
codingToValidate.setVersion("1");
CodeableConcept codeableConceptToValidate_v1 = new CodeableConcept(codingToValidate);
codingToValidate = new Coding("http://acme.org", "8495-4", "Systolic blood pressure 24 hour minimum v2");
codingToValidate.setVersion("2");
CodeableConcept codeableConceptToValidate_v2 = new CodeableConcept(codingToValidate);
// With correct system version specified. Should pass.
Parameters respParam = ourClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "codeableConcept", codeableConceptToValidate_v1)
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("1"))
.execute();
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertTrue(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
respParam = ourClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "codeableConcept", codeableConceptToValidate_v2)
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("2"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertTrue(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
// With incorrect version specified. Should fail.
respParam = ourClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "codeableConcept", codeableConceptToValidate_v1)
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("2"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertFalse(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
respParam = ourClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "codeableConcept", codeableConceptToValidate_v2)
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("1"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertFalse(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
}
@AfterEach
public void afterResetPreExpansionDefault() {
myDaoConfig.setPreExpandValueSets(new DaoConfig().isPreExpandValueSets());

View File

@ -13,12 +13,11 @@ import ca.uhn.fhir.jpa.entity.TermValueSetPreExpansionStatusEnum;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.term.api.ITermCodeSystemStorageSvc;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import ca.uhn.fhir.util.UrlUtil;
import org.apache.commons.io.Charsets;
import com.google.common.base.Charsets;
import org.apache.commons.io.IOUtils;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
@ -29,6 +28,8 @@ import org.hl7.fhir.r4.model.CodeSystem;
import org.hl7.fhir.r4.model.CodeSystem.CodeSystemContentMode;
import org.hl7.fhir.r4.model.CodeSystem.ConceptDefinitionComponent;
import org.hl7.fhir.r4.model.CodeType;
import org.hl7.fhir.r4.model.CodeableConcept;
import org.hl7.fhir.r4.model.Coding;
import org.hl7.fhir.r4.model.Enumerations;
import org.hl7.fhir.r4.model.IdType;
import org.hl7.fhir.r4.model.Parameters;
@ -59,6 +60,7 @@ import static org.hamcrest.Matchers.containsStringIgnoringCase;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.stringContainsInOrder;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
@ -126,21 +128,16 @@ public class ResourceProviderR4ValueSetVersionedTest extends BaseResourceProvide
private void loadAndPersistValueSet() throws IOException {
ValueSet valueSet = loadResourceFromClasspath(ValueSet.class, "/extensional-case-3-vs.xml");
persistTwoVersionsOfValueSet(valueSet, HttpVerb.POST);
}
@SuppressWarnings("EnumSwitchStatementWhichMissesCases")
private void persistTwoVersionsOfValueSet(ValueSet theValueSet, HttpVerb theVerb) {
theValueSet.setVersion("1");
theValueSet.setId("ValueSet/vs1");
theValueSet.getCompose().getInclude().get(0).setVersion("1");
myExtensionalVsId_v1 = persistSingleValueSet(theValueSet, theVerb);
valueSet.setVersion("1");
valueSet.setId("ValueSet/vs1");
valueSet.getCompose().getInclude().get(0).setVersion("1");
myExtensionalVsId_v1 = persistSingleValueSet(valueSet, HttpVerb.POST);
myExtensionalVsIdOnResourceTable_v1 = myValueSetDao.readEntity(myExtensionalVsId_v1, null).getId();
theValueSet.setVersion("2");
theValueSet.setId("ValueSet/vs2");
theValueSet.getCompose().getInclude().get(0).setVersion("2");
myExtensionalVsId_v2 = persistSingleValueSet(theValueSet, theVerb);
valueSet.setVersion("2");
valueSet.setId("ValueSet/vs2");
valueSet.getCompose().getInclude().get(0).setVersion("2");
myExtensionalVsId_v2 = persistSingleValueSet(valueSet, HttpVerb.POST);
myExtensionalVsIdOnResourceTable_v2 = myValueSetDao.readEntity(myExtensionalVsId_v2, null).getId();
}
@ -148,6 +145,9 @@ public class ResourceProviderR4ValueSetVersionedTest extends BaseResourceProvide
private IIdType persistSingleValueSet(ValueSet theValueSet, HttpVerb theVerb) {
final IIdType[] vsId = new IIdType[1];
switch (theVerb) {
case GET:
case HEAD:
break;
case POST:
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
@Override
@ -164,6 +164,9 @@ public class ResourceProviderR4ValueSetVersionedTest extends BaseResourceProvide
}
});
break;
case DELETE:
case PATCH:
case NULL:
default:
throw new IllegalArgumentException("HTTP verb is not supported: " + theVerb);
}
@ -188,12 +191,6 @@ public class ResourceProviderR4ValueSetVersionedTest extends BaseResourceProvide
}
// private void createExternalCsAndLocalVsWithUnknownCode() {
// String codeSystemUrl = createExternalCs();
// createLocalVsWithUnknownCode(codeSystemUrl);
// }
private void createLocalCs() {
CodeSystem codeSystem = new CodeSystem();
codeSystem.setUrl(URL_MY_CODE_SYSTEM);
@ -250,27 +247,6 @@ public class ResourceProviderR4ValueSetVersionedTest extends BaseResourceProvide
return myValueSetDao.create(theValueSet, mySrd).getId().toUnqualifiedVersionless();
}
private void createLocalVsWithUnknownCode(String codeSystemUrl) {
myLocalVs_v1 = new ValueSet();
myLocalVs_v1.setUrl(URL_MY_VALUE_SET);
myLocalVs_v1.setVersion("1");
ConceptSetComponent include = myLocalVs_v1.getCompose().addInclude();
include.setSystem(codeSystemUrl);
include.setSystem("1");
include.addFilter().setProperty("concept").setOp(FilterOperator.ISA).setValue("childFOOOOOOO");
myLocalValueSetId_v1 = myValueSetDao.create(myLocalVs_v1, mySrd).getId().toUnqualifiedVersionless();
myLocalVs_v2 = new ValueSet();
myLocalVs_v2.setUrl(URL_MY_VALUE_SET);
myLocalVs_v2.setVersion("2");
include = myLocalVs_v2.getCompose().addInclude();
include.setSystem(codeSystemUrl);
include.setSystem("2");
include.addFilter().setProperty("concept").setOp(FilterOperator.ISA).setValue("childFOOOOOOO");
myLocalValueSetId_v2 = myValueSetDao.create(myLocalVs_v2, mySrd).getId().toUnqualifiedVersionless();
}
@Test
public void testExpandById() throws Exception {
loadAndPersistCodeSystemAndValueSet();
@ -1201,151 +1177,284 @@ public class ResourceProviderR4ValueSetVersionedTest extends BaseResourceProvide
assertEquals(23, concept.getOrder());
});
}
/*
@Test
public void testValidateCodeOperationByCodeAndSystemInstance() throws Exception {
public void testValidateCodeOperationByCodeAndSystem() throws Exception {
loadAndPersistCodeSystemAndValueSet();
// With correct system version specified. Should pass.
Parameters respParam = myClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "code", new CodeType("8495-4"))
.andParameter("system", new UriType("http://acme.org"))
.andParameter("systemVersion", new StringType("1"))
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("1"))
.execute();
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertTrue(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
respParam = myClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "code", new CodeType("8495-4"))
.andParameter("system", new UriType("http://acme.org"))
.andParameter("systemVersion", new StringType("2"))
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("2"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertTrue(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
// With incorrect version specified. Should fail.
respParam = myClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "code", new CodeType("8495-4"))
.andParameter("system", new UriType("http://acme.org"))
.andParameter("systemVersion", new StringType("1"))
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("2"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertFalse(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
respParam = myClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "code", new CodeType("8495-4"))
.andParameter("system", new UriType("http://acme.org"))
.andParameter("systemVersion", new StringType("2"))
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("1"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertFalse(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
}
@Test
public void testValidateCodeOperationOnInstanceByCodeAndSystem() throws Exception {
loadAndPersistCodeSystemAndValueSet();
// With correct system version specified. Should pass.
Parameters respParam = myClient
.operation()
.onInstance(myExtensionalVsId_v1)
.named("validate-code")
.withParameter(Parameters.class, "code", new CodeType("8495-4"))
.andParameter("system", new UriType("http://acme.org"))
.andParameter("systemVersion", new StringType("1"))
.execute();
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertEquals(true, ((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
}
@Test
public void testValidateCodeOperationByCodeAndSystemInstanceOnType() throws IOException {
createLocalCs();
createLocalVsWithIncludeConcept();
String url = ourServerBase +
"/ValueSet/" + myLocalValueSetId_v1.getIdPart() + "/$validate-code?system=" +
UrlUtil.escapeUrlParam(URL_MY_CODE_SYSTEM) +
"&code=AA";
HttpGet request = new HttpGet(url);
request.addHeader("Accept", "application/fhir+json");
try (CloseableHttpResponse response = ourHttpClient.execute(request)) {
String respString = IOUtils.toString(response.getEntity().getContent(), Charsets.UTF_8);
ourLog.info(respString);
Parameters respParam = myFhirCtx.newJsonParser().parseResource(Parameters.class, respString);
assertTrue(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
}
}
@Test
public void testValidateCodeOperationByCodeAndSystemInstanceOnInstance() throws IOException {
createLocalCs();
createLocalVsWithIncludeConcept();
respParam = myClient
.operation()
.onInstance(myExtensionalVsId_v2)
.named("validate-code")
.withParameter(Parameters.class, "code", new CodeType("8495-4"))
.andParameter("system", new UriType("http://acme.org"))
.andParameter("systemVersion", new StringType("2"))
.execute();
String url = ourServerBase +
"/ValueSet/" + myLocalValueSetId_v1.getIdPart() + "/$validate-code?system=" +
UrlUtil.escapeUrlParam(URL_MY_CODE_SYSTEM) +
"&code=AA";
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
ourLog.info("* Requesting: {}", url);
HttpGet request = new HttpGet(url);
request.addHeader("Accept", "application/fhir+json");
try (CloseableHttpResponse response = ourHttpClient.execute(request)) {
String respString = IOUtils.toString(response.getEntity().getContent(), Charsets.UTF_8);
ourLog.info(respString);
Parameters respParam = myFhirCtx.newJsonParser().parseResource(Parameters.class, respString);
assertTrue(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
}
}
@Test
public void testValidateCodeOperationByCodeAndSystemType() throws Exception {
loadAndPersistCodeSystemAndValueSet();
Parameters respParam = myClient
// With incorrect version specified. Should fail.
respParam = myClient
.operation()
.onInstance(myExtensionalVsId_v1)
.named("validate-code")
.withParameter(Parameters.class, "code", new CodeType("8450-9"))
.withParameter(Parameters.class, "code", new CodeType("8495-4"))
.andParameter("system", new UriType("http://acme.org"))
.andParameter("systemVersion", new StringType("2"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertFalse(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
respParam = myClient
.operation()
.onInstance(myExtensionalVsId_v2)
.named("validate-code")
.withParameter(Parameters.class, "code", new CodeType("8495-4"))
.andParameter("system", new UriType("http://acme.org"))
.andParameter("systemVersion", new StringType("1"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertFalse(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
}
@Test
public void testValidateCodeOperationByCoding() throws Exception {
loadAndPersistCodeSystemAndValueSet();
Coding codingToValidate_v1 = new Coding("http://acme.org", "8495-4", "Systolic blood pressure 24 hour minimum");
codingToValidate_v1.setVersion("1");
Coding codingToValidate_v2 = new Coding("http://acme.org", "8495-4", "Systolic blood pressure 24 hour minimum v2");
codingToValidate_v2.setVersion("2");
// With correct system version specified. Should pass.
Parameters respParam = myClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "coding", codingToValidate_v1)
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("1"))
.execute();
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertEquals(true, ((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
}
assertTrue(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
@Test
public void testValidateCodeOperationNoValueSetProvided() throws Exception {
loadAndPersistCodeSystemAndValueSet();
try {
myClient
respParam = myClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "code", new CodeType("8450-9"))
.andParameter("system", new UriType("http://acme.org"))
.withParameter(Parameters.class, "coding", codingToValidate_v2)
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("2"))
.execute();
fail();
} catch (InvalidRequestException e) {
assertEquals("HTTP 400 Bad Request: Either ValueSet ID or ValueSet identifier or system and code must be provided. Unable to validate.", e.getMessage());
}
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertTrue(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
// With incorrect version specified. Should fail.
respParam = myClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "coding", codingToValidate_v1)
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("2"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertFalse(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
respParam = myClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "coding", codingToValidate_v2)
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("1"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertFalse(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
}
@Test
public void testValidateCodeOperationOnInstanceWithIsAExpansion() throws IOException {
CodeSystem cs = new CodeSystem();
cs.setUrl("http://mycs");
cs.setContent(CodeSystemContentMode.COMPLETE);
cs.setHierarchyMeaning(CodeSystem.CodeSystemHierarchyMeaning.ISA);
cs.setStatus(Enumerations.PublicationStatus.ACTIVE);
ConceptDefinitionComponent parentA = cs.addConcept().setCode("ParentA").setDisplay("Parent A");
parentA.addConcept().setCode("ChildAA").setDisplay("Child AA");
myCodeSystemDao.create(cs);
public void testValidateCodeOperationByCodeableConcept() throws Exception {
loadAndPersistCodeSystemAndValueSet();
ValueSet vs = new ValueSet();
vs.setUrl("http://myvs");
vs.getCompose()
.addInclude()
.setSystem("http://mycs")
.addFilter()
.setOp(FilterOperator.ISA)
.setProperty("concept")
.setValue("ParentA");
IIdType vsId = myValueSetDao.create(vs).getId().toUnqualifiedVersionless();
Coding codingToValidate = new Coding("http://acme.org", "8495-4", "Systolic blood pressure 24 hour minimum");
codingToValidate.setVersion("1");
CodeableConcept codeableConceptToValidate_v1 = new CodeableConcept(codingToValidate);
HttpGet expandGet = new HttpGet(ourServerBase + "/ValueSet/" + vsId.getIdPart() + "/$expand?_pretty=true");
try (CloseableHttpResponse status = ourHttpClient.execute(expandGet)) {
String response = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8);
ourLog.info("Response: {}", response);
}
codingToValidate = new Coding("http://acme.org", "8495-4", "Systolic blood pressure 24 hour minimum v2");
codingToValidate.setVersion("2");
CodeableConcept codeableConceptToValidate_v2 = new CodeableConcept(codingToValidate);
HttpGet validateCodeGet = new HttpGet(ourServerBase + "/ValueSet/" + vsId.getIdPart() + "/$validate-code?system=http://mycs&code=ChildAA&_pretty=true");
try (CloseableHttpResponse status = ourHttpClient.execute(validateCodeGet)) {
String response = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8);
ourLog.info("Response: {}", response);
Parameters output = myFhirCtx.newXmlParser().parseResource(Parameters.class, response);
assertEquals(true, output.getParameterBool("result"));
}
// With correct system version specified. Should pass.
Parameters respParam = myClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "codeableConcept", codeableConceptToValidate_v1)
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("1"))
.execute();
HttpGet validateCodeGet2 = new HttpGet(ourServerBase + "/ValueSet/" + vsId.getIdPart() + "/$validate-code?system=http://mycs&code=FOO&_pretty=true");
try (CloseableHttpResponse status = ourHttpClient.execute(validateCodeGet2)) {
String response = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8);
ourLog.info("Response: {}", response);
Parameters output = myFhirCtx.newXmlParser().parseResource(Parameters.class, response);
assertEquals(false, output.getParameterBool("result"));
}
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertTrue(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
respParam = myClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "codeableConcept", codeableConceptToValidate_v2)
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("2"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertTrue(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
// With incorrect version specified. Should fail.
respParam = myClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "codeableConcept", codeableConceptToValidate_v1)
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("2"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertFalse(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
respParam = myClient
.operation()
.onType(ValueSet.class)
.named("validate-code")
.withParameter(Parameters.class, "codeableConcept", codeableConceptToValidate_v2)
.andParameter("url", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
.andParameter("valueSetVersion", new StringType("1"))
.execute();
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
ourLog.info(resp);
assertFalse(((BooleanType) respParam.getParameter().get(0).getValue()).booleanValue());
}
*/
private boolean clearDeferredStorageQueue() {

View File

@ -326,6 +326,30 @@ public class CommonCodeSystemsTerminologyService implements IValidationSupport {
return url;
}
public static String getValueSetVersion(@Nonnull IBaseResource theValueSet) {
String version;
switch (theValueSet.getStructureFhirVersionEnum()) {
case DSTU3: {
version = ((org.hl7.fhir.dstu3.model.ValueSet) theValueSet).getVersion();
break;
}
case R4: {
version = ((org.hl7.fhir.r4.model.ValueSet) theValueSet).getVersion();
break;
}
case R5: {
version = ((org.hl7.fhir.r5.model.ValueSet) theValueSet).getVersion();
break;
}
case DSTU2:
case DSTU2_HL7ORG:
case DSTU2_1:
default:
throw new IllegalArgumentException("Can not handle version: " + theValueSet.getStructureFhirVersionEnum());
}
return version;
}
private static HashMap<String, String> buildUspsCodes() {
HashMap<String, String> uspsCodes = new HashMap<>();
uspsCodes.put("AK", "Alaska");

View File

@ -91,23 +91,23 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
return new ValueSetExpansionOutcome(expansion, null);
}
private org.hl7.fhir.r5.model.ValueSet expandValueSetToCanonical(ValidationSupportContext theValidationSupportContext, IBaseResource theValueSetToExpand, @Nullable String theWantSystem, @Nullable String theWantCode) {
private org.hl7.fhir.r5.model.ValueSet expandValueSetToCanonical(ValidationSupportContext theValidationSupportContext, IBaseResource theValueSetToExpand, @Nullable String theWantSystemIdentifier, @Nullable String theWantCode) {
org.hl7.fhir.r5.model.ValueSet expansionR5;
switch (theValueSetToExpand.getStructureFhirVersionEnum()) {
case DSTU2: {
expansionR5 = expandValueSetDstu2(theValidationSupportContext, (ca.uhn.fhir.model.dstu2.resource.ValueSet) theValueSetToExpand, theWantSystem, theWantCode);
expansionR5 = expandValueSetDstu2(theValidationSupportContext, (ca.uhn.fhir.model.dstu2.resource.ValueSet) theValueSetToExpand, theWantSystemIdentifier, theWantCode);
break;
}
case DSTU2_HL7ORG: {
expansionR5 = expandValueSetDstu2Hl7Org(theValidationSupportContext, (ValueSet) theValueSetToExpand, theWantSystem, theWantCode);
expansionR5 = expandValueSetDstu2Hl7Org(theValidationSupportContext, (ValueSet) theValueSetToExpand, theWantSystemIdentifier, theWantCode);
break;
}
case DSTU3: {
expansionR5 = expandValueSetDstu3(theValidationSupportContext, (org.hl7.fhir.dstu3.model.ValueSet) theValueSetToExpand, theWantSystem, theWantCode);
expansionR5 = expandValueSetDstu3(theValidationSupportContext, (org.hl7.fhir.dstu3.model.ValueSet) theValueSetToExpand, theWantSystemIdentifier, theWantCode);
break;
}
case R4: {
expansionR5 = expandValueSetR4(theValidationSupportContext, (org.hl7.fhir.r4.model.ValueSet) theValueSetToExpand, theWantSystem, theWantCode);
expansionR5 = expandValueSetR4(theValidationSupportContext, (org.hl7.fhir.r4.model.ValueSet) theValueSetToExpand, theWantSystemIdentifier, theWantCode);
break;
}
case R5: {
@ -119,20 +119,17 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
throw new IllegalArgumentException("Can not handle version: " + myCtx.getVersion().getVersion());
}
if (expansionR5 == null) {
return null;
}
return expansionR5;
}
@Override
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);
validateCodeInValueSet(ValidationSupportContext theValidationSupportContext, ConceptValidationOptions theOptions, String theCodeSystemIdentifier, String theCode, String theDisplay, @Nonnull IBaseResource theValueSet) {
org.hl7.fhir.r5.model.ValueSet expansion = expandValueSetToCanonical(theValidationSupportContext, theValueSet, theCodeSystemIdentifier, theCode);
if (expansion == null) {
return null;
}
return validateCodeInExpandedValueSet(theValidationSupportContext, theOptions, theCodeSystem, theCode, theDisplay, expansion);
return validateCodeInExpandedValueSet(theValidationSupportContext, theOptions, theCodeSystemIdentifier, theCode, theDisplay, expansion);
}
@ -145,26 +142,59 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
return null;
}
} else {
String codeSystemUrl;
String codeSystemVersion = null;
int codeSystemVersionIndex = theCodeSystem.indexOf("|");
if (codeSystemVersionIndex > -1) {
codeSystemUrl = theCodeSystem.substring(0, codeSystemVersionIndex);
codeSystemVersion = theCodeSystem.substring(codeSystemVersionIndex + 1);
} else {
codeSystemUrl = theCodeSystem;
}
switch (myCtx.getVersion().getVersion()) {
case DSTU2_HL7ORG:
if (codeSystemVersion != null) {
vs = new org.hl7.fhir.dstu2.model.ValueSet()
.setCompose(new org.hl7.fhir.dstu2.model.ValueSet.ValueSetComposeComponent()
.addInclude(new org.hl7.fhir.dstu2.model.ValueSet.ConceptSetComponent().setSystem(codeSystemUrl).setVersion(codeSystemVersion)));
} else {
vs = new org.hl7.fhir.dstu2.model.ValueSet()
.setCompose(new org.hl7.fhir.dstu2.model.ValueSet.ValueSetComposeComponent()
.addInclude(new org.hl7.fhir.dstu2.model.ValueSet.ConceptSetComponent().setSystem(theCodeSystem)));
}
break;
case DSTU3:
if (codeSystemVersion != null) {
vs = new org.hl7.fhir.dstu3.model.ValueSet()
.setCompose(new org.hl7.fhir.dstu3.model.ValueSet.ValueSetComposeComponent()
.addInclude(new org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent().setSystem(codeSystemUrl).setVersion(codeSystemVersion)));
} else {
vs = new org.hl7.fhir.dstu3.model.ValueSet()
.setCompose(new org.hl7.fhir.dstu3.model.ValueSet.ValueSetComposeComponent()
.addInclude(new org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent().setSystem(theCodeSystem)));
}
break;
case R4:
if (codeSystemVersion != null) {
vs = new org.hl7.fhir.r4.model.ValueSet()
.setCompose(new org.hl7.fhir.r4.model.ValueSet.ValueSetComposeComponent()
.addInclude(new org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent().setSystem(codeSystemUrl).setVersion(codeSystemVersion)));
} else {
vs = new org.hl7.fhir.r4.model.ValueSet()
.setCompose(new org.hl7.fhir.r4.model.ValueSet.ValueSetComposeComponent()
.addInclude(new org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent().setSystem(theCodeSystem)));
}
break;
case R5:
if (codeSystemVersion != null) {
vs = new org.hl7.fhir.r5.model.ValueSet()
.setCompose(new org.hl7.fhir.r5.model.ValueSet.ValueSetComposeComponent()
.addInclude(new org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent().setSystem(codeSystemUrl).setVersion(codeSystemVersion)));
} else {
vs = new org.hl7.fhir.r5.model.ValueSet()
.setCompose(new org.hl7.fhir.r5.model.ValueSet.ValueSetComposeComponent()
.addInclude(new org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent().setSystem(theCodeSystem)));
}
break;
case DSTU2:
case DSTU2_1:
@ -184,39 +214,39 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
}
private CodeValidationResult validateCodeInExpandedValueSet(ValidationSupportContext theValidationSupportContext, ConceptValidationOptions theOptions, String theCodeSystem, String theCode, String theDisplay, IBaseResource theExpansion) {
private CodeValidationResult validateCodeInExpandedValueSet(ValidationSupportContext theValidationSupportContext, ConceptValidationOptions theOptions, String theCodeSystemIdentifierToValidate, String theCodeToValidate, String theDisplayToValidate, IBaseResource theExpansion) {
assert theExpansion != null;
boolean caseSensitive = true;
IBaseResource system = null;
if (!theOptions.isInferSystem() && isNotBlank(theCodeSystem)) {
system = theValidationSupportContext.getRootValidationSupport().fetchCodeSystem(theCodeSystem);
IBaseResource codeSystemToValidateResource = null;
if (!theOptions.isInferSystem() && isNotBlank(theCodeSystemIdentifierToValidate)) {
codeSystemToValidateResource = theValidationSupportContext.getRootValidationSupport().fetchCodeSystem(theCodeSystemIdentifierToValidate);
}
List<VersionIndependentConcept> codes = new ArrayList<>();
List<VersionIndependentConcept> codesInValueSetExpansion = new ArrayList<>();
switch (theExpansion.getStructureFhirVersionEnum()) {
case DSTU2_HL7ORG: {
ValueSet expansionVs = (ValueSet) theExpansion;
List<ValueSet.ValueSetExpansionContainsComponent> contains = expansionVs.getExpansion().getContains();
flattenAndConvertCodesDstu2(contains, codes);
flattenAndConvertCodesDstu2(contains, codesInValueSetExpansion);
break;
}
case DSTU3: {
org.hl7.fhir.dstu3.model.ValueSet expansionVs = (org.hl7.fhir.dstu3.model.ValueSet) theExpansion;
List<org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionContainsComponent> contains = expansionVs.getExpansion().getContains();
flattenAndConvertCodesDstu3(contains, codes);
flattenAndConvertCodesDstu3(contains, codesInValueSetExpansion);
break;
}
case R4: {
org.hl7.fhir.r4.model.ValueSet expansionVs = (org.hl7.fhir.r4.model.ValueSet) theExpansion;
List<org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionContainsComponent> contains = expansionVs.getExpansion().getContains();
flattenAndConvertCodesR4(contains, codes);
flattenAndConvertCodesR4(contains, codesInValueSetExpansion);
break;
}
case R5: {
org.hl7.fhir.r5.model.ValueSet expansionVs = (org.hl7.fhir.r5.model.ValueSet) theExpansion;
List<org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent> contains = expansionVs.getExpansion().getContains();
flattenAndConvertCodesR5(contains, codes);
flattenAndConvertCodesR5(contains, codesInValueSetExpansion);
break;
}
case DSTU2:
@ -225,37 +255,37 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
throw new IllegalArgumentException("Can not handle version: " + myCtx.getVersion().getVersion());
}
String codeSystemName = null;
String codeSystemVersion = null;
String codeSystemContentMode = null;
if (system != null) {
switch (system.getStructureFhirVersionEnum()) {
String codeSystemResourceName = null;
String codeSystemResourceVersion = null;
String codeSystemResourceContentMode = null;
if (codeSystemToValidateResource != null) {
switch (codeSystemToValidateResource.getStructureFhirVersionEnum()) {
case DSTU2_HL7ORG: {
caseSensitive = true;
break;
}
case DSTU3: {
org.hl7.fhir.dstu3.model.CodeSystem systemDstu3 = (org.hl7.fhir.dstu3.model.CodeSystem) system;
org.hl7.fhir.dstu3.model.CodeSystem systemDstu3 = (org.hl7.fhir.dstu3.model.CodeSystem) codeSystemToValidateResource;
caseSensitive = systemDstu3.getCaseSensitive();
codeSystemName = systemDstu3.getName();
codeSystemVersion = systemDstu3.getVersion();
codeSystemContentMode = systemDstu3.getContentElement().getValueAsString();
codeSystemResourceName = systemDstu3.getName();
codeSystemResourceVersion = systemDstu3.getVersion();
codeSystemResourceContentMode = systemDstu3.getContentElement().getValueAsString();
break;
}
case R4: {
org.hl7.fhir.r4.model.CodeSystem systemR4 = (org.hl7.fhir.r4.model.CodeSystem) system;
org.hl7.fhir.r4.model.CodeSystem systemR4 = (org.hl7.fhir.r4.model.CodeSystem) codeSystemToValidateResource;
caseSensitive = systemR4.getCaseSensitive();
codeSystemName = systemR4.getName();
codeSystemVersion = systemR4.getVersion();
codeSystemContentMode = systemR4.getContentElement().getValueAsString();
codeSystemResourceName = systemR4.getName();
codeSystemResourceVersion = systemR4.getVersion();
codeSystemResourceContentMode = systemR4.getContentElement().getValueAsString();
break;
}
case R5: {
CodeSystem systemR5 = (CodeSystem) system;
CodeSystem systemR5 = (CodeSystem) codeSystemToValidateResource;
caseSensitive = systemR5.getCaseSensitive();
codeSystemName = systemR5.getName();
codeSystemVersion = systemR5.getVersion();
codeSystemContentMode = systemR5.getContentElement().getValueAsString();
codeSystemResourceName = systemR5.getName();
codeSystemResourceVersion = systemR5.getVersion();
codeSystemResourceContentMode = systemR5.getContentElement().getValueAsString();
break;
}
case DSTU2:
@ -265,29 +295,40 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
}
}
for (VersionIndependentConcept nextExpansionCode : codes) {
String codeSystemUrlToValidate=null;
String codeSystemVersionToValidate=null;
if (theCodeSystemIdentifierToValidate != null) {
int versionIndex = theCodeSystemIdentifierToValidate.indexOf("|");
if (versionIndex > -1) {
codeSystemUrlToValidate = theCodeSystemIdentifierToValidate.substring(0, versionIndex);
codeSystemVersionToValidate = theCodeSystemIdentifierToValidate.substring(versionIndex+1);
} else {
codeSystemUrlToValidate = theCodeSystemIdentifierToValidate;
}
}
for (VersionIndependentConcept nextExpansionCode : codesInValueSetExpansion) {
boolean codeMatches;
if (caseSensitive) {
codeMatches = defaultString(theCode).equals(nextExpansionCode.getCode());
codeMatches = defaultString(theCodeToValidate).equals(nextExpansionCode.getCode());
} else {
codeMatches = defaultString(theCode).equalsIgnoreCase(nextExpansionCode.getCode());
codeMatches = defaultString(theCodeToValidate).equalsIgnoreCase(nextExpansionCode.getCode());
}
if (codeMatches) {
if (theOptions.isInferSystem() || nextExpansionCode.getSystem().equals(theCodeSystem)) {
if (!theOptions.isValidateDisplay() || (isBlank(nextExpansionCode.getDisplay()) || isBlank(theDisplay) || nextExpansionCode.getDisplay().equals(theDisplay))) {
if (theOptions.isInferSystem() || (nextExpansionCode.getSystem().equals(codeSystemUrlToValidate) && (codeSystemVersionToValidate == null || codeSystemVersionToValidate.equals(nextExpansionCode.getSystemVersion())))) {
if (!theOptions.isValidateDisplay() || (isBlank(nextExpansionCode.getDisplay()) || isBlank(theDisplayToValidate) || nextExpansionCode.getDisplay().equals(theDisplayToValidate))) {
return new CodeValidationResult()
.setCode(theCode)
.setCode(theCodeToValidate)
.setDisplay(nextExpansionCode.getDisplay())
.setCodeSystemName(codeSystemName)
.setCodeSystemVersion(codeSystemVersion);
.setCodeSystemName(codeSystemResourceName)
.setCodeSystemVersion(codeSystemResourceVersion);
} else {
return new CodeValidationResult()
.setSeverity(IssueSeverity.ERROR)
.setDisplay(nextExpansionCode.getDisplay())
.setMessage("Concept Display \"" + theDisplay + "\" does not match expected \"" + nextExpansionCode.getDisplay() + "\"")
.setCodeSystemName(codeSystemName)
.setCodeSystemVersion(codeSystemVersion);
.setMessage("Concept Display \"" + theDisplayToValidate + "\" does not match expected \"" + nextExpansionCode.getDisplay() + "\"")
.setCodeSystemName(codeSystemResourceName)
.setCodeSystemVersion(codeSystemResourceVersion);
}
}
}
@ -295,12 +336,12 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
ValidationMessage.IssueSeverity severity;
String message;
if ("fragment".equals(codeSystemContentMode)) {
if ("fragment".equals(codeSystemResourceContentMode)) {
severity = ValidationMessage.IssueSeverity.WARNING;
message = "Unknown code in fragment CodeSystem '" + (isNotBlank(theCodeSystem) ? theCodeSystem + "#" : "") + theCode + "'";
message = "Unknown code in fragment CodeSystem '" + (isNotBlank(theCodeSystemIdentifierToValidate) ? theCodeSystemIdentifierToValidate + "#" : "") + theCodeToValidate + "'";
} else {
severity = ValidationMessage.IssueSeverity.ERROR;
message = "Unknown code '" + (isNotBlank(theCodeSystem) ? theCodeSystem + "#" : "") + theCode + "'";
message = "Unknown code '" + (isNotBlank(theCodeSystemIdentifierToValidate) ? theCodeSystemIdentifierToValidate + "#" : "") + theCodeToValidate + "'";
}
return new CodeValidationResult()
@ -314,7 +355,7 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
}
@Nullable
private org.hl7.fhir.r5.model.ValueSet expandValueSetDstu2Hl7Org(ValidationSupportContext theValidationSupportContext, ValueSet theInput, @Nullable String theWantSystem, @Nullable String theWantCode) {
private org.hl7.fhir.r5.model.ValueSet expandValueSetDstu2Hl7Org(ValidationSupportContext theValidationSupportContext, ValueSet theInput, @Nullable String theWantSystemIdentifier, @Nullable String theWantCode) {
Function<String, CodeSystem> codeSystemLoader = t -> {
org.hl7.fhir.dstu2.model.ValueSet codeSystem = (org.hl7.fhir.dstu2.model.ValueSet) theValidationSupportContext.getRootValidationSupport().fetchCodeSystem(t);
CodeSystem retVal = new CodeSystem();
@ -327,12 +368,12 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
};
org.hl7.fhir.r5.model.ValueSet input = ValueSet10_50.convertValueSet(theInput);
org.hl7.fhir.r5.model.ValueSet output = expandValueSetR5(theValidationSupportContext, input, codeSystemLoader, valueSetLoader, theWantSystem, theWantCode);
org.hl7.fhir.r5.model.ValueSet output = expandValueSetR5(theValidationSupportContext, input, codeSystemLoader, valueSetLoader, theWantSystemIdentifier, theWantCode);
return (output);
}
@Nullable
private org.hl7.fhir.r5.model.ValueSet expandValueSetDstu2(ValidationSupportContext theValidationSupportContext, ca.uhn.fhir.model.dstu2.resource.ValueSet theInput, @Nullable String theWantSystem, @Nullable String theWantCode) {
private org.hl7.fhir.r5.model.ValueSet expandValueSetDstu2(ValidationSupportContext theValidationSupportContext, ca.uhn.fhir.model.dstu2.resource.ValueSet theInput, @Nullable String theWantSystemIdentifier, @Nullable String theWantCode) {
IParser parserRi = FhirContext.forCached(FhirVersionEnum.DSTU2_HL7ORG).newJsonParser();
IParser parserHapi = FhirContext.forCached(FhirVersionEnum.DSTU2).newJsonParser();
@ -355,7 +396,7 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
org.hl7.fhir.dstu2.model.ValueSet valueSetRi = parserRi.parseResource(org.hl7.fhir.dstu2.model.ValueSet.class, parserHapi.encodeResourceToString(theInput));
org.hl7.fhir.r5.model.ValueSet input = ValueSet10_50.convertValueSet(valueSetRi);
org.hl7.fhir.r5.model.ValueSet output = expandValueSetR5(theValidationSupportContext, input, codeSystemLoader, valueSetLoader, theWantSystem, theWantCode);
org.hl7.fhir.r5.model.ValueSet output = expandValueSetR5(theValidationSupportContext, input, codeSystemLoader, valueSetLoader, theWantSystemIdentifier, theWantCode);
return (output);
}
@ -404,7 +445,7 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
}
@Nullable
private org.hl7.fhir.r5.model.ValueSet expandValueSetDstu3(ValidationSupportContext theValidationSupportContext, org.hl7.fhir.dstu3.model.ValueSet theInput, @Nullable String theWantSystem, @Nullable String theWantCode) {
private org.hl7.fhir.r5.model.ValueSet expandValueSetDstu3(ValidationSupportContext theValidationSupportContext, org.hl7.fhir.dstu3.model.ValueSet theInput, @Nullable String theWantSystemIdentifier, @Nullable String theWantCode) {
Function<String, org.hl7.fhir.r5.model.CodeSystem> codeSystemLoader = t -> {
org.hl7.fhir.dstu3.model.CodeSystem codeSystem = (org.hl7.fhir.dstu3.model.CodeSystem) theValidationSupportContext.getRootValidationSupport().fetchCodeSystem(t);
return CodeSystem30_50.convertCodeSystem(codeSystem);
@ -415,12 +456,12 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
};
org.hl7.fhir.r5.model.ValueSet input = ValueSet30_50.convertValueSet(theInput);
org.hl7.fhir.r5.model.ValueSet output = expandValueSetR5(theValidationSupportContext, input, codeSystemLoader, valueSetLoader, theWantSystem, theWantCode);
org.hl7.fhir.r5.model.ValueSet output = expandValueSetR5(theValidationSupportContext, input, codeSystemLoader, valueSetLoader, theWantSystemIdentifier, theWantCode);
return (output);
}
@Nullable
private org.hl7.fhir.r5.model.ValueSet expandValueSetR4(ValidationSupportContext theValidationSupportContext, org.hl7.fhir.r4.model.ValueSet theInput, @Nullable String theWantSystem, @Nullable String theWantCode) {
private org.hl7.fhir.r5.model.ValueSet expandValueSetR4(ValidationSupportContext theValidationSupportContext, org.hl7.fhir.r4.model.ValueSet theInput, @Nullable String theWantSystemIdentifier, @Nullable String theWantCode) {
Function<String, org.hl7.fhir.r5.model.CodeSystem> codeSystemLoader = t -> {
org.hl7.fhir.r4.model.CodeSystem codeSystem = (org.hl7.fhir.r4.model.CodeSystem) theValidationSupportContext.getRootValidationSupport().fetchCodeSystem(t);
return CodeSystem40_50.convertCodeSystem(codeSystem);
@ -431,7 +472,7 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
};
org.hl7.fhir.r5.model.ValueSet input = ValueSet40_50.convertValueSet(theInput);
org.hl7.fhir.r5.model.ValueSet output = expandValueSetR5(theValidationSupportContext, input, codeSystemLoader, valueSetLoader, theWantSystem, theWantCode);
org.hl7.fhir.r5.model.ValueSet output = expandValueSetR5(theValidationSupportContext, input, codeSystemLoader, valueSetLoader, theWantSystemIdentifier, theWantCode);
return (output);
}
@ -444,12 +485,12 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
}
@Nullable
private org.hl7.fhir.r5.model.ValueSet expandValueSetR5(ValidationSupportContext theValidationSupportContext, org.hl7.fhir.r5.model.ValueSet theInput, Function<String, CodeSystem> theCodeSystemLoader, Function<String, org.hl7.fhir.r5.model.ValueSet> theValueSetLoader, @Nullable String theWantSystem, @Nullable String theWantCode) {
private org.hl7.fhir.r5.model.ValueSet expandValueSetR5(ValidationSupportContext theValidationSupportContext, org.hl7.fhir.r5.model.ValueSet theInput, Function<String, CodeSystem> theCodeSystemLoader, Function<String, org.hl7.fhir.r5.model.ValueSet> theValueSetLoader, @Nullable String theWantSystemIdentifier, @Nullable String theWantCode) {
Set<VersionIndependentConcept> concepts = new HashSet<>();
try {
expandValueSetR5IncludeOrExclude(theValidationSupportContext, concepts, theCodeSystemLoader, theValueSetLoader, theInput.getCompose().getInclude(), true, theWantSystem, theWantCode);
expandValueSetR5IncludeOrExclude(theValidationSupportContext, concepts, theCodeSystemLoader, theValueSetLoader, theInput.getCompose().getExclude(), false, theWantSystem, theWantCode);
expandValueSetR5IncludeOrExclude(theValidationSupportContext, concepts, theCodeSystemLoader, theValueSetLoader, theInput.getCompose().getInclude(), true, theWantSystemIdentifier, theWantCode);
expandValueSetR5IncludeOrExclude(theValidationSupportContext, concepts, theCodeSystemLoader, theValueSetLoader, theInput.getCompose().getExclude(), false, theWantSystemIdentifier, theWantCode);
} catch (ExpansionCouldNotBeCompletedInternallyException e) {
return null;
}
@ -460,23 +501,46 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
contains.setSystem(next.getSystem());
contains.setCode(next.getCode());
contains.setDisplay(next.getDisplay());
contains.setVersion(next.getSystemVersion());
}
return retVal;
}
private void expandValueSetR5IncludeOrExclude(ValidationSupportContext theValidationSupportContext, Set<VersionIndependentConcept> theConcepts, Function<String, CodeSystem> theCodeSystemLoader, Function<String, org.hl7.fhir.r5.model.ValueSet> theValueSetLoader, List<org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent> theComposeList, boolean theComposeListIsInclude, @Nullable String theWantSystem, @Nullable String theWantCode) throws ExpansionCouldNotBeCompletedInternallyException {
private void expandValueSetR5IncludeOrExclude(ValidationSupportContext theValidationSupportContext, Set<VersionIndependentConcept> theConcepts, Function<String, CodeSystem> theCodeSystemLoader, Function<String, org.hl7.fhir.r5.model.ValueSet> theValueSetLoader, List<org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent> theComposeList, boolean theComposeListIsInclude, @Nullable String theWantSystemIdentifier, @Nullable String theWantCode) throws ExpansionCouldNotBeCompletedInternallyException {
String wantSystemUrl = null;
String wantSystemVersion = null;
if (theWantSystemIdentifier != null) {
int versionIndex = theWantSystemIdentifier.indexOf("|");
if (versionIndex > -1) {
wantSystemUrl = theWantSystemIdentifier.substring(0,versionIndex);
wantSystemVersion = theWantSystemIdentifier.substring(versionIndex+1);
} else {
wantSystemUrl = theWantSystemIdentifier;
}
}
for (org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent nextInclude : theComposeList) {
List<VersionIndependentConcept> nextCodeList = new ArrayList<>();
String system = nextInclude.getSystem();
if (isNotBlank(system)) {
String includeOrExcludeConceptSystemUrl = nextInclude.getSystem();
String includeOrExcludeConceptSystemVersion = nextInclude.getVersion();
if (isNotBlank(includeOrExcludeConceptSystemUrl)) {
if (theWantSystem != null && !theWantSystem.equals(system)) {
if (wantSystemUrl != null && !wantSystemUrl.equals(includeOrExcludeConceptSystemUrl)) {
continue;
}
CodeSystem codeSystem = theCodeSystemLoader.apply(system);
if (wantSystemVersion != null && !wantSystemVersion.equals(includeOrExcludeConceptSystemVersion)) {
continue;
}
CodeSystem includeOrExcludeSystemResource;
if (includeOrExcludeConceptSystemVersion != null) {
includeOrExcludeSystemResource = theCodeSystemLoader.apply(includeOrExcludeConceptSystemUrl + "|" + includeOrExcludeConceptSystemVersion);
} else {
includeOrExcludeSystemResource = theCodeSystemLoader.apply(includeOrExcludeConceptSystemUrl);
}
Set<String> wantCodes;
if (nextInclude.getConcept().isEmpty()) {
@ -488,18 +552,18 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
}
boolean ableToHandleCode = false;
if (codeSystem == null || codeSystem.getContent() == CodeSystem.CodeSystemContentMode.NOTPRESENT) {
if (includeOrExcludeSystemResource == null || includeOrExcludeSystemResource.getContent() == CodeSystem.CodeSystemContentMode.NOTPRESENT) {
if (theWantCode != null) {
if (theValidationSupportContext.getRootValidationSupport().isCodeSystemSupported(theValidationSupportContext, system)) {
LookupCodeResult lookup = theValidationSupportContext.getRootValidationSupport().lookupCode(theValidationSupportContext, system, theWantCode);
if (theValidationSupportContext.getRootValidationSupport().isCodeSystemSupported(theValidationSupportContext, includeOrExcludeConceptSystemUrl)) {
LookupCodeResult lookup = theValidationSupportContext.getRootValidationSupport().lookupCode(theValidationSupportContext, includeOrExcludeConceptSystemUrl, theWantCode);
if (lookup != null && lookup.isFound()) {
CodeSystem.ConceptDefinitionComponent conceptDefinition = new CodeSystem.ConceptDefinitionComponent()
.addConcept()
.setCode(theWantCode)
.setDisplay(lookup.getCodeDisplay());
List<CodeSystem.ConceptDefinitionComponent> codesList = Collections.singletonList(conceptDefinition);
addCodes(system, codesList, nextCodeList, wantCodes);
addCodes(includeOrExcludeConceptSystemUrl, includeOrExcludeConceptSystemVersion, codesList, nextCodeList, wantCodes);
ableToHandleCode = true;
}
} else if (theComposeListIsInclude) {
@ -514,7 +578,7 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
* enumerate a set of good codes for them is a nice compromise there.
*/
for (org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent next : theComposeList) {
if (Objects.equals(next.getSystem(), theWantSystem)) {
if (Objects.equals(next.getSystem(), theWantSystemIdentifier)) {
Optional<org.hl7.fhir.r5.model.ValueSet.ConceptReferenceComponent> matchingEnumeratedConcept = next.getConcept().stream().filter(t -> Objects.equals(t.getCode(), theWantCode)).findFirst();
if (matchingEnumeratedConcept.isPresent()) {
CodeSystem.ConceptDefinitionComponent conceptDefinition = new CodeSystem.ConceptDefinitionComponent()
@ -522,7 +586,7 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
.setCode(theWantCode)
.setDisplay(matchingEnumeratedConcept.get().getDisplay());
List<CodeSystem.ConceptDefinitionComponent> codesList = Collections.singletonList(conceptDefinition);
addCodes(system, codesList, nextCodeList, wantCodes);
addCodes(includeOrExcludeConceptSystemUrl, includeOrExcludeConceptSystemVersion, codesList, nextCodeList, wantCodes);
ableToHandleCode = true;
break;
}
@ -540,8 +604,8 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
throw new ExpansionCouldNotBeCompletedInternallyException();
}
if (codeSystem != null && codeSystem.getContent() != CodeSystem.CodeSystemContentMode.NOTPRESENT) {
addCodes(system, codeSystem.getConcept(), nextCodeList, wantCodes);
if (includeOrExcludeSystemResource != null && includeOrExcludeSystemResource.getContent() != CodeSystem.CodeSystemContentMode.NOTPRESENT) {
addCodes(includeOrExcludeConceptSystemUrl, includeOrExcludeConceptSystemVersion, includeOrExcludeSystemResource.getConcept(), nextCodeList, wantCodes);
}
}
@ -549,12 +613,12 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
for (CanonicalType nextValueSetInclude : nextInclude.getValueSet()) {
org.hl7.fhir.r5.model.ValueSet vs = theValueSetLoader.apply(nextValueSetInclude.getValueAsString());
if (vs != null) {
org.hl7.fhir.r5.model.ValueSet subExpansion = expandValueSetR5(theValidationSupportContext, vs, theCodeSystemLoader, theValueSetLoader, theWantSystem, theWantCode);
org.hl7.fhir.r5.model.ValueSet subExpansion = expandValueSetR5(theValidationSupportContext, vs, theCodeSystemLoader, theValueSetLoader, theWantSystemIdentifier, theWantCode);
if (subExpansion == null) {
throw new ExpansionCouldNotBeCompletedInternallyException();
}
for (org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent next : subExpansion.getExpansion().getContains()) {
nextCodeList.add(new VersionIndependentConcept(next.getSystem(), next.getCode(), next.getDisplay()));
nextCodeList.add(new VersionIndependentConcept(next.getSystem(), next.getCode(), next.getDisplay(), next.getVersion()));
}
}
}
@ -569,14 +633,14 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
}
private void addCodes(String theSystem, List<CodeSystem.ConceptDefinitionComponent> theSource, List<VersionIndependentConcept> theTarget, Set<String> theCodeFilter) {
private void addCodes(String theCodeSystemUrl, String theCodeSystemVersion, List<CodeSystem.ConceptDefinitionComponent> theSource, List<VersionIndependentConcept> theTarget, Set<String> theCodeFilter) {
for (CodeSystem.ConceptDefinitionComponent next : theSource) {
if (isNotBlank(next.getCode())) {
if (theCodeFilter == null || theCodeFilter.contains(next.getCode())) {
theTarget.add(new VersionIndependentConcept(theSystem, next.getCode(), next.getDisplay()));
theTarget.add(new VersionIndependentConcept(theCodeSystemUrl, next.getCode(), next.getDisplay(), theCodeSystemVersion));
}
}
addCodes(theSystem, next.getConcept(), theTarget, theCodeFilter);
addCodes(theCodeSystemUrl, theCodeSystemVersion, next.getConcept(), theTarget, theCodeFilter);
}
}
@ -593,21 +657,21 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
private static void flattenAndConvertCodesDstu3(List<org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionContainsComponent> theInput, List<VersionIndependentConcept> theVersionIndependentConcepts) {
for (org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionContainsComponent next : theInput) {
theVersionIndependentConcepts.add(new VersionIndependentConcept(next.getSystem(), next.getCode(), next.getDisplay()));
theVersionIndependentConcepts.add(new VersionIndependentConcept(next.getSystem(), next.getCode(), next.getDisplay(), next.getVersion()));
flattenAndConvertCodesDstu3(next.getContains(), theVersionIndependentConcepts);
}
}
private static void flattenAndConvertCodesR4(List<org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionContainsComponent> theInput, List<VersionIndependentConcept> theVersionIndependentConcepts) {
for (org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionContainsComponent next : theInput) {
theVersionIndependentConcepts.add(new VersionIndependentConcept(next.getSystem(), next.getCode(), next.getDisplay()));
theVersionIndependentConcepts.add(new VersionIndependentConcept(next.getSystem(), next.getCode(), next.getDisplay(), next.getVersion()));
flattenAndConvertCodesR4(next.getContains(), theVersionIndependentConcepts);
}
}
private static void flattenAndConvertCodesR5(List<org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent> theInput, List<VersionIndependentConcept> theVersionIndependentConcepts) {
for (org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent next : theInput) {
theVersionIndependentConcepts.add(new VersionIndependentConcept(next.getSystem(), next.getCode(), next.getDisplay()));
theVersionIndependentConcepts.add(new VersionIndependentConcept(next.getSystem(), next.getCode(), next.getDisplay(), next.getVersion()));
flattenAndConvertCodesR5(next.getContains(), theVersionIndependentConcepts);
}
}