@Override public ValueSet expandByIdentifier(String theUri, String theFilter) { if (isBlank(theUri)) { throw new InvalidRequestException("URI must not be blank or missing"); } ValueSet source = new ValueSet(); source.getCompose().addImport(theUri); if (isNotBlank(theFilter)) { ConceptSetComponent include = source.getCompose().addInclude(); ConceptSetFilterComponent filter = include.addFilter(); filter.setProperty("display"); filter.setOp(FilterOperator.EQUAL); filter.setValue(theFilter); } ValueSet retVal = doExpand(source); return retVal; // if (defaultValueSet != null) { // source = getContext().newJsonParser().parseResource(ValueSet.class, // getContext().newJsonParser().encodeResourceToString(defaultValueSet)); // } else { // IBundleProvider ids = search(ValueSet.SP_URL, new UriParam(theUri)); // if (ids.size() == 0) { // throw new InvalidRequestException("Unknown ValueSet URI: " + theUri); // } // source = (ValueSet) ids.getResources(0, 1).get(0); // } // // return expand(defaultValueSet, theFilter); }
private String getVSSummary(ValueSet vs) { CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); for (ConceptSetComponent cc : vs.getCompose().getInclude()) b.append("Include " + getIncSummary(cc)); for (ConceptSetComponent cc : vs.getCompose().getExclude()) b.append("Exclude " + getIncSummary(cc)); return b.toString(); }
private boolean notcomplete(ValueSet vs) { if (!vs.hasExpansion()) return true; if (!vs.getExpansion() .getExtensionsByUrl("http://hl7.org/fhir/StructureDefinition/valueset-unclosed") .isEmpty()) return true; if (!vs.getExpansion() .getExtensionsByUrl("http://hl7.org/fhir/StructureDefinition/valueset-toocostly") .isEmpty()) return true; return false; }
/** * Only produce the v3 vocabulary for appending to rim.ttl * * @throws Exception */ public void executeV3(Map<String, ValueSet> valuesets, Map<String, CodeSystem> codeSystems) throws Exception { for (ValueSet vs : this.valuesets.values()) { valuesets.put("vs:" + tail(vs.getUrl()), vs); } // for (String n : sorted(valuesets.keySet())) // gen(n, valuesets.get(n)); commit(false); }
private ValidationResult verifyCodeInExpansion(ValueSet vs, String code) throws FHIRException { if (vs.getExpansion() .hasExtension("http://hl7.org/fhir/StructureDefinition/valueset-toocostly")) { throw new FHIRException("Unable to validate core - value set is too costly to expand"); } else { ValueSetExpansionContainsComponent cc = findCode(vs.getExpansion().getContains(), code); if (cc == null) return new ValidationResult( IssueSeverity.ERROR, "Unknown Code " + code + " in " + vs.getUrl()); return null; } }
@Override public ValueSetExpansionComponent expandVS(ConceptSetComponent inc, boolean heirachical) throws TerminologyServiceException { ValueSet vs = new ValueSet(); vs.setCompose(new ValueSetComposeComponent()); vs.getCompose().getInclude().add(inc); ValueSetExpansionOutcome vse = expandVS(vs, true, heirachical); ValueSet valueset = vse.getValueset(); if (valueset == null) throw new TerminologyServiceException("Error Expanding ValueSet: " + vse.getError()); return valueset.getExpansion(); }
@Override public ValidationResult validateCode( String system, String code, String display, ConceptSetComponent vsi) { try { ValueSet vs = new ValueSet(); vs.setUrl(Utilities.makeUuidUrn()); vs.getCompose().addInclude(vsi); return verifyCodeExternal( vs, new Coding().setSystem(system).setCode(code).setDisplay(display), true); } catch (Exception e) { return new ValidationResult( IssueSeverity.FATAL, "Error validating code \"" + code + "\" in system \"" + system + "\": " + e.getMessage()); } }
private ValueSet doExpand(ValueSet theSource) { validateIncludes("include", theSource.getCompose().getInclude()); validateIncludes("exclude", theSource.getCompose().getExclude()); HapiWorkerContext workerContext = new HapiWorkerContext(getContext(), myValidationSupport); ValueSetExpansionOutcome outcome = workerContext.expand(theSource); ValueSetExpansionComponent expansion = outcome.getValueset().getExpansion(); ValueSet retVal = new ValueSet(); retVal.getMeta().setLastUpdated(new Date()); retVal.setExpansion(expansion); return retVal; }
@Override public ValueSetExpansionOutcome expandVS(ValueSet vs, boolean cacheOk, boolean heirarchical) { try { if (vs.hasExpansion()) { return new ValueSetExpansionOutcome(vs.copy()); } String cacheFn = null; if (cache != null) { cacheFn = Utilities.path(cache, determineCacheId(vs, heirarchical) + ".json"); if (new File(cacheFn).exists()) return loadFromCache(vs.copy(), cacheFn); } if (cacheOk && vs.hasUrl()) { if (expProfile == null) throw new Exception("No ExpansionProfile provided"); ValueSetExpansionOutcome vse = expansionCache.getExpander().expand(vs, expProfile.setExcludeNested(!heirarchical)); if (vse.getValueset() != null) { if (cache != null) { FileOutputStream s = new FileOutputStream(cacheFn); newJsonParser().compose(new FileOutputStream(cacheFn), vse.getValueset()); s.close(); } } return vse; } else { ValueSetExpansionOutcome res = expandOnServer(vs, cacheFn); if (cacheFn != null) { if (res.getValueset() != null) { saveToCache(res.getValueset(), cacheFn); } else { OperationOutcome oo = new OperationOutcome(); oo.addIssue().getDetails().setText(res.getError()); saveToCache(oo, cacheFn); } } return res; } } catch (NoTerminologyServiceException e) { return new ValueSetExpansionOutcome( e.getMessage() == null ? e.getClass().getName() : e.getMessage(), TerminologyServiceErrorClass.NOSERVICE); } catch (Exception e) { return new ValueSetExpansionOutcome( e.getMessage() == null ? e.getClass().getName() : e.getMessage(), TerminologyServiceErrorClass.UNKNOWN); } }
private ValidationResult verifyCodeInternal(ValueSet vs, String code) throws FileNotFoundException, ETooCostly, IOException, FHIRException { if (vs.hasExpansion()) return verifyCodeInExpansion(vs, code); else { ValueSetExpansionOutcome vse = expansionCache.getExpander().expand(vs, null); if (vse.getValueset() == null) return new ValidationResult(IssueSeverity.ERROR, vse.getError(), vse.getErrorClass()); else return verifyCodeInExpansion(vse.getValueset(), code); } }
private ValidationResult verifyCodeInExpansion( ValueSet vs, String system, String code, String display) { ValueSetExpansionContainsComponent cc = findCode(vs.getExpansion().getContains(), code); if (cc == null) return new ValidationResult( IssueSeverity.ERROR, "Unknown Code " + code + " in " + vs.getUrl()); if (display == null) return new ValidationResult( new ConceptDefinitionComponent().setCode(code).setDisplay(cc.getDisplay())); if (cc.hasDisplay()) { if (display.equalsIgnoreCase(cc.getDisplay())) return new ValidationResult( new ConceptDefinitionComponent().setCode(code).setDisplay(cc.getDisplay())); return new ValidationResult( IssueSeverity.WARNING, "Display Name for " + code + " must be '" + cc.getDisplay() + "'", new ConceptDefinitionComponent().setCode(code).setDisplay(cc.getDisplay())); } return null; }
private ValidationResult verifyCodeInternal( ValueSet vs, String system, String code, String display) throws Exception { if (vs.hasExpansion()) return verifyCodeInExpansion(vs, system, code, display); else { ValueSetExpansionOutcome vse = expansionCache.getExpander().expand(vs, null); if (vse.getValueset() != null) return verifyCodeExternal( vs, new Coding().setSystem(system).setCode(code).setDisplay(display), false); else return verifyCodeInExpansion(vse.getValueset(), system, code, display); } }
private ValidationResult handleByCache(ValueSet vs, Coding coding, boolean tryCache) { String cacheId = cacheId(coding); Map<String, ValidationResult> cache = validationCache.get(vs.getUrl()); if (cache == null) { cache = new HashMap<String, IWorkerContext.ValidationResult>(); validationCache.put(vs.getUrl(), cache); } if (cache.containsKey(cacheId)) return cache.get(cacheId); if (!tryCache) return null; if (!cacheValidation) return null; if (failed.contains(vs.getUrl())) return null; ValueSetExpansionOutcome vse = expandVS(vs, true, false); if (vse.getValueset() == null || notcomplete(vse.getValueset())) { failed.add(vs.getUrl()); return null; } ValidationResult res = validateCode(coding, vse.getValueset()); cache.put(cacheId, res); return res; }
private ValidationResult verifyCodeExternal(ValueSet vs, CodeableConcept cc, boolean tryCache) throws Exception { ValidationResult res = handleByCache(vs, cc, tryCache); if (res != null) return res; Parameters pin = new Parameters(); pin.addParameter().setName("codeableConcept").setValue(cc); pin.addParameter().setName("valueSet").setResource(vs); res = serverValidateCode(pin, false); Map<String, ValidationResult> cache = validationCache.get(vs.getUrl()); cache.put(cacheId(cc), res); return res; }
private String determineCacheId(ValueSet vs, boolean heirarchical) throws Exception { // just the content logical definition is hashed ValueSet vsid = new ValueSet(); vsid.setCompose(vs.getCompose()); JsonParser parser = new JsonParser(); parser.setOutputStyle(OutputStyle.NORMAL); ByteArrayOutputStream b = new ByteArrayOutputStream(); parser.compose(b, vsid); b.close(); String s = new String(b.toByteArray(), Charsets.UTF_8); // any code systems we can find, we add these too. for (ConceptSetComponent inc : vs.getCompose().getInclude()) { CodeSystem cs = fetchCodeSystem(inc.getSystem()); if (cs != null) { String css = cacheValue(cs); s = s + css; } } s = s + "-" + Boolean.toString(heirarchical); String r = Integer.toString(s.hashCode()); // TextFile.stringToFile(s, Utilities.path(cache, r+".id.json")); return r; }
private ValidationResult verifyCodeExternal(ValueSet vs, Coding coding, boolean tryCache) throws Exception { ValidationResult res = vs == null ? null : handleByCache(vs, coding, tryCache); if (res != null) return res; Parameters pin = new Parameters(); pin.addParameter().setName("coding").setValue(coding); if (vs != null) pin.addParameter().setName("valueSet").setResource(vs); res = serverValidateCode(pin, vs == null); if (vs != null) { Map<String, ValidationResult> cache = validationCache.get(vs.getUrl()); cache.put(cacheId(coding), res); } return res; }
private ValueSetExpansionOutcome loadFromCache(ValueSet vs, String cacheFn) throws FileNotFoundException, Exception { JsonParser parser = new JsonParser(); Resource r = parser.parse(new FileInputStream(cacheFn)); if (r instanceof OperationOutcome) return new ValueSetExpansionOutcome( ((OperationOutcome) r).getIssue().get(0).getDetails().getText(), TerminologyServiceErrorClass.UNKNOWN); else { vs.setExpansion( ((ValueSet) r) .getExpansion()); // because what is cached might be from a different value set return new ValueSetExpansionOutcome(vs); } }
@Override public ValidationResult validateCode(String system, String code, String display, ValueSet vs) { try { if (system == null && display == null) return verifyCodeInternal(vs, code); if ((codeSystems.containsKey(system) && codeSystems.get(system) != null) || vs.hasExpansion()) return verifyCodeInternal(vs, system, code, display); else return verifyCodeExternal( vs, new Coding().setSystem(system).setCode(code).setDisplay(display), true); } catch (Exception e) { return new ValidationResult( IssueSeverity.FATAL, "Error validating code \"" + code + "\" in system \"" + system + "\": " + e.getMessage(), TerminologyServiceErrorClass.SERVER_ERROR); } }
@Override public ValidationResult validateCode(Coding code, ValueSet vs) { if (codeSystems.containsKey(code.getSystem()) && codeSystems.get(code.getSystem()) != null) try { return verifyCodeInCodeSystem( codeSystems.get(code.getSystem()), code.getSystem(), code.getCode(), code.getDisplay()); } catch (Exception e) { return new ValidationResult( IssueSeverity.FATAL, "Error validating code \"" + code + "\" in system \"" + code.getSystem() + "\": " + e.getMessage()); } else if (vs.hasExpansion()) try { return verifyCodeInternal(vs, code.getSystem(), code.getCode(), code.getDisplay()); } catch (Exception e) { return new ValidationResult( IssueSeverity.FATAL, "Error validating code \"" + code + "\" in system \"" + code.getSystem() + "\": " + e.getMessage()); } else try { return verifyCodeExternal(vs, code, true); } catch (Exception e) { return new ValidationResult( IssueSeverity.WARNING, "Error validating code \"" + code + "\" in system \"" + code.getSystem() + "\": " + e.getMessage()); } }
public ValueSetExpansionOutcome expandOnServer(ValueSet vs, String fn) throws Exception { if (noTerminologyServer) return new ValueSetExpansionOutcome( "Error expanding ValueSet: running without terminology services", TerminologyServiceErrorClass.NOSERVICE); if (expProfile == null) throw new Exception("No ExpansionProfile provided"); try { Map<String, String> params = new HashMap<String, String>(); params.put("_limit", Integer.toString(expandCodesLimit)); params.put("_incomplete", "true"); log("Terminology Server: $expand on " + getVSSummary(vs)); ValueSet result = txServer.expandValueset(vs, expProfile.setIncludeDefinition(false), params); return new ValueSetExpansionOutcome(result); } catch (Exception e) { return new ValueSetExpansionOutcome( "Error expanding ValueSet \"" + vs.getUrl() + ": " + e.getMessage(), TerminologyServiceErrorClass.UNKNOWN); } }
private String gen(Section section, CodeSystem cs, ValueSet vs) { String bn = getPNameForUri(cs.getUrl()); if (!bn.startsWith("<")) { section.triple(bn + ".system", "a", "fhir:CodeSystem"); if (cs.hasVersion()) section.triple(bn + ".system", "fhir:version", literal(cs.getVersion())); if (vs.hasName()) section.label(bn + ".system", vs.getName()); if (vs.hasDescription()) section.comment( bn + ".system", vs.getDescription() .replace("value set", "code system") .replace("Value Set", "Code System") .replace("Value set", "Code system")); if (vs.hasCopyright()) section.triple(bn + ".system", "dc:rights", literal(vs.getCopyright())); if (vs.hasDate()) section.triple(bn + ".system", "dc:date", literal(vs.getDate().toString())); section.triple(bn, "a", "fhir:Concept"); gen(section, bn, bn, cs.getConcept()); } return bn; }
@Override public ValueSet expand(ValueSet source, String theFilter) { ValueSet toExpand = new ValueSet(); for (UriType next : source.getCompose().getImport()) { ConceptSetComponent include = toExpand.getCompose().addInclude(); include.setSystem(next.getValue()); addFilterIfPresent(theFilter, include); } for (ConceptSetComponent next : source.getCompose().getInclude()) { toExpand.getCompose().addInclude(next); addFilterIfPresent(theFilter, next); } if (toExpand.getCompose().isEmpty()) { throw new InvalidRequestException( "ValueSet does not have any compose.include or compose.import values, can not expand"); } toExpand.getCompose().getExclude().addAll(source.getCompose().getExclude()); ValueSet retVal = doExpand(toExpand); return retVal; }
@Override public ValidationResult validateCode(CodeableConcept code, ValueSet vs) { try { if (vs.hasExpansion()) return verifyCodeInternal(vs, code); else { // we'll try expanding first; if that doesn't work, then we'll just pass it to the server to // validate // ... could be a problem if the server doesn't have the code systems we have locally, so we // try not to depend on the server try { ValueSetExpansionOutcome vse = expandVS(vs, true, false); if (vse.getValueset() != null) return verifyCodeInternal(vse.getValueset(), code); } catch (Exception e) { // failed? we'll just try the server } return verifyCodeExternal(vs, code, true); } } catch (Exception e) { return new ValidationResult( IssueSeverity.FATAL, "Error validating code \"" + code.toString() + "\": " + e.getMessage(), TerminologyServiceErrorClass.SERVER_ERROR); } }
private void gen(String bn, ValueSet vs) throws FHIRException { Section section = section(bn); section.triple(bn, "a", "fhir:ValueSet"); if (vs.hasVersion()) section.triple(bn, "fhir:version", literal(vs.getVersion())); if (vs.hasName()) section.label(bn, vs.getName()); if (vs.hasDescription()) section.comment( bn, vs.getDescription() .replace("code system", "value set") .replace("Code System", "Value Set") .replace("Code system", "Value set")); if (vs.hasCopyright()) section.triple(bn, "dc:rights", literal(vs.getCopyright())); if (vs.hasDate()) section.triple(bn, "dc:date", literal(vs.getDateElement().asStringValue())); for (UsageContext cc : vs.getUseContext()) codedTriple(section, bn, "fhir:useContext", cc.getValueCodeableConcept()); section.triple( bn, "fhir:status", complex().predicate("a", "fhir:conformance-resource-status\\#" + vs.getStatus().toCode())); section.triple( bn, "fhir:canonicalStatus", complex().predicate("a", getCanonicalStatus("ValueSet.status", vs.getStatus().toCode()))); }
@Override public ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.ValidateCodeResult validateCode( IPrimitiveType<String> theValueSetIdentifier, IIdType theId, IPrimitiveType<String> theCode, IPrimitiveType<String> theSystem, IPrimitiveType<String> theDisplay, Coding theCoding, CodeableConcept theCodeableConcept, RequestDetails theRequestDetails) { List<IIdType> valueSetIds = Collections.emptyList(); boolean haveCodeableConcept = theCodeableConcept != null && theCodeableConcept.getCoding().size() > 0; boolean haveCoding = theCoding != null && theCoding.isEmpty() == false; boolean haveCode = theCode != null && theCode.isEmpty() == false; if (!haveCodeableConcept && !haveCoding && !haveCode) { throw new InvalidRequestException("No code, coding, or codeableConcept provided to validate"); } if (!LogicUtil.multiXor(haveCodeableConcept, haveCoding, haveCode)) { throw new InvalidRequestException( "$validate-code can only validate (system AND code) OR (coding) OR (codeableConcept)"); } boolean haveIdentifierParam = theValueSetIdentifier != null && theValueSetIdentifier.isEmpty() == false; if (theId != null) { valueSetIds = Collections.singletonList(theId); } else if (haveIdentifierParam) { Set<Long> ids = searchForIds( ValueSet.SP_IDENTIFIER, new TokenParam(null, theValueSetIdentifier.getValue())); valueSetIds = new ArrayList<IIdType>(); for (Long next : ids) { valueSetIds.add(new IdType("ValueSet", next)); } } else { if (theCode == null || theCode.isEmpty()) { throw new InvalidRequestException( "Either ValueSet ID or ValueSet identifier or system and code must be provided. Unable to validate."); } // String code = theCode.getValue(); // String system = toStringOrNull(theSystem); LookupCodeResult result = myCodeSystemDao.lookupCode(theCode, theSystem, null, null); if (result.isFound()) { ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.ValidateCodeResult retVal = new ValidateCodeResult(true, "Found code", result.getCodeDisplay()); return retVal; } } // if (valueSetIds.isEmpty()) { // if (haveIdentifierParam) { // myValidationSupport.expandValueSet(getContext(), include); // if (myValidationSupport.isCodeSystemSupported(getContext(), // theValueSetIdentifier.getValue())) { // String system = toStringOrNull(theSystem); // String code = toStringOrNull(theCode); // String display = toStringOrNull(theDisplay); // CodeValidationResult result = myValidationSupport.validateCode(getContext(), system, // code, display); // if (result != null) { // if (theDisplay != null && isNotBlank(theDisplay.getValue()) && // isNotBlank(result.getDisplay())) { // if (!theDisplay.getValue().equals(result.getDisplay())) { // return new ValidateCodeResult(false, "Display for code does not match", // result.getDisplay()); // } // } // return new ValidateCodeResult(true, "Code validates", result.getDisplay()); // } // } // } // } for (IIdType nextId : valueSetIds) { ValueSet expansion = expand(nextId, null, theRequestDetails); List<ValueSetExpansionContainsComponent> contains = expansion.getExpansion().getContains(); ValidateCodeResult result = validateCodeIsInContains( contains, toStringOrNull(theSystem), toStringOrNull(theCode), theCoding, theCodeableConcept); if (result != null) { if (theDisplay != null && isNotBlank(theDisplay.getValue()) && isNotBlank(result.getDisplay())) { if (!theDisplay.getValue().equals(result.getDisplay())) { return new ValidateCodeResult( false, "Display for code does not match", result.getDisplay()); } } return result; } } return new ValidateCodeResult(false, "Code not found", null); }