Merge pull request #1545 from hapifhir/2024-01-gg-more-tx-work3
2024 01 gg more tx work3
This commit is contained in:
commit
79f3fbb93c
|
@ -1,7 +1,12 @@
|
|||
## Validator Changes
|
||||
|
||||
* Fix issues with multiple terminology servers (should be live soon)
|
||||
* Rework terminology system & cache to support new terminology server ecosystem
|
||||
* Handle value set with exclusion filters when expanding
|
||||
* Fix to consistent error messages when value sets can't be resolved
|
||||
|
||||
## Other code changes
|
||||
|
||||
* no changes
|
||||
* Fix bug processing empty structure maps
|
||||
* Performance improvements to common IO routines, with test cases - see https://blog.qligier.ch/posts/2024-improving-perf-ig-publisher-io/ (thanks to Quentin Ligier)
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ public class BOMRemover {
|
|||
String s = Utilities.stripBOM(src);
|
||||
if (!s.equals(src)) {
|
||||
System.out.println("Remove BOM from "+f.getAbsolutePath());
|
||||
TextFile.stringToFile(s, f, false);
|
||||
TextFile.stringToFile(s, f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import org.hl7.fhir.r5.terminologies.client.ITerminologyClient;
|
|||
import org.hl7.fhir.r5.terminologies.client.TerminologyClientManager.ITerminologyClientFactory;
|
||||
import org.hl7.fhir.r5.terminologies.client.TerminologyClientR5;
|
||||
import org.hl7.fhir.utilities.FhirPublication;
|
||||
import org.hl7.fhir.utilities.ToolingClientLogger;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.VersionUtilities;
|
||||
|
||||
|
@ -23,27 +24,28 @@ public class TerminologyClientFactory implements ITerminologyClientFactory {
|
|||
this.v = version;
|
||||
}
|
||||
|
||||
public ITerminologyClient makeClient(String id, String url, String userAgent) throws URISyntaxException {
|
||||
@Override
|
||||
public ITerminologyClient makeClient(String id, String url, String userAgent, ToolingClientLogger logger) throws URISyntaxException {
|
||||
if (v == null)
|
||||
return new TerminologyClientR5(id, checkEndsWith("/r4", url), userAgent);
|
||||
return new TerminologyClientR5(id, checkEndsWith("/r4", url), userAgent).setLogger(logger);
|
||||
v = VersionUtilities.getMajMin(v);
|
||||
if (VersionUtilities.isR2Ver(v)) {
|
||||
return new TerminologyClientR2(id, checkEndsWith("/r2", url), userAgent);
|
||||
return new TerminologyClientR2(id, checkEndsWith("/r2", url), userAgent).setLogger(logger);
|
||||
}
|
||||
if (VersionUtilities.isR2BVer(v)) {
|
||||
return new TerminologyClientR3(id, checkEndsWith("/r3", url), userAgent); // r3 is the least worst match
|
||||
return new TerminologyClientR3(id, checkEndsWith("/r3", url), userAgent).setLogger(logger); // r3 is the least worst match
|
||||
}
|
||||
if (VersionUtilities.isR3Ver(v)) {
|
||||
return new TerminologyClientR3(id, checkEndsWith("/r3", url), userAgent); // r3 is the least worst match
|
||||
return new TerminologyClientR3(id, checkEndsWith("/r3", url), userAgent).setLogger(logger); // r3 is the least worst match
|
||||
}
|
||||
if (VersionUtilities.isR4Ver(v)) {
|
||||
return new TerminologyClientR4(id, checkEndsWith("/r4", url), userAgent);
|
||||
return new TerminologyClientR4(id, checkEndsWith("/r4", url), userAgent).setLogger(logger);
|
||||
}
|
||||
if (VersionUtilities.isR4BVer(v)) {
|
||||
return new TerminologyClientR4(id, checkEndsWith("/r4", url), userAgent);
|
||||
return new TerminologyClientR4(id, checkEndsWith("/r4", url), userAgent).setLogger(logger);
|
||||
}
|
||||
if (VersionUtilities.isR5Plus(v)) {
|
||||
return new TerminologyClientR5(id, checkEndsWith("/r4", url), userAgent); // r4 for now, since the terminology is currently the same
|
||||
return new TerminologyClientR5(id, checkEndsWith("/r4", url), userAgent).setLogger(logger); // r4 for now, since the terminology is currently the same
|
||||
}
|
||||
throw new Error("The version " + v + " is not currently supported");
|
||||
}
|
||||
|
|
|
@ -131,6 +131,11 @@ public class TerminologyClientR2 implements ITerminologyClient {
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ToolingClientLogger getLogger() {
|
||||
return client.getLogger();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITerminologyClient setLogger(ToolingClientLogger txLog) {
|
||||
client.setLogger(txLog);
|
||||
|
@ -227,4 +232,10 @@ public class TerminologyClientR2 implements ITerminologyClient {
|
|||
public int getUseCount() {
|
||||
return client.getUseCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bundle search(String type, String criteria) {
|
||||
org.hl7.fhir.dstu2.model.Bundle result = client.search(type, criteria);
|
||||
return result == null ? null : (Bundle) VersionConvertorFactory_10_50.convertResource(result);
|
||||
}
|
||||
}
|
|
@ -127,6 +127,11 @@ public class TerminologyClientR3 implements ITerminologyClient {
|
|||
client.setTimeoutFactor(i);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ToolingClientLogger getLogger() {
|
||||
return client.getLogger();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITerminologyClient setLogger(ToolingClientLogger txLog) {
|
||||
|
@ -230,4 +235,11 @@ public class TerminologyClientR3 implements ITerminologyClient {
|
|||
return client.getUseCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bundle search(String type, String criteria) {
|
||||
org.hl7.fhir.dstu3.model.Bundle result = client.search(type, criteria);
|
||||
return result == null ? null : (Bundle) VersionConvertorFactory_30_50.convertResource(result);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -138,6 +138,11 @@ public class TerminologyClientR4 implements ITerminologyClient {
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ToolingClientLogger getLogger() {
|
||||
return client.getLogger();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITerminologyClient setLogger(ToolingClientLogger txLog) {
|
||||
client.setLogger(txLog);
|
||||
|
@ -242,5 +247,11 @@ public class TerminologyClientR4 implements ITerminologyClient {
|
|||
return client.getUseCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bundle search(String type, String criteria) {
|
||||
org.hl7.fhir.r4.model.Bundle result = client.search(type, criteria);
|
||||
return result == null ? null : (Bundle) VersionConvertorFactory_40_50.convertResource(result);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -53,14 +53,14 @@ public class TerminologyClientFactoryTest {
|
|||
@ParameterizedTest
|
||||
@MethodSource("data")
|
||||
public void testMakeClient(String url, FhirPublication fhirPublication, String expectedAddress) throws URISyntaxException {
|
||||
ITerminologyClient terminologyClient = new TerminologyClientFactory(fhirPublication).makeClient("id", url, "dummyUserAgent");
|
||||
ITerminologyClient terminologyClient = new TerminologyClientFactory(fhirPublication).makeClient("id", url, "dummyUserAgent", null);
|
||||
assertEquals(expectedAddress, terminologyClient.getAddress());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMakeClientDstu1Fails() throws URISyntaxException {
|
||||
assertThrows(Error.class, () -> {
|
||||
ITerminologyClient terminologyClient = new TerminologyClientFactory(FhirPublication.DSTU1).makeClient("id", "urldoesnotmatter", "dummyUserAgent");
|
||||
ITerminologyClient terminologyClient = new TerminologyClientFactory(FhirPublication.DSTU1).makeClient("id", "urldoesnotmatter", "dummyUserAgent", null);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ public class TerminologyClientFactoryTest {
|
|||
@Test
|
||||
public void testMakeClientNullFails() throws URISyntaxException {
|
||||
assertThrows(Error.class, () -> {
|
||||
ITerminologyClient terminologyClient = new TerminologyClientFactory(FhirPublication.NULL).makeClient("id", "urldoesnotmatter", "dummyUserAgent");
|
||||
ITerminologyClient terminologyClient = new TerminologyClientFactory(FhirPublication.NULL).makeClient("id", "urldoesnotmatter", "dummyUserAgent", null);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -924,5 +924,10 @@ public class FHIRToolingClient extends FHIRBaseToolingClient {
|
|||
private void recordUse() {
|
||||
useCount++;
|
||||
}
|
||||
|
||||
|
||||
public Bundle search(String type, String criteria) {
|
||||
recordUse();
|
||||
return fetchFeed(Utilities.pathURL(base, type+criteria));
|
||||
}
|
||||
|
||||
}
|
|
@ -654,5 +654,10 @@ public class FHIRToolingClient extends FHIRBaseToolingClient {
|
|||
useCount++;
|
||||
}
|
||||
|
||||
public Bundle search(String type, String criteria) {
|
||||
recordUse();
|
||||
return fetchFeed(Utilities.pathURL(base, type+criteria));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -372,7 +372,9 @@ public class FhirRequestBuilder {
|
|||
headerMap.keySet().forEach(key -> headerMap.get(key).forEach(value -> headerList.add(key + ":" + value)));
|
||||
|
||||
try {
|
||||
logger.logResponse(Integer.toString(responseCode), headerList, responseBody);
|
||||
if (logger != null) {
|
||||
logger.logResponse(Integer.toString(responseCode), headerList, responseBody);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println("Error parsing response body passed in to logger ->\n" + e.getLocalizedMessage());
|
||||
}
|
||||
|
|
|
@ -87,7 +87,7 @@ public class TerminologyClientR4 implements TerminologyClient {
|
|||
|
||||
@Override
|
||||
public void setTimeout(int i) {
|
||||
client.setTimeoutNormal(i); // #FIXME
|
||||
client.setTimeoutNormal(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -43,7 +43,9 @@ public class FhirLoggingInterceptor implements Interceptor {
|
|||
request.body().writeTo(buf);
|
||||
cnt = buf.readByteArray();
|
||||
}
|
||||
logger.logRequest(request.method(), request.url().toString(), hdrs, cnt);
|
||||
if (logger != null) {
|
||||
logger.logRequest(request.method(), request.url().toString(), hdrs, cnt);
|
||||
}
|
||||
|
||||
// Log Response
|
||||
Response response = null;
|
||||
|
@ -61,7 +63,9 @@ public class FhirLoggingInterceptor implements Interceptor {
|
|||
Map<String, List<String>> headerMap = response.headers().toMultimap();
|
||||
headerMap.keySet().forEach(key -> headerMap.get(key).forEach(value -> headerList.add(key + ":" + value)));
|
||||
|
||||
logger.logResponse(Integer.toString(response.code()), headerList, bodyBytes);
|
||||
if (logger != null) {
|
||||
logger.logResponse(Integer.toString(response.code()), headerList, bodyBytes);
|
||||
}
|
||||
|
||||
// Reading byte[] clears body. Need to recreate.
|
||||
ResponseBody body = ResponseBody.create(bodyBytes, contentType);
|
||||
|
|
|
@ -25,8 +25,10 @@ import org.hl7.fhir.utilities.settings.FhirSettings;
|
|||
import okhttp3.Authenticator;
|
||||
import okhttp3.Credentials;
|
||||
import okhttp3.Headers;
|
||||
import okhttp3.Headers.Builder;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.Response;
|
||||
|
||||
public class FhirRequestBuilder {
|
||||
|
@ -259,10 +261,11 @@ public class FhirRequestBuilder {
|
|||
protected <T extends Resource> T unmarshalReference(Response response, String format) {
|
||||
T resource = null;
|
||||
OperationOutcome error = null;
|
||||
|
||||
byte[] body = null;
|
||||
|
||||
if (response.body() != null) {
|
||||
try {
|
||||
byte[] body = response.body().bytes();
|
||||
body = response.body().bytes();
|
||||
resource = (T) getParser(format).parse(body);
|
||||
if (resource instanceof OperationOutcome && hasError((OperationOutcome) resource)) {
|
||||
error = (OperationOutcome) resource;
|
||||
|
@ -276,13 +279,14 @@ public class FhirRequestBuilder {
|
|||
|
||||
if (error != null) {
|
||||
String s = ResourceUtilities.getErrorDescription(error);
|
||||
System.out.println(s);
|
||||
System.out.println("Error from "+source+": " + s);
|
||||
throw new EFhirClientException("Error from "+source+": " + ResourceUtilities.getErrorDescription(error), error);
|
||||
}
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Unmarshalls Bundle from response stream.
|
||||
*/
|
||||
|
@ -291,6 +295,7 @@ public class FhirRequestBuilder {
|
|||
OperationOutcome error = null;
|
||||
try {
|
||||
byte[] body = response.body().bytes();
|
||||
TextFile.bytesToFile(body, "/Users/grahamegrieve/temp/http-body.txt");
|
||||
String contentType = response.header("Content-Type");
|
||||
if (body != null) {
|
||||
if (contentType.contains(ResourceFormat.RESOURCE_XML.getHeader())
|
||||
|
|
|
@ -127,7 +127,7 @@ public abstract class ParserBase {
|
|||
public abstract void compose(Element e, OutputStream destination, OutputStyle style, String base)
|
||||
throws FHIRException, IOException;
|
||||
|
||||
// FIXME: i18n should be done here
|
||||
// TODO: i18n should be done here ?
|
||||
public void logError(int line, int col, String path, IssueType type, String message, IssueSeverity level)
|
||||
throws FHIRFormatError {
|
||||
if (errors != null) {
|
||||
|
|
|
@ -153,7 +153,7 @@ public class ValueSetCheckerSimple extends ValueSetWorker implements ValueSetChe
|
|||
}
|
||||
}
|
||||
if (result == null) {
|
||||
warnings.add(0, context.formatMessage(I18nConstants.UNABLE_TO_CHECK_IF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_,
|
||||
warnings.add(0, context.formatMessage(I18nConstants.UNABLE_TO_CHECK_IF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_CS,
|
||||
valueset.getUrl(), b.toString()));
|
||||
} else if (!result) {
|
||||
errors.add(0, context.formatMessagePlural(code.getCoding().size(),
|
||||
|
|
|
@ -110,7 +110,7 @@ public class TestingUtilities extends BaseTestingUtilities {
|
|||
if (!Utilities.noString(s))
|
||||
return s;
|
||||
s = "C:\\work\\org.hl7.fhir\\build";
|
||||
// FIXME: change this back
|
||||
// #TODO - what should we do with this?
|
||||
s = "/Users/jamesagnew/git/fhir";
|
||||
if (new File(s).exists())
|
||||
return s;
|
||||
|
|
|
@ -236,10 +236,6 @@ public interface IResourceValidator {
|
|||
|
||||
public void setWantCheckSnapshotUnchanged(boolean wantCheckSnapshotUnchanged);
|
||||
|
||||
// FIXME: don't need that, gets never used?
|
||||
// public String getValidationLanguage();
|
||||
// public void setValidationLanguage(String value);
|
||||
|
||||
/**
|
||||
* It's common to see references such as Patient/234234 - these usually mean a
|
||||
* reference to a Patient resource. But there's no actual technical rule that it
|
||||
|
|
|
@ -364,11 +364,11 @@ public class NPMPackageGenerator {
|
|||
// also, for cache management on current builds, generate a little manifest
|
||||
Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
||||
String json = gson.toJson(packageManifest);
|
||||
TextFile.stringToFile(json, Utilities.changeFileExt(destFile, ".manifest.json"), false);
|
||||
TextFile.stringToFile(json, Utilities.changeFileExt(destFile, ".manifest.json"));
|
||||
}
|
||||
|
||||
private void buildIndexJson() throws IOException {
|
||||
byte[] content = TextFile.stringToBytes(indexer.build(), false);
|
||||
byte[] content = TextFile.stringToBytes(indexer.build());
|
||||
addFile(Category.RESOURCE, ".index.json", content);
|
||||
content = TextFile.fileToBytes(indexdb);
|
||||
new File(indexdb).delete();
|
||||
|
|
|
@ -38,8 +38,10 @@ public class FhirLoggingInterceptor implements Interceptor {
|
|||
request.body().writeTo(buf);
|
||||
cnt = buf.readByteArray();
|
||||
}
|
||||
logger.logRequest(request.method(), request.url().toString(), hdrs, cnt);
|
||||
|
||||
if (logger != null) {
|
||||
logger.logRequest(request.method(), request.url().toString(), hdrs, cnt);
|
||||
}
|
||||
|
||||
// Log Response
|
||||
Response response = null;
|
||||
response = chain.proceed(chain.request());
|
||||
|
@ -56,7 +58,9 @@ public class FhirLoggingInterceptor implements Interceptor {
|
|||
Map<String, List<String>> headerMap = response.headers().toMultimap();
|
||||
headerMap.keySet().forEach(key -> headerMap.get(key).forEach(value -> headerList.add(key + ":" + value)));
|
||||
|
||||
logger.logResponse(Integer.toString(response.code()), headerList, bodyBytes);
|
||||
if (logger != null) {
|
||||
logger.logResponse(Integer.toString(response.code()), headerList, bodyBytes);
|
||||
}
|
||||
|
||||
// Reading byte[] clears body. Need to recreate.
|
||||
ResponseBody body = ResponseBody.create(bodyBytes, contentType);
|
||||
|
|
|
@ -10,4 +10,6 @@ public class BindingResolution {
|
|||
}
|
||||
public String display;
|
||||
public String url;
|
||||
public String uri;
|
||||
public boolean external;
|
||||
}
|
|
@ -2722,8 +2722,8 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+derived.getPath(), "illegal attempt to change the binding on "+derived.getPath()+" from "+base.getBinding().getStrength().toCode()+" to "+derived.getBinding().getStrength().toCode(), ValidationMessage.IssueSeverity.ERROR));
|
||||
// throw new DefinitionException("StructureDefinition "+pn+" at "+derived.getPath()+": illegal attempt to change a binding from "+base.getBinding().getStrength().toCode()+" to "+derived.getBinding().getStrength().toCode());
|
||||
else if (base.hasBinding() && derived.hasBinding() && base.getBinding().getStrength() == BindingStrength.REQUIRED && base.getBinding().hasValueSet() && derived.getBinding().hasValueSet()) {
|
||||
ValueSet baseVs = context.fetchResource(ValueSet.class, base.getBinding().getValueSet(), srcSD);
|
||||
ValueSet contextVs = context.fetchResource(ValueSet.class, derived.getBinding().getValueSet(), derivedSrc);
|
||||
ValueSet baseVs = context.findTxResource(ValueSet.class, base.getBinding().getValueSet(), srcSD);
|
||||
ValueSet contextVs = context.findTxResource(ValueSet.class, derived.getBinding().getValueSet(), derivedSrc);
|
||||
if (baseVs == null) {
|
||||
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+base.getPath(), "Binding "+base.getBinding().getValueSet()+" could not be located", ValidationMessage.IssueSeverity.WARNING));
|
||||
} else if (contextVs == null) {
|
||||
|
|
|
@ -48,6 +48,7 @@ import java.util.List;
|
|||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
@ -124,6 +125,7 @@ import org.hl7.fhir.r5.terminologies.utilities.TerminologyOperationContext.Termi
|
|||
import org.hl7.fhir.r5.terminologies.utilities.TerminologyServiceErrorClass;
|
||||
import org.hl7.fhir.r5.terminologies.utilities.ValidationResult;
|
||||
import org.hl7.fhir.r5.terminologies.utilities.TerminologyCache.CacheToken;
|
||||
import org.hl7.fhir.r5.terminologies.utilities.TerminologyCache.SourcedValueSet;
|
||||
import org.hl7.fhir.r5.terminologies.validation.VSCheckerException;
|
||||
import org.hl7.fhir.r5.terminologies.validation.ValueSetValidator;
|
||||
import org.hl7.fhir.r5.terminologies.ValueSetUtilities;
|
||||
|
@ -136,6 +138,7 @@ import org.hl7.fhir.r5.utils.ToolingExtensions;
|
|||
import org.hl7.fhir.r5.utils.client.EFhirClientException;
|
||||
import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier;
|
||||
import org.hl7.fhir.utilities.FhirPublication;
|
||||
import org.hl7.fhir.utilities.TextFile;
|
||||
import org.hl7.fhir.utilities.TimeTracker;
|
||||
import org.hl7.fhir.utilities.ToolingClientLogger;
|
||||
import org.hl7.fhir.utilities.TranslationServices;
|
||||
|
@ -231,7 +234,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
private Object lock = new Object(); // used as a lock for the data that follows
|
||||
protected String version; // although the internal resources are all R5, the version of FHIR they describe may not be
|
||||
|
||||
protected TerminologyClientManager terminologyClientManager = new TerminologyClientManager(null);
|
||||
protected final TerminologyClientManager terminologyClientManager = new TerminologyClientManager(null, UUID.randomUUID().toString());
|
||||
private boolean minimalMemory = false;
|
||||
|
||||
private Map<String, Map<String, ResourceProxy>> allResourcesById = new HashMap<String, Map<String, ResourceProxy>>();
|
||||
|
@ -269,7 +272,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
|
||||
private final Set<String> codeSystemsUsed = new HashSet<>();
|
||||
protected ToolingClientLogger txLog;
|
||||
private boolean canRunWithoutTerminology;
|
||||
protected boolean canRunWithoutTerminology;
|
||||
protected boolean noTerminologyServer;
|
||||
private int expandCodesLimit = 1000;
|
||||
protected ILoggingService logger = new SystemOutLoggingService();
|
||||
|
@ -278,7 +281,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
private Map<String, PackageInformation> packages = new HashMap<>();
|
||||
|
||||
@Getter
|
||||
protected TerminologyCache txCache;
|
||||
protected TerminologyCache txCache = new TerminologyCache(this, null);
|
||||
protected TimeTracker clock;
|
||||
private boolean tlogging = true;
|
||||
private IWorkerContextManager.ICanonicalResourceLocator locator;
|
||||
|
@ -774,12 +777,11 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
if (noTerminologyServer) {
|
||||
return false;
|
||||
}
|
||||
if (terminologyClientManager.getTxCapabilities() == null) {
|
||||
if (terminologyClientManager != null) {
|
||||
try {
|
||||
logger.logMessage("Terminology server: Check for supported code systems for "+system);
|
||||
final TerminologyCapabilities capabilityStatement = txCache.hasTerminologyCapabilities() ? txCache.getTerminologyCapabilities() : terminologyClientManager.getMasterClient().getTerminologyCapabilities();
|
||||
txCache.cacheTerminologyCapabilities(capabilityStatement);
|
||||
setTxCaps(capabilityStatement);
|
||||
if (terminologyClientManager.supportsSystem(system)) {
|
||||
supportedCodeSystems.add(system);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (canRunWithoutTerminology) {
|
||||
noTerminologyServer = true;
|
||||
|
@ -851,7 +853,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
Set<String> systems = findRelevantSystems(vs);
|
||||
TerminologyClientContext tc = terminologyClientManager.chooseServer(systems, true);
|
||||
if (tc == null) {
|
||||
res = new ValueSetExpansionOutcome("No server available", TerminologyServiceErrorClass.INTERNAL_ERROR, true);
|
||||
return new ValueSetExpansionOutcome("No server available", TerminologyServiceErrorClass.INTERNAL_ERROR, true);
|
||||
}
|
||||
Parameters p = constructParameters(tc, vs, hierarchical);
|
||||
for (ConceptSetComponent incl : vs.getCompose().getInclude()) {
|
||||
|
@ -1373,15 +1375,15 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
}
|
||||
|
||||
protected ValueSetExpander constructValueSetExpanderSimple(ValidationOptions options) {
|
||||
return new ValueSetExpander(this, new TerminologyOperationContext(this, options));
|
||||
return new ValueSetExpander(this, new TerminologyOperationContext(this, options)).setDebug(logger.isDebugLogging());
|
||||
}
|
||||
|
||||
protected ValueSetValidator constructValueSetCheckerSimple(ValidationOptions options, ValueSet vs, ValidationContextCarrier ctxt) {
|
||||
return new ValueSetValidator(this, new TerminologyOperationContext(this, options), options, vs, ctxt, expParameters, terminologyClientManager.getTxCapabilities());
|
||||
return new ValueSetValidator(this, new TerminologyOperationContext(this, options), options, vs, ctxt, expParameters, terminologyClientManager);
|
||||
}
|
||||
|
||||
protected ValueSetValidator constructValueSetCheckerSimple( ValidationOptions options, ValueSet vs) {
|
||||
return new ValueSetValidator(this, new TerminologyOperationContext(this, options), options, vs, expParameters, terminologyClientManager.getTxCapabilities());
|
||||
return new ValueSetValidator(this, new TerminologyOperationContext(this, options), options, vs, expParameters, terminologyClientManager);
|
||||
}
|
||||
|
||||
protected Parameters constructParameters(TerminologyClientContext tcd, ValueSet vs, boolean hierarchical) {
|
||||
|
@ -1645,8 +1647,11 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
protected void addServerValidationParameters(TerminologyClientContext terminologyClientContext, ValueSet vs, Parameters pin, ValidationOptions options) {
|
||||
boolean cache = false;
|
||||
if (vs != null) {
|
||||
if (terminologyClientManager.isTxCaching() && terminologyClientManager.getCacheId() != null && vs.getUrl() != null && terminologyClientContext.getCached().contains(vs.getUrl()+"|"+ vs.getVersion())) {
|
||||
pin.addParameter().setName("url").setValue(new UriType(vs.getUrl()+(vs.hasVersion() ? "|"+ vs.getVersion() : "")));
|
||||
if (terminologyClientContext != null && terminologyClientContext.isTxCaching() && terminologyClientContext.getCacheId() != null && vs.getUrl() != null && terminologyClientContext.getCached().contains(vs.getUrl()+"|"+ vs.getVersion())) {
|
||||
pin.addParameter().setName("url").setValue(new UriType(vs.getUrl()));
|
||||
if (vs.hasVersion()) {
|
||||
pin.addParameter().setName("valueSetVersion").setValue(new StringType(vs.getVersion()));
|
||||
}
|
||||
} else if (options.getVsAsUrl()){
|
||||
pin.addParameter().setName("url").setValue(new UriType(vs.getUrl()));
|
||||
} else {
|
||||
|
@ -1705,7 +1710,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
private boolean checkAddToParams(TerminologyClientContext tc, Parameters pin, CanonicalResource cr) {
|
||||
boolean cache = false;
|
||||
boolean addToParams = false;
|
||||
if (terminologyClientManager.usingCache()) {
|
||||
if (tc.usingCache()) {
|
||||
if (!tc.alreadyCached(cr)) {
|
||||
tc.addToCache(cr);
|
||||
if (logger.isDebugLogging()) {
|
||||
|
@ -1856,11 +1861,15 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
return "item";
|
||||
}
|
||||
|
||||
protected void initTS(String cachePath) throws IOException {
|
||||
if (cachePath != null && !new File(cachePath).exists()) {
|
||||
Utilities.createDirectory(cachePath);
|
||||
public void initTxCache(String cachePath) throws FileNotFoundException, FHIRException, IOException {
|
||||
if (cachePath != null) {
|
||||
txCache = new TerminologyCache(lock, cachePath);
|
||||
initTxCache(txCache);
|
||||
}
|
||||
txCache = new TerminologyCache(lock, cachePath);
|
||||
}
|
||||
|
||||
public void initTxCache(TerminologyCache cache) {
|
||||
txCache = cache;
|
||||
terminologyClientManager.setCache(txCache);
|
||||
}
|
||||
|
||||
|
@ -1868,10 +1877,6 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
txCache.removeCS(url);
|
||||
}
|
||||
|
||||
public void clearTS() {
|
||||
txCache.clear();
|
||||
}
|
||||
|
||||
public boolean isCanRunWithoutTerminology() {
|
||||
return canRunWithoutTerminology;
|
||||
}
|
||||
|
@ -2024,6 +2029,9 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
if (codeSystems.has(uri)) {
|
||||
return (T) codeSystems.get(uri, version, pvlist);
|
||||
}
|
||||
if (systems.has(uri)) {
|
||||
return (T) systems.get(uri, version, pvlist);
|
||||
}
|
||||
if (operations.has(uri)) {
|
||||
return (T) operations.get(uri, version, pvlist);
|
||||
}
|
||||
|
@ -2082,6 +2090,8 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
return (T) structures.get(uri, version, pvlist);
|
||||
} else if (class_ == StructureMap.class) {
|
||||
return (T) transforms.get(uri, version, pvlist);
|
||||
} else if (class_ == NamingSystem.class) {
|
||||
return (T) systems.get(uri, version, pvlist);
|
||||
} else if (class_ == ValueSet.class) {
|
||||
return (T) valueSets.get(uri, version, pvlist);
|
||||
} else if (class_ == CodeSystem.class) {
|
||||
|
@ -2988,33 +2998,10 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
return terminologyClientManager.getCacheId();
|
||||
}
|
||||
|
||||
public void setCacheId(String cacheId) {
|
||||
terminologyClientManager.setCacheId(cacheId);
|
||||
}
|
||||
|
||||
public TerminologyCapabilities getTxCaps() {
|
||||
return terminologyClientManager.getTxCapabilities();
|
||||
}
|
||||
|
||||
public void setTxCaps(TerminologyCapabilities txCaps) {
|
||||
this.terminologyClientManager.setTxCapabilities(txCaps);
|
||||
if (txCaps != null) {
|
||||
for (TerminologyCapabilitiesExpansionParameterComponent t : terminologyClientManager.getTxCapabilities().getExpansion().getParameter()) {
|
||||
if ("cache-id".equals(t.getName())) {
|
||||
terminologyClientManager.setTxCaching(true);
|
||||
}
|
||||
}
|
||||
for (TerminologyCapabilitiesCodeSystemComponent tccs : terminologyClientManager.getTxCapabilities().getCodeSystem()) {
|
||||
supportedCodeSystems.add(tccs.getUri());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public TimeTracker clock() {
|
||||
return clock;
|
||||
}
|
||||
|
||||
|
||||
public int countAllCaches() {
|
||||
return codeSystems.size() + valueSets.size() + maps.size() + transforms.size() + structures.size() + measures.size() + libraries.size() +
|
||||
guides.size() + capstmts.size() + searchParameters.size() + questionnaires.size() + operations.size() + plans.size() +
|
||||
|
@ -3165,7 +3152,69 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
|
||||
binaries.clear();
|
||||
validationCache.clear();
|
||||
txCache.clear();
|
||||
txCache.unload();
|
||||
}
|
||||
|
||||
private <T extends Resource> T doFindTxResource(Class<T> class_, String canonical) {
|
||||
// well, we haven't found it locally. We're going look it up
|
||||
if (class_ == ValueSet.class) {
|
||||
SourcedValueSet svs = null;
|
||||
if (txCache.hasValueSet(canonical)) {
|
||||
svs = txCache.getValueSet(canonical);
|
||||
} else {
|
||||
svs = terminologyClientManager.findValueSetOnServer(canonical);
|
||||
txCache.cacheValueSet(canonical, svs);
|
||||
}
|
||||
if (svs != null) {
|
||||
String web = ToolingExtensions.readStringExtension(svs.getVs(), ToolingExtensions.EXT_WEB_SOURCE);
|
||||
if (web == null) {
|
||||
web = Utilities.pathURL(svs.getServer(), "ValueSet", svs.getVs().getIdBase());
|
||||
}
|
||||
svs.getVs().setWebPath(web);
|
||||
svs.getVs().setUserData("External.Link", svs.getServer()); // so we can render it differently
|
||||
}
|
||||
if (svs == null) {
|
||||
return null;
|
||||
} else {
|
||||
cacheResource(svs.getVs());
|
||||
return (T) svs.getVs();
|
||||
}
|
||||
} else {
|
||||
throw new Error("Not supported");
|
||||
}
|
||||
}
|
||||
|
||||
public <T extends Resource> T findTxResource(Class<T> class_, String canonical, Resource sourceOfReference) {
|
||||
if (canonical == null) {
|
||||
return null;
|
||||
}
|
||||
T result = fetchResource(class_, canonical, sourceOfReference);
|
||||
if (result == null) {
|
||||
result = doFindTxResource(class_, canonical);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public <T extends Resource> T findTxResource(Class<T> class_, String canonical) {
|
||||
if (canonical == null) {
|
||||
return null;
|
||||
}
|
||||
T result = fetchResource(class_, canonical);
|
||||
if (result == null) {
|
||||
result = doFindTxResource(class_, canonical);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public <T extends Resource> T findTxResource(Class<T> class_, String canonical, String version) {
|
||||
if (canonical == null) {
|
||||
return null;
|
||||
}
|
||||
T result = fetchResource(class_, canonical, version);
|
||||
if (result == null) {
|
||||
result = doFindTxResource(class_, canonical+"|"+version);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -627,4 +627,17 @@ public interface IWorkerContext {
|
|||
|
||||
public Set<String> urlsForOid(boolean codeSystem, String oid);
|
||||
|
||||
/**
|
||||
* this first does a fetch resource, and if nothing is found, looks in the
|
||||
* terminology eco-system for a matching definition for the resource
|
||||
*
|
||||
* usually used (and so far only tested with) ValueSet.class
|
||||
*
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public <T extends Resource> T findTxResource(Class<T> class_, String canonical, Resource sourceOfReference);
|
||||
public <T extends Resource> T findTxResource(Class<T> class_, String canonical);
|
||||
public <T extends Resource> T findTxResource(Class<T> class_, String canonical, String version);
|
||||
|
||||
}
|
|
@ -41,6 +41,7 @@ import java.util.List;
|
|||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
|
@ -51,6 +52,7 @@ import org.apache.commons.io.IOUtils;
|
|||
import org.hl7.fhir.exceptions.DefinitionException;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.FHIRFormatError;
|
||||
import org.hl7.fhir.exceptions.TerminologyServiceException;
|
||||
import org.hl7.fhir.r5.context.CanonicalResourceManager.CanonicalResourceProxy;
|
||||
import org.hl7.fhir.r5.context.ILoggingService.LogCategory;
|
||||
import org.hl7.fhir.r5.formats.IParser;
|
||||
|
@ -64,6 +66,7 @@ import org.hl7.fhir.r5.model.StructureMap.StructureMapModelMode;
|
|||
import org.hl7.fhir.r5.model.StructureMap.StructureMapStructureComponent;
|
||||
import org.hl7.fhir.r5.terminologies.JurisdictionUtilities;
|
||||
import org.hl7.fhir.r5.terminologies.client.ITerminologyClient;
|
||||
import org.hl7.fhir.r5.terminologies.client.TerminologyClientContext;
|
||||
import org.hl7.fhir.r5.terminologies.client.TerminologyClientManager;
|
||||
import org.hl7.fhir.r5.terminologies.client.TerminologyClientManager.ITerminologyClientFactory;
|
||||
import org.hl7.fhir.r5.terminologies.client.TerminologyClientR5;
|
||||
|
@ -237,7 +240,7 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
|
|||
}
|
||||
|
||||
private SimpleWorkerContext build(SimpleWorkerContext context) throws IOException {
|
||||
context.initTS(terminologyCachePath);
|
||||
context.initTxCache(terminologyCachePath);
|
||||
context.setUserAgent(userAgent);
|
||||
context.setLogger(loggingService);
|
||||
context.cacheResource(new org.hl7.fhir.r5.formats.JsonParser().parse(MagicResources.spdxCodesAsData()));
|
||||
|
@ -247,7 +250,7 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
|
|||
public SimpleWorkerContext fromPackage(NpmPackage pi) throws IOException, FHIRException {
|
||||
SimpleWorkerContext context = getSimpleWorkerContextInstance();
|
||||
context.setAllowLoadingDuplicates(allowLoadingDuplicates);
|
||||
context.terminologyClientManager = new TerminologyClientManager(TerminologyClientR5.factory());
|
||||
context.terminologyClientManager.setFactory(TerminologyClientR5.factory());
|
||||
context.loadFromPackage(pi, null);
|
||||
return build(context);
|
||||
}
|
||||
|
@ -328,30 +331,48 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
|
|||
loadBytes(name, stream);
|
||||
}
|
||||
|
||||
public String connectToTSServer(ITerminologyClientFactory factory, ITerminologyClient client, String log) {
|
||||
public void connectToTSServer(ITerminologyClientFactory factory, ITerminologyClient client) {
|
||||
terminologyClientManager.setFactory(factory);
|
||||
if (txLog == null) {
|
||||
txLog = client.getLogger();
|
||||
}
|
||||
TerminologyClientContext tcc = terminologyClientManager.setMasterClient(client);
|
||||
txLog("Connect to "+client.getAddress());
|
||||
try {
|
||||
tcc.initialize();
|
||||
} catch (Exception e) {
|
||||
if (canRunWithoutTerminology) {
|
||||
noTerminologyServer = true;
|
||||
logger.logMessage("==============!! Running without terminology server !! ==============");
|
||||
if (terminologyClientManager.getMasterClient() != null) {
|
||||
logger.logMessage("txServer = "+ terminologyClientManager.getMasterClient().getId());
|
||||
logger.logMessage("Error = "+e.getMessage()+"");
|
||||
}
|
||||
logger.logMessage("=====================================================================");
|
||||
} else {
|
||||
e.printStackTrace();
|
||||
throw new TerminologyServiceException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void connectToTSServer(ITerminologyClientFactory factory, String address, String software, String log) {
|
||||
try {
|
||||
txLog("Connect to "+client.getAddress());
|
||||
terminologyClientManager.setFactory(factory);
|
||||
terminologyClientManager.setMasterClient(client);
|
||||
if (log != null && (log.endsWith(".htm") || log.endsWith(".html"))) {
|
||||
txLog = new HTMLClientLogger(log);
|
||||
} else {
|
||||
txLog = new TextClientLogger(log);
|
||||
}
|
||||
terminologyClientManager.setLogger(txLog);
|
||||
terminologyClientManager.setUserAgent(userAgent);
|
||||
|
||||
final CapabilityStatement capabilitiesStatementQuick = txCache.hasCapabilityStatement() ? txCache.getCapabilityStatement() : terminologyClientManager.getMasterClient().getCapabilitiesStatementQuick();
|
||||
txCache.cacheCapabilityStatement(capabilitiesStatementQuick);
|
||||
|
||||
final TerminologyCapabilities capabilityStatement = txCache.hasTerminologyCapabilities() ? txCache.getTerminologyCapabilities() : terminologyClientManager.getMasterClient().getTerminologyCapabilities();
|
||||
txCache.cacheTerminologyCapabilities(capabilityStatement);
|
||||
|
||||
setTxCaps(capabilityStatement);
|
||||
return capabilitiesStatementQuick.getSoftware().getVersion();
|
||||
}
|
||||
ITerminologyClient client = factory.makeClient("tx-server", address, software, txLog);
|
||||
// txFactory.makeClient("Tx-Server", txServer, "fhir/publisher", null)
|
||||
// terminologyClientManager.setLogger(txLog);
|
||||
// terminologyClientManager.setUserAgent(userAgent);
|
||||
connectToTSServer(factory, client);
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new FHIRException(formatMessage(canNoTS ? I18nConstants.UNABLE_TO_CONNECT_TO_TERMINOLOGY_SERVER_USE_PARAMETER_TX_NA_TUN_RUN_WITHOUT_USING_TERMINOLOGY_SERVICES_TO_VALIDATE_LOINC_SNOMED_ICDX_ETC_ERROR__ : I18nConstants.UNABLE_TO_CONNECT_TO_TERMINOLOGY_SERVER, e.getMessage(), client.getAddress()), e);
|
||||
throw new FHIRException(formatMessage(canNoTS ? I18nConstants.UNABLE_TO_CONNECT_TO_TERMINOLOGY_SERVER_USE_PARAMETER_TX_NA_TUN_RUN_WITHOUT_USING_TERMINOLOGY_SERVICES_TO_VALIDATE_LOINC_SNOMED_ICDX_ETC_ERROR__ : I18nConstants.UNABLE_TO_CONNECT_TO_TERMINOLOGY_SERVER, e.getMessage(), address), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -243,7 +243,7 @@ public class SHLParser extends ParserBase {
|
|||
}
|
||||
|
||||
private void processContent(List<ValidatedFragment> res, List<ValidationMessage> errors, String path, String name, String jose, String ct) throws FHIRFormatError, DefinitionException, FHIRException, IOException {
|
||||
ValidatedFragment bin = addNamedElement(res, "encrypted", "jose", TextFile.stringToBytes(jose, false));
|
||||
ValidatedFragment bin = addNamedElement(res, "encrypted", "jose", TextFile.stringToBytes(jose));
|
||||
byte[] cnt = null;
|
||||
JWEObject jwe;
|
||||
try {
|
||||
|
|
|
@ -58,26 +58,26 @@ public class FHIRLexer {
|
|||
private boolean allowDoubleQuotes;
|
||||
|
||||
public FHIRLexer(String source, String name) throws FHIRLexerException {
|
||||
this.source = source == null ? "" : source;
|
||||
this.source = source == null ? "" : Utilities.stripBOM(source);
|
||||
this.name = name == null ? "??" : name;
|
||||
currentLocation = new SourceLocation(1, 1);
|
||||
next();
|
||||
}
|
||||
public FHIRLexer(String source, int i) throws FHIRLexerException {
|
||||
this.source = source;
|
||||
this.source = Utilities.stripBOM(source);
|
||||
this.cursor = i;
|
||||
currentLocation = new SourceLocation(1, 1);
|
||||
next();
|
||||
}
|
||||
public FHIRLexer(String source, int i, boolean allowDoubleQuotes) throws FHIRLexerException {
|
||||
this.source = source;
|
||||
this.source = Utilities.stripBOM(source);
|
||||
this.cursor = i;
|
||||
this.allowDoubleQuotes = allowDoubleQuotes;
|
||||
currentLocation = new SourceLocation(1, 1);
|
||||
next();
|
||||
}
|
||||
public FHIRLexer(String source, String name, boolean metadataFormat, boolean allowDoubleQuotes) throws FHIRLexerException {
|
||||
this.source = source == null ? "" : source;
|
||||
this.source = source == null ? "" : Utilities.stripBOM(source);
|
||||
this.name = name == null ? "??" : name;
|
||||
this.metadataFormat = metadataFormat;
|
||||
this.allowDoubleQuotes = allowDoubleQuotes;
|
||||
|
|
|
@ -2555,7 +2555,7 @@ public class FHIRPathEngine {
|
|||
private List<Base> opMemberOf(ExecutionContext context, List<Base> left, List<Base> right, ExpressionNode expr) throws FHIRException {
|
||||
boolean ans = false;
|
||||
String url = right.get(0).primitiveValue();
|
||||
ValueSet vs = hostServices != null ? hostServices.resolveValueSet(this, context.appInfo, url) : worker.fetchResource(ValueSet.class, url);
|
||||
ValueSet vs = hostServices != null ? hostServices.resolveValueSet(this, context.appInfo, url) : worker.findTxResource(ValueSet.class, url);
|
||||
if (vs != null) {
|
||||
for (Base l : left) {
|
||||
if (Utilities.existsInList(l.fhirType(), "code", "string", "uri")) {
|
||||
|
@ -2748,7 +2748,7 @@ public class FHIRPathEngine {
|
|||
p = worker.getUcumService().multiply(pl, pr);
|
||||
result.add(pairToQty(p));
|
||||
} catch (UcumException e) {
|
||||
throw new PathEngineException(e.getMessage(), null, expr.getOpStart(), expr.toString(), e); // #FIXME
|
||||
throw new PathEngineException(e.getMessage(), null, expr.getOpStart(), expr.toString(), e); // #TODO: i18n
|
||||
}
|
||||
} else {
|
||||
throw makeException(expr, I18nConstants.FHIRPATH_OP_INCOMPATIBLE, "*", left.get(0).fhirType(), right.get(0).fhirType());
|
||||
|
@ -4620,7 +4620,7 @@ public class FHIRPathEngine {
|
|||
}
|
||||
|
||||
String url = nl.get(0).primitiveValue();
|
||||
ValueSet vs = hostServices != null ? hostServices.resolveValueSet(this, context.appInfo, url) : worker.fetchResource(ValueSet.class, url);
|
||||
ValueSet vs = hostServices != null ? hostServices.resolveValueSet(this, context.appInfo, url) : worker.findTxResource(ValueSet.class, url);
|
||||
if (vs == null) {
|
||||
return new ArrayList<Base>();
|
||||
}
|
||||
|
@ -4977,10 +4977,10 @@ public class FHIRPathEngine {
|
|||
tn = "FHIR."+expr.getParameters().get(0).getName();
|
||||
}
|
||||
if (!isKnownType(tn)) {
|
||||
throw new PathEngineException(worker.formatMessage(I18nConstants.FHIRPATH_INVALID_TYPE, tn), I18nConstants.FHIRPATH_INVALID_TYPE); // #FIXME
|
||||
throw new PathEngineException(worker.formatMessage(I18nConstants.FHIRPATH_INVALID_TYPE, tn), I18nConstants.FHIRPATH_INVALID_TYPE);
|
||||
}
|
||||
if (!doNotEnforceAsSingletonRule && focus.size() > 1) {
|
||||
throw new PathEngineException(worker.formatMessage(I18nConstants.FHIRPATH_AS_COLLECTION, focus.size(), expr.toString()), I18nConstants.FHIRPATH_AS_COLLECTION); // #FIXME
|
||||
throw new PathEngineException(worker.formatMessage(I18nConstants.FHIRPATH_AS_COLLECTION, focus.size(), expr.toString()), I18nConstants.FHIRPATH_AS_COLLECTION);
|
||||
}
|
||||
|
||||
for (Base b : focus) {
|
||||
|
@ -5020,7 +5020,7 @@ public class FHIRPathEngine {
|
|||
tn = "FHIR."+expr.getParameters().get(0).getName();
|
||||
}
|
||||
if (!isKnownType(tn)) {
|
||||
throw new PathEngineException(worker.formatMessage(I18nConstants.FHIRPATH_INVALID_TYPE, tn), I18nConstants.FHIRPATH_INVALID_TYPE); // #FIXME
|
||||
throw new PathEngineException(worker.formatMessage(I18nConstants.FHIRPATH_INVALID_TYPE, tn), I18nConstants.FHIRPATH_INVALID_TYPE);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -142,6 +142,9 @@ public class OperationOutcome extends DomainResource implements IBaseOperationOu
|
|||
default: return "?";
|
||||
}
|
||||
}
|
||||
public boolean isHigherThan(IssueSeverity other) {
|
||||
return this.ordinal() < other.ordinal();
|
||||
}
|
||||
}
|
||||
|
||||
public static class IssueSeverityEnumFactory implements EnumFactory<IssueSeverity> {
|
||||
|
|
|
@ -259,7 +259,11 @@ public class AdditionalBindingsRenderer {
|
|||
if (binding.compare!=null && binding.valueSet.equals(binding.compare.valueSet))
|
||||
valueset.style(STYLE_UNCHANGED);
|
||||
if (br.url != null) {
|
||||
valueset.ah(determineUrl(br.url), binding.valueSet).tx(br.display);
|
||||
XhtmlNode a = valueset.ah(determineUrl(br.url), br.uri).tx(br.display);
|
||||
if (br.external) {
|
||||
a.tx(" ");
|
||||
a.img("external.png", null);
|
||||
}
|
||||
} else {
|
||||
valueset.span(null, binding.valueSet).tx(br.display);
|
||||
}
|
||||
|
@ -411,7 +415,7 @@ public class AdditionalBindingsRenderer {
|
|||
return; // what should happen?
|
||||
}
|
||||
BindingResolution br = pkp.resolveBinding(profile, b.getValueSet(), corePath);
|
||||
XhtmlNode a = children.ahOrCode(br.url == null ? null : Utilities.isAbsoluteUrl(br.url) || !context.getPkp().prependLinks() ? br.url : corePath+br.url, b.hasDocumentation() ? b.getDocumentation() : null);
|
||||
XhtmlNode a = children.ahOrCode(br.url == null ? null : Utilities.isAbsoluteUrl(br.url) || !context.getPkp().prependLinks() ? br.url : corePath+br.url, b.hasDocumentation() ? b.getDocumentation() : br.uri);
|
||||
if (b.hasDocumentation()) {
|
||||
a.attribute("title", b.getDocumentation());
|
||||
}
|
||||
|
|
|
@ -337,7 +337,7 @@ public class DataRenderer extends Renderer implements CodeResolver {
|
|||
if ("fr-CA".equals(lang)) {
|
||||
return "French (Canadian)"; // this one was omitted from the value set
|
||||
}
|
||||
ValueSet v = getContext().getWorker().fetchResource(ValueSet.class, "http://hl7.org/fhir/ValueSet/languages");
|
||||
ValueSet v = getContext().getWorker().findTxResource(ValueSet.class, "http://hl7.org/fhir/ValueSet/languages");
|
||||
if (v != null) {
|
||||
ConceptReferenceComponent l = null;
|
||||
for (ConceptReferenceComponent cc : v.getCompose().getIncludeFirstRep().getConcept()) {
|
||||
|
|
|
@ -324,7 +324,7 @@ public class QuestionnaireRenderer extends TerminologyRenderer {
|
|||
defn.getPieces().add(gen.new Piece(vs.getWebPath(), vs.present(), null));
|
||||
}
|
||||
} else {
|
||||
ValueSet vs = context.getWorker().fetchResource(ValueSet.class, i.getAnswerValueSet(), q);
|
||||
ValueSet vs = context.getWorker().findTxResource(ValueSet.class, i.getAnswerValueSet(), q);
|
||||
if (vs == null || !vs.hasWebPath()) {
|
||||
defn.getPieces().add(gen.new Piece(null, i.getAnswerValueSet(), null));
|
||||
} else {
|
||||
|
@ -513,7 +513,7 @@ public class QuestionnaireRenderer extends TerminologyRenderer {
|
|||
defn.getPieces().add(gen.new Piece(vs.getWebPath(), vs.present(), null));
|
||||
}
|
||||
} else {
|
||||
ValueSet vs = context.getWorker().fetchResource(ValueSet.class, i.getAnswerValueSet(), q);
|
||||
ValueSet vs = context.getWorker().findTxResource(ValueSet.class, i.getAnswerValueSet(), q);
|
||||
if (vs == null || !vs.hasWebPath()) {
|
||||
defn.getPieces().add(gen.new Piece(null, i.getAnswerValueSet(), null));
|
||||
} else {
|
||||
|
@ -753,7 +753,7 @@ public class QuestionnaireRenderer extends TerminologyRenderer {
|
|||
ans.ah(vs.getWebPath()).tx(vs.present());
|
||||
}
|
||||
} else {
|
||||
ValueSet vs = context.getWorker().fetchResource(ValueSet.class, i.getAnswerValueSet(), q);
|
||||
ValueSet vs = context.getWorker().findTxResource(ValueSet.class, i.getAnswerValueSet(), q);
|
||||
if (vs == null || !vs.hasWebPath()) {
|
||||
ans.tx(i.getAnswerValueSet());
|
||||
} else {
|
||||
|
@ -854,7 +854,7 @@ public class QuestionnaireRenderer extends TerminologyRenderer {
|
|||
vs.setUrl(q.getUrl()+"--"+q.getContained(i.getAnswerValueSet().substring(1)));
|
||||
}
|
||||
} else {
|
||||
vs = context.getContext().fetchResource(ValueSet.class, i.getAnswerValueSet(), q);
|
||||
vs = context.getContext().findTxResource(ValueSet.class, i.getAnswerValueSet(), q);
|
||||
}
|
||||
if (vs != null) {
|
||||
ValueSetExpansionOutcome exp = context.getContext().expandVS(vs, true, false);
|
||||
|
@ -975,7 +975,7 @@ public class QuestionnaireRenderer extends TerminologyRenderer {
|
|||
// content control
|
||||
defn(tbl, "Max Length", qi.getMaxLength());
|
||||
if (qi.hasAnswerValueSet()) {
|
||||
defn(tbl, "Value Set", qi.getDefinition(), context.getWorker().fetchResource(ValueSet.class, qi.getAnswerValueSet(), q));
|
||||
defn(tbl, "Value Set", qi.getDefinition(), context.getWorker().findTxResource(ValueSet.class, qi.getAnswerValueSet(), q));
|
||||
}
|
||||
if (qi.hasAnswerOption()) {
|
||||
XhtmlNode tr = tbl.tr();
|
||||
|
|
|
@ -492,7 +492,7 @@ public class QuestionnaireResponseRenderer extends ResourceRenderer {
|
|||
// ans.ah(vs.getWebPath()).tx(vs.present());
|
||||
// }
|
||||
// } else {
|
||||
// ValueSet vs = context.getWorker().fetchResource(ValueSet.class, i.getAnswerValueSet());
|
||||
// ValueSet vs = context.getWorker().findTxResource(ValueSet.class, i.getAnswerValueSet());
|
||||
// if (vs == null || !vs.hasWebPath()) {
|
||||
// ans.tx(i.getAnswerValueSet());
|
||||
// } else {
|
||||
|
@ -579,7 +579,7 @@ public class QuestionnaireResponseRenderer extends ResourceRenderer {
|
|||
// vs.setUrl("urn:uuid:"+UUID.randomUUID().toString().toLowerCase());
|
||||
// }
|
||||
// } else {
|
||||
// vs = context.getContext().fetchResource(ValueSet.class, i.getAnswerValueSet());
|
||||
// vs = context.getContext().findTxResource(ValueSet.class, i.getAnswerValueSet());
|
||||
// }
|
||||
// if (vs != null) {
|
||||
// ValueSetExpansionOutcome exp = context.getContext().expandVS(vs, true, false);
|
||||
|
@ -707,7 +707,7 @@ public class QuestionnaireResponseRenderer extends ResourceRenderer {
|
|||
// // content control
|
||||
// defn(tbl, "Max Length", qi.getMaxLength());
|
||||
// if (qi.hasAnswerValueSet()) {
|
||||
// defn(tbl, "Value Set", qi.getDefinition(), context.getWorker().fetchResource(ValueSet.class, qi.getAnswerValueSet()));
|
||||
// defn(tbl, "Value Set", qi.getDefinition(), context.getWorker().findTxResource(ValueSet.class, qi.getAnswerValueSet()));
|
||||
// }
|
||||
// if (qi.hasAnswerOption()) {
|
||||
// XhtmlNode tr = tbl.tr();
|
||||
|
|
|
@ -1550,7 +1550,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
|
|||
c.addPiece(gen.new Piece("br"));
|
||||
BindingResolution br = context.getPkp() == null ? makeNullBr(binding) : context.getPkp().resolveBinding(profile, binding, definition.getPath());
|
||||
c.getPieces().add(checkForNoChange(binding, gen.new Piece(null, translate("sd.table", "Binding")+": ", null).addStyle("font-weight:bold")));
|
||||
c.getPieces().add(checkForNoChange(binding.getValueSetElement(), gen.new Piece(br.url == null ? null : Utilities.isAbsoluteUrl(br.url) || !context.getPkp().prependLinks() ? br.url : corePath+br.url, br.display, null)));
|
||||
c.getPieces().add(checkForNoChange(binding.getValueSetElement(), checkAddExternalFlag(br, gen.new Piece(br.url == null ? null : Utilities.isAbsoluteUrl(br.url) || !context.getPkp().prependLinks() ? br.url : corePath+br.url, br.display, br.uri))));
|
||||
if (binding.hasStrength()) {
|
||||
c.getPieces().add(checkForNoChange(binding.getStrengthElement(), gen.new Piece(null, " (", null)));
|
||||
c.getPieces().add(checkForNoChange(binding.getStrengthElement(), gen.new Piece(corePath+"terminologies.html#"+binding.getStrength().toCode(), egt(binding.getStrengthElement()), binding.getStrength().getDefinition())));
|
||||
|
@ -1662,6 +1662,13 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
|
|||
return c;
|
||||
}
|
||||
|
||||
private Piece checkAddExternalFlag(BindingResolution br, Piece piece) {
|
||||
if (br.external) {
|
||||
piece.setTagImg("external.png");
|
||||
}
|
||||
return piece;
|
||||
}
|
||||
|
||||
private boolean isAttr(SourcedElementDefinition ed) {
|
||||
for (Enumeration<PropertyRepresentation> t : ed.getDefinition().getRepresentation()) {
|
||||
if (t.getValue() == PropertyRepresentation.XMLATTR) {
|
||||
|
@ -2375,10 +2382,11 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
|
|||
c.addPiece(gen.new Piece("br"));
|
||||
BindingResolution br = context.getPkp().resolveBinding(profile, binding, definition.getPath());
|
||||
c.getPieces().add(checkForNoChange(binding, gen.new Piece(null, "Binding: ", null).addStyle("font-weight:bold")));
|
||||
c.getPieces().add(checkForNoChange(binding, gen.new Piece(br.url == null ? null : Utilities.isAbsoluteUrl(br.url) || !context.getPkp().prependLinks() ? br.url : corePath+br.url, br.display, null)));
|
||||
c.getPieces().add(checkForNoChange(binding, checkAddExternalFlag(br, gen.new Piece(br.url == null ? null : Utilities.isAbsoluteUrl(br.url) || !context.getPkp().prependLinks() ? br.url : corePath+br.url, br.display, br.uri))));
|
||||
if (binding.hasStrength()) {
|
||||
c.getPieces().add(checkForNoChange(binding, gen.new Piece(null, " (", null)));
|
||||
c.getPieces().add(checkForNoChange(binding, gen.new Piece(corePath+"terminologies.html#"+binding.getStrength().toCode(), binding.getStrength().toCode(), binding.getStrength().getDefinition()))); c.getPieces().add(gen.new Piece(null, ")", null));
|
||||
c.getPieces().add(checkForNoChange(binding, gen.new Piece(corePath+"terminologies.html#"+binding.getStrength().toCode(), binding.getStrength().toCode(), binding.getStrength().getDefinition())));
|
||||
c.getPieces().add(gen.new Piece(null, ")", null));
|
||||
}
|
||||
if (binding.hasDescription() && MarkDownProcessor.isSimpleMarkdown(binding.getDescription())) {
|
||||
c.getPieces().add(gen.new Piece(null, ": ", null));
|
||||
|
@ -3088,7 +3096,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
|
|||
c.addPiece(gen.new Piece("br"));
|
||||
BindingResolution br = context.getPkp().resolveBinding(ed, ved.getBinding(), ved.getPath());
|
||||
c.getPieces().add(checkForNoChange(ved.getBinding(), gen.new Piece(null, translate("sd.table", "Binding")+": ", null).addStyle("font-weight:bold")));
|
||||
c.getPieces().add(checkForNoChange(ved.getBinding(), gen.new Piece(br.url == null ? null : Utilities.isAbsoluteUrl(br.url) || !context.getPkp().prependLinks() ? br.url : corePath+br.url, br.display, null)));
|
||||
c.getPieces().add(checkForNoChange(ved.getBinding(), checkAddExternalFlag(br, gen.new Piece(br.url == null ? null : Utilities.isAbsoluteUrl(br.url) || !context.getPkp().prependLinks() ? br.url : corePath+br.url, br.display, br.uri))));
|
||||
if (ved.getBinding().hasStrength()) {
|
||||
c.getPieces().add(checkForNoChange(ved.getBinding(), gen.new Piece(null, " (", null)));
|
||||
c.getPieces().add(checkForNoChange(ved.getBinding(), gen.new Piece(corePath+"terminologies.html#"+ved.getBinding().getStrength().toCode(), egt(ved.getBinding().getStrengthElement()), ved.getBinding().getStrength().getDefinition())));
|
||||
|
@ -3470,11 +3478,11 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
|
|||
return false;
|
||||
}
|
||||
|
||||
public XhtmlNode compareString(String newStr, Base source, String nLink, String name, Base parent, String oldStr, String oLink, int mode) {
|
||||
public XhtmlNode compareString(String newStr, Base source, String nLink, String name, Base parent, String oldStr, String oLink, int mode, boolean externalN, boolean externalO) {
|
||||
XhtmlNode x = new XhtmlNode(NodeType.Element, "div");
|
||||
if (mode != GEN_MODE_KEY) {
|
||||
if (newStr != null) {
|
||||
renderStatus(source, x).ah(nLink).tx(newStr);
|
||||
renderStatus(source, x).ah(nLink).txN(newStr).iff(externalN).txN(" ").img("external.png", null);
|
||||
} else if (VersionComparisonAnnotation.hasDeleted(parent, name)) {
|
||||
PrimitiveType p = (PrimitiveType) VersionComparisonAnnotation.getDeletedItem(parent, name);
|
||||
renderStatus(p, x).tx(p.primitiveValue());
|
||||
|
@ -3485,33 +3493,33 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
|
|||
if (newStr==null || newStr.isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
renderStatus(source, x).ah(nLink).tx(newStr);
|
||||
renderStatus(source, x).ah(nLink).txN(newStr).iff(externalN).txN(" ").img("external.png", null);
|
||||
}
|
||||
} else if (oldStr!=null && !oldStr.isEmpty() && (newStr==null || newStr.isEmpty())) {
|
||||
if (mode == GEN_MODE_DIFF) {
|
||||
return null;
|
||||
} else {
|
||||
removed(x).ah(oLink).tx(oldStr);
|
||||
removed(x).ah(oLink).txN(oldStr).iff(externalO).txN(" ").img("external.png", null);
|
||||
}
|
||||
} else if (oldStr.equals(newStr)) {
|
||||
if (mode==GEN_MODE_DIFF) {
|
||||
return null;
|
||||
} else {
|
||||
unchanged(x).ah(nLink).tx(newStr);
|
||||
unchanged(x).ah(nLink).txN(newStr).iff(externalN).txN(" ").img("external.png", null);
|
||||
}
|
||||
} else if (newStr.startsWith(oldStr)) {
|
||||
unchanged(x).ah(oLink).tx(oldStr);
|
||||
renderStatus(source, x).ah(nLink).tx(newStr.substring(oldStr.length()));
|
||||
unchanged(x).ah(oLink).txN(oldStr).iff(externalO).txN(" ").img("external.png", null);
|
||||
renderStatus(source, x).ah(nLink).txN(newStr.substring(oldStr.length())).iff(externalN).txN(" ").img("external.png", null);
|
||||
} else {
|
||||
// TODO: improve comparision in this fall-through case, by looking for matches in sub-paragraphs?
|
||||
renderStatus(source, x).ah(nLink).tx(newStr);
|
||||
removed(x).ah(oLink).tx(oldStr);
|
||||
renderStatus(source, x).ah(nLink).txN(newStr).iff(externalN).txN(" ").img("external.png", null);
|
||||
removed(x).ah(oLink).txN(oldStr).iff(externalO).txN(" ").img("external.png", null);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
public boolean compareString(XhtmlNode x, String newStr, Base source, String nLink, String name, Base parent, String oldStr, String oLink, int mode) {
|
||||
XhtmlNode x1 = compareString(newStr, source, nLink, name, parent, oldStr, oLink, mode);
|
||||
public boolean compareString(XhtmlNode x, String newStr, Base source, String nLink, String name, Base parent, String oldStr, String oLink, int mode, boolean externalN, boolean externalO) {
|
||||
XhtmlNode x1 = compareString(newStr, source, nLink, name, parent, oldStr, oLink, mode, externalN, externalO);
|
||||
if (x1 == null) {
|
||||
return false;
|
||||
} else {
|
||||
|
@ -3541,12 +3549,12 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
|
|||
boolean slicedExtension = d.hasSliceName() && (d.getPath().endsWith(".extension") || d.getPath().endsWith(".modifierExtension"));
|
||||
// int slicedExtensionMode = (mode == GEN_MODE_KEY) && slicedExtension ? GEN_MODE_SNAP : mode; // see ProfileUtilities.checkExtensionDoco / Task 3970
|
||||
if (d.hasSliceName()) {
|
||||
tableRow(tbl, "Slice Name", "profiling.html#slicing", strikethrough, compareString(d.getSliceName(), d.getSliceNameElement(), null, (compare != null ? compare.getSliceName() : null), d, null, "sliceName", mode));
|
||||
tableRow(tbl, "Slice Constraining", "profiling.html#slicing", strikethrough, compareString(encodeValue(d.getSliceIsConstrainingElement()), d.getSliceIsConstrainingElement(), null, (compare != null ? encodeValue(compare.getSliceIsConstrainingElement()) : null), d, null, "sliceName", mode));
|
||||
tableRow(tbl, "Slice Name", "profiling.html#slicing", strikethrough, compareString(d.getSliceName(), d.getSliceNameElement(), null, (compare != null ? compare.getSliceName() : null), d, null, "sliceName", mode, false, false));
|
||||
tableRow(tbl, "Slice Constraining", "profiling.html#slicing", strikethrough, compareString(encodeValue(d.getSliceIsConstrainingElement()), d.getSliceIsConstrainingElement(), null, (compare != null ? encodeValue(compare.getSliceIsConstrainingElement()) : null), d, null, "sliceName", mode, false, false));
|
||||
}
|
||||
|
||||
tableRow(tbl, "Definition", null, strikethrough, compareMarkdown(sd.getName(), d.getDefinitionElement(), (compare==null) || slicedExtension ? null : compare.getDefinitionElement(), mode));
|
||||
tableRow(tbl, "Short", null, strikethrough, compareString(d.hasShort() ? d.getShort() : null, d.getShortElement(), null, "short", d, compare!= null && compare.hasShortElement() ? compare.getShort() : null, null, mode));
|
||||
tableRow(tbl, "Short", null, strikethrough, compareString(d.hasShort() ? d.getShort() : null, d.getShortElement(), null, "short", d, compare!= null && compare.hasShortElement() ? compare.getShort() : null, null, mode, false, false));
|
||||
tableRow(tbl, "Comments", null, strikethrough, compareMarkdown(sd.getName(), d.getCommentElement(), (compare==null) || slicedExtension ? null : compare.getCommentElement(), mode));
|
||||
tableRow(tbl, "Note", null, strikethrough, businessIdWarning(sd.getName(), tail(d.getPath())));
|
||||
tableRow(tbl, "Control", "conformance-rules.html#conformance", strikethrough, describeCardinality(d, compare, mode));
|
||||
|
@ -3696,13 +3704,13 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
|
|||
tableRow(tbl, "Summary", "search.html#summary", strikethrough, Boolean.toString(d.getIsSummary()));
|
||||
}
|
||||
tableRow(tbl, "Requirements", null, strikethrough, compareMarkdown(sd.getName(), d.getRequirementsElement(), (compare==null) || slicedExtension ? null : compare.getRequirementsElement(), mode));
|
||||
tableRow(tbl, "Label", null, strikethrough, compareString(d.getLabel(), d.getLabelElement(), null, "label", d, (compare != null ? compare.getLabel() : null), null, mode));
|
||||
tableRow(tbl, "Label", null, strikethrough, compareString(d.getLabel(), d.getLabelElement(), null, "label", d, (compare != null ? compare.getLabel() : null), null, mode, false, false));
|
||||
tableRow(tbl, "Alternate Names", null, strikethrough, compareSimpleTypeLists(d.getAlias(), ((compare==null) || slicedExtension ? null : compare.getAlias()), mode));
|
||||
tableRow(tbl, "Definitional Codes", null, strikethrough, compareDataTypeLists(d.getCode(), ((compare==null) || slicedExtension ? null : compare.getCode()), mode));
|
||||
tableRow(tbl, "Min Value", null, strikethrough, compareString(d.hasMinValue() ? encodeValue(d.getMinValue()) : null, d.getMinValue(), null, "minValue", d, compare!= null && compare.hasMinValue() ? encodeValue(compare.getMinValue()) : null, null, mode));
|
||||
tableRow(tbl, "Max Value", null, strikethrough, compareString(d.hasMaxValue() ? encodeValue(d.getMaxValue()) : null, d.getMaxValue(), null, "maxValue", d, compare!= null && compare.hasMaxValue() ? encodeValue(compare.getMaxValue()) : null, null, mode));
|
||||
tableRow(tbl, "Max Length", null, strikethrough, compareString(d.hasMaxLength() ? toStr(d.getMaxLength()) : null, d.getMaxLengthElement(), null, "maxLength", d, compare!= null && compare.hasMaxLengthElement() ? toStr(compare.getMaxLength()) : null, null, mode));
|
||||
tableRow(tbl, "Value Required", null, strikethrough, compareString(encodeValue(d.getMustHaveValueElement()), d.getMustHaveValueElement(), null, (compare != null ? encodeValue(compare.getMustHaveValueElement()) : null), d, null, "mustHaveValueElement", mode));
|
||||
tableRow(tbl, "Min Value", null, strikethrough, compareString(d.hasMinValue() ? encodeValue(d.getMinValue()) : null, d.getMinValue(), null, "minValue", d, compare!= null && compare.hasMinValue() ? encodeValue(compare.getMinValue()) : null, null, mode, false, false));
|
||||
tableRow(tbl, "Max Value", null, strikethrough, compareString(d.hasMaxValue() ? encodeValue(d.getMaxValue()) : null, d.getMaxValue(), null, "maxValue", d, compare!= null && compare.hasMaxValue() ? encodeValue(compare.getMaxValue()) : null, null, mode, false, false));
|
||||
tableRow(tbl, "Max Length", null, strikethrough, compareString(d.hasMaxLength() ? toStr(d.getMaxLength()) : null, d.getMaxLengthElement(), null, "maxLength", d, compare!= null && compare.hasMaxLengthElement() ? toStr(compare.getMaxLength()) : null, null, mode, false, false));
|
||||
tableRow(tbl, "Value Required", null, strikethrough, compareString(encodeValue(d.getMustHaveValueElement()), d.getMustHaveValueElement(), null, (compare != null ? encodeValue(compare.getMustHaveValueElement()) : null), d, null, "mustHaveValueElement", mode, false, false));
|
||||
tableRow(tbl, "Value Alternatives", null, strikethrough, compareSimpleTypeLists(d.getValueAlternatives(), ((compare==null) || slicedExtension ? null : compare.getValueAlternatives()), mode));
|
||||
tableRow(tbl, "Default Value", null, strikethrough, encodeValue(d.getDefaultValue(), "defaultValue", d, compare==null ? null : compare.getDefaultValue(), mode));
|
||||
tableRow(tbl, "Meaning if Missing", null, strikethrough, d.getMeaningWhenMissing());
|
||||
|
@ -3716,9 +3724,9 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
|
|||
}
|
||||
|
||||
private XhtmlNode presentModifier(ElementDefinition d, int mode, ElementDefinition compare) throws FHIRException, IOException {
|
||||
XhtmlNode x1 = compareString(encodeValue(d.getIsModifierElement()), d.getIsModifierElement(), null, "isModifier", d, compare == null ? null : encodeValue(compare.getIsModifierElement()), null, mode);
|
||||
XhtmlNode x1 = compareString(encodeValue(d.getIsModifierElement()), d.getIsModifierElement(), null, "isModifier", d, compare == null ? null : encodeValue(compare.getIsModifierElement()), null, mode, false, false);
|
||||
if (x1 != null) {
|
||||
XhtmlNode x2 = compareString(encodeValue(d.getIsModifierReasonElement()), d.getIsModifierReasonElement(), null, "isModifierReason", d, compare == null ? null : encodeValue(compare.getIsModifierReasonElement()), null, mode);
|
||||
XhtmlNode x2 = compareString(encodeValue(d.getIsModifierReasonElement()), d.getIsModifierReasonElement(), null, "isModifierReason", d, compare == null ? null : encodeValue(compare.getIsModifierReasonElement()), null, mode, false, false);
|
||||
if (x2 != null) {
|
||||
x1.tx(" because ");
|
||||
x1.copyAllContent(x2);
|
||||
|
@ -3860,7 +3868,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
|
|||
DataType au = ToolingExtensions.getAllowedUnits(d);
|
||||
if (au instanceof CanonicalType) {
|
||||
String url = ((CanonicalType) au).asStringValue();
|
||||
ValueSet vs = context.getContext().fetchResource(ValueSet.class, url);
|
||||
ValueSet vs = context.getContext().findTxResource(ValueSet.class, url);
|
||||
ret.tx("Value set ");
|
||||
genCT(ret, url, vs);
|
||||
return ret;
|
||||
|
@ -3951,9 +3959,9 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
|
|||
x.codeWithText("This element introduces a set of slices on ", ed.getPath(), ". The slices are ");
|
||||
String newOrdered = sliceOrderString(slicing);
|
||||
String oldOrdered = (compare==null || !compare.hasSlicing()) ? null : sliceOrderString(compare.getSlicing());
|
||||
compareString(x, newOrdered, slicing.getOrderedElement(), null, null, null, oldOrdered, null, mode);
|
||||
compareString(x, newOrdered, slicing.getOrderedElement(), null, null, null, oldOrdered, null, mode, false, false);
|
||||
x.tx(" and ");
|
||||
compareString(x, slicing.hasRules() ? slicing.getRules().getDisplay() : null, slicing.getRulesElement(), null, "rules", slicing, compare!=null && compare.hasSlicing() && compare.getSlicing().hasRules() ? compare.getSlicing().getRules().getDisplay() : null, null, mode);
|
||||
compareString(x, slicing.hasRules() ? slicing.getRules().getDisplay() : null, slicing.getRulesElement(), null, "rules", slicing, compare!=null && compare.hasSlicing() && compare.getSlicing().hasRules() ? compare.getSlicing().getRules().getDisplay() : null, null, mode, false, false);
|
||||
|
||||
if (slicing.hasDiscriminator()) {
|
||||
x.tx(", and can be differentiated using the following discriminators: ");
|
||||
|
@ -4080,11 +4088,11 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
|
|||
}
|
||||
} else {
|
||||
if (!(mode==GEN_MODE_DIFF && (d.getMin()==compare.getMin() || d.getMin()==0))) {
|
||||
compareString(x, toStr(d.getMin()), d.getMinElement(), null, "min", d, toStr(compare.getMin()), null, mode);
|
||||
compareString(x, toStr(d.getMin()), d.getMinElement(), null, "min", d, toStr(compare.getMin()), null, mode, false, false);
|
||||
}
|
||||
x.tx("..");
|
||||
if (!(mode==GEN_MODE_DIFF && (d.getMax().equals(compare.getMax()) || "1".equals(d.getMax())))) {
|
||||
compareString(x, d.getMax(), d.getMaxElement(), null, "max", d, compare.getMax(), null, mode);
|
||||
compareString(x, d.getMax(), d.getMaxElement(), null, "max", d, compare.getMax(), null, mode, false, false);
|
||||
}
|
||||
}
|
||||
XhtmlNode t = compareSimpleTypeLists(d.getCondition(), compare == null ? null : compare.getCondition(), mode);
|
||||
|
@ -4199,9 +4207,9 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
|
|||
|
||||
boolean ts = false;
|
||||
if (t.getWorkingCode().startsWith("xs:")) {
|
||||
ts = compareString(x, t.getWorkingCode(), t, null, "code", t, compare==null ? null : compare.getWorkingCode(), null, mode);
|
||||
ts = compareString(x, t.getWorkingCode(), t, null, "code", t, compare==null ? null : compare.getWorkingCode(), null, mode, false, false);
|
||||
} else {
|
||||
ts = compareString(x, t.getWorkingCode(), t, getTypeLink(t, sd), "code", t, compare==null ? null : compare.getWorkingCode(), compare==null ? null : getTypeLink(compare, sd), mode);
|
||||
ts = compareString(x, t.getWorkingCode(), t, getTypeLink(t, sd), "code", t, compare==null ? null : compare.getWorkingCode(), compare==null ? null : getTypeLink(compare, sd), mode, false, false);
|
||||
}
|
||||
|
||||
if ((!mustSupportOnly && (t.hasProfile() || (compare!=null && compare.hasProfile()))) || isMustSupport(t.getProfile())) {
|
||||
|
@ -4314,7 +4322,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
|
|||
private XhtmlNode displayBoolean(boolean value, BooleanType source, String name, Base parent, BooleanType compare, int mode) {
|
||||
String newValue = value ? "true" : source.hasValue() ? "false" : null;
|
||||
String oldValue = compare==null || compare.getValue()==null ? null : (compare.getValue()!=true ? null : "true");
|
||||
return compareString(newValue, source, null, name, parent, oldValue, null, mode);
|
||||
return compareString(newValue, source, null, name, parent, oldValue, null, mode, false, false);
|
||||
}
|
||||
|
||||
|
||||
|
@ -4402,16 +4410,32 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private boolean isSimpleContent(XhtmlNode bindingDesc) {
|
||||
return bindingDesc.getChildNodes().size() == 1 && bindingDesc.getChildNodes().get(0).isPara();
|
||||
}
|
||||
|
||||
private void renderBinding(XhtmlNode span, ElementDefinitionBindingComponent binding, ElementDefinitionBindingComponent compare, String path, StructureDefinition sd, int mode) {
|
||||
compareString(span, conf(binding), binding.getStrengthElement(), null, "strength", binding, compare == null ? null : conf(compare), null, mode);
|
||||
compareString(span, conf(binding), binding.getStrengthElement(), null, "strength", binding, compare == null ? null : conf(compare), null, mode, false, false);
|
||||
span.tx(" ");
|
||||
BindingResolution br = context.getPkp().resolveBinding(sd, binding, path);
|
||||
compareString(span, br.display, binding.getValueSetElement(), br.url, "valueSet", binding, compare == null ? null : compare.getValueSet(), null, mode);
|
||||
compareString(span, br.display, binding.getValueSetElement(), br.url, "valueSet", binding, compare == null ? null : compare.getValueSet(), null, mode, br.external, false);
|
||||
if (binding.hasStrength() || binding.hasValueSet()) {
|
||||
span.br();
|
||||
span.tx("(");
|
||||
if (binding.hasStrength()) {
|
||||
span.ah(Utilities.pathURL(corePath, "terminologies.html#"+binding.getStrength().toCode())).tx(binding.getStrength().toCode());
|
||||
}
|
||||
if (binding.hasStrength() && binding.hasValueSet()) {
|
||||
span.tx(" ");
|
||||
}
|
||||
if (binding.hasValueSet()) {
|
||||
span.tx("to ");
|
||||
XhtmlNode ispan = span.spanClss("copy-text-inline");
|
||||
ispan.code().tx(binding.getValueSet());
|
||||
ispan.button("btn-copy", "Click to Copy URL").attribute("data-clipboard-text", binding.getValueSet());
|
||||
}
|
||||
span.tx(")");
|
||||
}
|
||||
}
|
||||
|
||||
private String stripPara(String s) {
|
||||
|
@ -4459,7 +4483,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
|
|||
private XhtmlNode encodeValue(DataType value, String name, Base parent, DataType compare, int mode) throws FHIRException, IOException {
|
||||
String oldValue = encodeValue(compare);
|
||||
String newValue = encodeValue(value);
|
||||
return compareString(newValue, value, null, name, parent, oldValue, null, mode);
|
||||
return compareString(newValue, value, null, name, parent, oldValue, null, mode, false, false);
|
||||
}
|
||||
|
||||
private String encodeValue(DataType value) throws FHIRException, IOException {
|
||||
|
@ -4508,7 +4532,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
|
|||
}
|
||||
}
|
||||
|
||||
return compareString(Utilities.escapeXml(newMap), null, null, "mapping", d, Utilities.escapeXml(oldMap), null, mode);
|
||||
return compareString(Utilities.escapeXml(newMap), null, null, "mapping", d, Utilities.escapeXml(oldMap), null, mode, false, false);
|
||||
}
|
||||
|
||||
private XhtmlNode compareSimpleTypeLists(List<? extends PrimitiveType> original, List<? extends PrimitiveType> compare, int mode) throws IOException {
|
||||
|
|
|
@ -287,7 +287,7 @@ public abstract class TerminologyRenderer extends ResourceRenderer {
|
|||
}
|
||||
CanonicalResource vs = (CanonicalResource) res;
|
||||
if (vs == null)
|
||||
vs = getContext().getWorker().fetchResource(ValueSet.class, value, source);
|
||||
vs = getContext().getWorker().findTxResource(ValueSet.class, value, source);
|
||||
if (vs == null)
|
||||
vs = getContext().getWorker().fetchResource(StructureDefinition.class, value, source);
|
||||
if (vs == null)
|
||||
|
|
|
@ -118,7 +118,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
|
|||
re = new ConceptMapRenderInstructions(cm.present(), cm.getUrl(), false);
|
||||
}
|
||||
if (re != null) {
|
||||
ValueSet vst = cm.hasTargetScope() ? getContext().getWorker().fetchResource(ValueSet.class, cm.hasTargetScopeCanonicalType() ? cm.getTargetScopeCanonicalType().getValue() : cm.getTargetScopeUriType().asStringValue(), cm) : null;
|
||||
ValueSet vst = cm.hasTargetScope() ? getContext().getWorker().findTxResource(ValueSet.class, cm.hasTargetScopeCanonicalType() ? cm.getTargetScopeCanonicalType().getValue() : cm.getTargetScopeUriType().asStringValue(), cm) : null;
|
||||
res.add(new UsedConceptMap(re, vst == null ? cm.getWebPath() : vst.getWebPath(), cm));
|
||||
}
|
||||
}
|
||||
|
@ -141,7 +141,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
|
|||
// Map<ConceptMap, String> mymaps = new HashMap<ConceptMap, String>();
|
||||
// for (ConceptMap a : context.getWorker().findMapsForSource(vs.getUrl())) {
|
||||
// String url = "";
|
||||
// ValueSet vsr = context.getWorker().fetchResource(ValueSet.class, ((Reference) a.getTarget()).getReference());
|
||||
// ValueSet vsr = context.getWorker().findTxResource(ValueSet.class, ((Reference) a.getTarget()).getReference());
|
||||
// if (vsr != null)
|
||||
// url = (String) vsr.getUserData("filename");
|
||||
// mymaps.put(a, url);
|
||||
|
@ -160,7 +160,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
|
|||
// ConceptMap cm = (ConceptMap) r;
|
||||
// if (((Reference) cm.getSource()).getReference().equals(cs.getValueSet())) {
|
||||
// String url = "";
|
||||
// ValueSet vsr = context.getWorker().fetchResource(ValueSet.class, ((Reference) cm.getTarget()).getReference());
|
||||
// ValueSet vsr = context.getWorker().findTxResource(ValueSet.class, ((Reference) cm.getTarget()).getReference());
|
||||
// if (vsr != null)
|
||||
// url = (String) vsr.getUserData("filename");
|
||||
// mymaps.put(cm, url);
|
||||
|
|
|
@ -68,10 +68,42 @@ import org.hl7.fhir.r5.utils.CanonicalResourceUtilities;
|
|||
import org.hl7.fhir.r5.utils.ToolingExtensions;
|
||||
import org.hl7.fhir.utilities.StandardsStatus;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.VersionUtilities;
|
||||
|
||||
public class ValueSetUtilities extends TerminologyUtilities {
|
||||
|
||||
|
||||
public static class ValueSetSorter implements Comparator<ValueSet> {
|
||||
|
||||
@Override
|
||||
public int compare(ValueSet o1, ValueSet o2) {
|
||||
String url1 = o1.getUrl();
|
||||
String url2 = o2.getUrl();
|
||||
int c = compareString(url1, url2);
|
||||
if (c == 0) {
|
||||
String ver1 = o1.getVersion();
|
||||
String ver2 = o2.getVersion();
|
||||
c = VersionUtilities.compareVersions(ver1, ver2);
|
||||
if (c == 0) {
|
||||
String d1 = o1.getDateElement().asStringValue();
|
||||
String d2 = o2.getDateElement().asStringValue();
|
||||
c = compareString(url1, url2);
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
private int compareString(String s1, String s2) {
|
||||
if (s1 == null) {
|
||||
return s2 == null ? 0 : 1;
|
||||
} else {
|
||||
return s1.compareTo(s2);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static boolean isServerSide(String url) {
|
||||
return Utilities.existsInList(url, "http://hl7.org/fhir/sid/cvx");
|
||||
}
|
||||
|
@ -413,7 +445,7 @@ public class ValueSetUtilities extends TerminologyUtilities {
|
|||
Set<String> systems = new HashSet<>();
|
||||
for (ConceptSetComponent inc : vs.getCompose().getInclude()) {
|
||||
for (CanonicalType ct : inc.getValueSet()) {
|
||||
ValueSet vsr = ctxt.fetchResource(ValueSet.class, ct.asStringValue(), vs);
|
||||
ValueSet vsr = ctxt.findTxResource(ValueSet.class, ct.asStringValue(), vs);
|
||||
if (vsr != null) {
|
||||
systems.addAll(listSystems(ctxt, vsr));
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@ public interface ITerminologyClient {
|
|||
Parameters validateCS(Parameters pin) throws FHIRException;
|
||||
Parameters validateVS(Parameters pin) throws FHIRException;
|
||||
ITerminologyClient setTimeoutFactor(int i) throws FHIRException;
|
||||
ToolingClientLogger getLogger();
|
||||
ITerminologyClient setLogger(ToolingClientLogger txLog) throws FHIRException;
|
||||
int getRetryCount() throws FHIRException;
|
||||
ITerminologyClient setRetryCount(int retryCount) throws FHIRException;
|
||||
|
@ -69,4 +70,5 @@ public interface ITerminologyClient {
|
|||
ITerminologyClient setContentLanguage(String lang);
|
||||
String getUserAgent();
|
||||
int getUseCount();
|
||||
Bundle search(String type, String criteria);
|
||||
}
|
|
@ -1,18 +1,34 @@
|
|||
package org.hl7.fhir.r5.terminologies.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hl7.fhir.r5.model.CanonicalResource;
|
||||
import org.hl7.fhir.r5.model.CapabilityStatement;
|
||||
import org.hl7.fhir.r5.model.TerminologyCapabilities;
|
||||
import org.hl7.fhir.r5.model.TerminologyCapabilities.TerminologyCapabilitiesCodeSystemComponent;
|
||||
import org.hl7.fhir.r5.model.TerminologyCapabilities.TerminologyCapabilitiesExpansionParameterComponent;
|
||||
import org.hl7.fhir.r5.terminologies.client.TerminologyClientContext.TerminologyClientContextUseCount;
|
||||
import org.hl7.fhir.r5.terminologies.utilities.TerminologyCache;
|
||||
|
||||
public class TerminologyClientContext {
|
||||
public enum TerminologyClientContextUseType {
|
||||
expand, validate, readVS
|
||||
}
|
||||
public class TerminologyClientContextUseCount {
|
||||
private int expands;
|
||||
private int validates;
|
||||
private int readVS;
|
||||
|
||||
public int getReadVS() {
|
||||
return readVS;
|
||||
}
|
||||
public void setReadVS(int readVS) {
|
||||
this.readVS = readVS;
|
||||
}
|
||||
public int getExpands() {
|
||||
return expands;
|
||||
}
|
||||
|
@ -29,14 +45,21 @@ public class TerminologyClientContext {
|
|||
}
|
||||
|
||||
private ITerminologyClient client;
|
||||
Map<String, TerminologyClientContextUseCount> useCounts = new HashMap<>();
|
||||
private boolean initialised = false;
|
||||
private CapabilityStatement capabilitiesStatementQuick;
|
||||
private TerminologyCapabilities txcaps;
|
||||
private TerminologyCache txCache;
|
||||
|
||||
private Map<String, TerminologyClientContextUseCount> useCounts = new HashMap<>();
|
||||
private boolean isTxCaching;
|
||||
private final Set<String> cached = new HashSet<>();
|
||||
private boolean master;
|
||||
private String cacheId;
|
||||
|
||||
protected TerminologyClientContext(ITerminologyClient client, boolean master) {
|
||||
protected TerminologyClientContext(ITerminologyClient client, String cacheId, boolean master) {
|
||||
super();
|
||||
this.client = client;
|
||||
this.cacheId = cacheId;
|
||||
this.master = master;
|
||||
}
|
||||
|
||||
|
@ -52,24 +75,32 @@ public class TerminologyClientContext {
|
|||
return client;
|
||||
}
|
||||
|
||||
public void seeUse(String s, boolean expand) {
|
||||
public void seeUse(String s, TerminologyClientContextUseType useType) {
|
||||
TerminologyClientContextUseCount uc = useCounts.get(s);
|
||||
if (uc == null) {
|
||||
uc = new TerminologyClientContextUseCount();
|
||||
useCounts.put(s,uc);
|
||||
}
|
||||
if (expand) {
|
||||
switch (useType) {
|
||||
case expand:
|
||||
uc.expands++;
|
||||
} else {
|
||||
break;
|
||||
case readVS:
|
||||
uc.readVS++;
|
||||
break;
|
||||
case validate:
|
||||
uc.validates++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public TerminologyCapabilities getTxcaps() {
|
||||
public TerminologyCapabilities getTxCapabilities() {
|
||||
return txcaps;
|
||||
}
|
||||
|
||||
public void setTxcaps(TerminologyCapabilities txcaps) {
|
||||
public void setTxCapabilities(TerminologyCapabilities txcaps) {
|
||||
this.txcaps = txcaps;
|
||||
}
|
||||
|
||||
|
@ -93,4 +124,65 @@ public class TerminologyClientContext {
|
|||
return getClient().getUseCount();
|
||||
}
|
||||
|
||||
public boolean isTxCaching() {
|
||||
return isTxCaching;
|
||||
}
|
||||
|
||||
public void setTxCaching(boolean isTxCaching) {
|
||||
this.isTxCaching = isTxCaching;
|
||||
}
|
||||
|
||||
public boolean usingCache() {
|
||||
return isTxCaching && cacheId != null;
|
||||
}
|
||||
|
||||
public String getCacheId() {
|
||||
return cacheId;
|
||||
}
|
||||
|
||||
public TerminologyCache getTxCache() {
|
||||
return txCache;
|
||||
}
|
||||
|
||||
public void setTxCache(TerminologyCache txCache) {
|
||||
this.txCache = txCache;
|
||||
}
|
||||
|
||||
public void initialize() throws IOException {
|
||||
if (!initialised) {
|
||||
// we don't cache the quick CS - we want to know that the server is with us.
|
||||
capabilitiesStatementQuick = client.getCapabilitiesStatementQuick();
|
||||
if (txCache != null && txCache.hasTerminologyCapabilities(getAddress())) {
|
||||
txcaps = txCache.getTerminologyCapabilities(getAddress());
|
||||
if (txcaps.getSoftware().hasVersion() && !txcaps.getSoftware().getVersion().equals(capabilitiesStatementQuick.getSoftware().getVersion())) {
|
||||
txcaps = null;
|
||||
}
|
||||
}
|
||||
if (txcaps == null) {
|
||||
txcaps = client.getTerminologyCapabilities();
|
||||
if (txCache != null) {
|
||||
txCache.cacheTerminologyCapabilities(getAddress(), txcaps);
|
||||
}
|
||||
}
|
||||
if (txcaps != null) {
|
||||
for (TerminologyCapabilitiesExpansionParameterComponent t : txcaps.getExpansion().getParameter()) {
|
||||
if ("cache-id".equals(t.getName())) {
|
||||
setTxCaching(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
initialised = true;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean supportsSystem(String system) throws IOException {
|
||||
initialize();
|
||||
for (TerminologyCapabilitiesCodeSystemComponent tccs : txcaps.getCodeSystem()) {
|
||||
if (system.equals(tccs.getUri())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import java.net.MalformedURLException;
|
|||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
@ -13,10 +14,19 @@ import java.util.Map;
|
|||
import java.util.Set;
|
||||
|
||||
import org.hl7.fhir.exceptions.TerminologyServiceException;
|
||||
import org.hl7.fhir.r5.context.CanonicalResourceManager;
|
||||
import org.hl7.fhir.r5.model.Bundle;
|
||||
import org.hl7.fhir.r5.model.Bundle.BundleEntryComponent;
|
||||
import org.hl7.fhir.r5.model.Parameters;
|
||||
import org.hl7.fhir.r5.model.Parameters.ParametersParameterComponent;
|
||||
import org.hl7.fhir.r5.model.TerminologyCapabilities.TerminologyCapabilitiesCodeSystemComponent;
|
||||
import org.hl7.fhir.r5.model.TerminologyCapabilities;
|
||||
import org.hl7.fhir.r5.model.ValueSet;
|
||||
import org.hl7.fhir.r5.terminologies.ValueSetUtilities;
|
||||
import org.hl7.fhir.r5.terminologies.client.TerminologyClientContext.TerminologyClientContextUseType;
|
||||
import org.hl7.fhir.r5.terminologies.utilities.TerminologyCache;
|
||||
import org.hl7.fhir.r5.terminologies.utilities.TerminologyCache.SourcedValueSet;
|
||||
import org.hl7.fhir.r5.utils.ToolingExtensions;
|
||||
import org.hl7.fhir.utilities.ToolingClientLogger;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.json.model.JsonObject;
|
||||
|
@ -28,15 +38,16 @@ public class TerminologyClientManager {
|
|||
}
|
||||
|
||||
public interface ITerminologyClientFactory {
|
||||
ITerminologyClient makeClient(String id, String url, String userAgent) throws URISyntaxException;
|
||||
ITerminologyClient makeClient(String id, String url, String userAgent, ToolingClientLogger logger) throws URISyntaxException;
|
||||
String getVersion();
|
||||
}
|
||||
|
||||
public static final String UNRESOLVED_VALUESET = "--unknown--";
|
||||
|
||||
private static final boolean IGNORE_TX_REGISTRY = false;
|
||||
|
||||
private ITerminologyClientFactory factory;
|
||||
private String cacheId;
|
||||
private boolean isTxCaching;
|
||||
private List<TerminologyClientContext> serverList = new ArrayList<>(); // clients by server address
|
||||
private Map<String, TerminologyClientContext> serverMap = new HashMap<>(); // clients by server address
|
||||
private Map<String, String> resMap = new HashMap<>(); // client resolution list
|
||||
|
@ -50,30 +61,18 @@ public class TerminologyClientManager {
|
|||
|
||||
private String monitorServiceURL;
|
||||
|
||||
public TerminologyClientManager(ITerminologyClientFactory factory) {
|
||||
public TerminologyClientManager(ITerminologyClientFactory factory, String cacheId) {
|
||||
super();
|
||||
this.factory = factory;
|
||||
this.cacheId = cacheId;
|
||||
}
|
||||
|
||||
public String getCacheId() {
|
||||
return cacheId;
|
||||
}
|
||||
|
||||
public void setCacheId(String cacheId) {
|
||||
this.cacheId = cacheId;
|
||||
}
|
||||
|
||||
public boolean isTxCaching() {
|
||||
return isTxCaching;
|
||||
}
|
||||
|
||||
public void setTxCaching(boolean isTxCaching) {
|
||||
this.isTxCaching = isTxCaching;
|
||||
}
|
||||
|
||||
public void copy(TerminologyClientManager other) {
|
||||
cacheId = other.cacheId;
|
||||
isTxCaching = other.isTxCaching;
|
||||
serverList.addAll(other.serverList);
|
||||
serverMap.putAll(other.serverMap);
|
||||
resMap.putAll(other.resMap);
|
||||
|
@ -82,10 +81,6 @@ public class TerminologyClientManager {
|
|||
usage = other.usage;
|
||||
}
|
||||
|
||||
public boolean usingCache() {
|
||||
return isTxCaching && cacheId != null;
|
||||
}
|
||||
|
||||
|
||||
public TerminologyClientContext chooseServer(Set<String> systems, boolean expand) throws TerminologyServiceException {
|
||||
if (serverList.isEmpty()) {
|
||||
|
@ -124,21 +119,25 @@ public class TerminologyClientManager {
|
|||
TerminologyClientContext client = serverMap.get(server);
|
||||
if (client == null) {
|
||||
try {
|
||||
client = new TerminologyClientContext(factory.makeClient("id"+(serverList.size()+1), server, getMasterClient().getUserAgent()), false);
|
||||
client = new TerminologyClientContext(factory.makeClient("id"+(serverList.size()+1), server, getMasterClient().getUserAgent(), getMasterClient().getLogger()), cacheId, false);
|
||||
} catch (URISyntaxException e) {
|
||||
throw new TerminologyServiceException(e);
|
||||
}
|
||||
client.setTxCache(cache);
|
||||
serverList.add(client);
|
||||
serverMap.put(server, client);
|
||||
}
|
||||
client.seeUse(s, expand);
|
||||
client.seeUse(s, expand ? TerminologyClientContextUseType.expand : TerminologyClientContextUseType.validate);
|
||||
return client;
|
||||
}
|
||||
|
||||
private String decideWhichServer(String url) {
|
||||
if (IGNORE_TX_REGISTRY) {
|
||||
return getMasterClient().getAddress();
|
||||
}
|
||||
if (expParameters != null) {
|
||||
if (!url.contains("|")) {
|
||||
// the client hasn''t specified an explicit version, but the expansion parameters might
|
||||
// the client hasn't specified an explicit version, but the expansion parameters might
|
||||
for (ParametersParameterComponent p : expParameters.getParameter()) {
|
||||
if (Utilities.existsInList(p.getName(), "system-version", "force-system-version") && p.hasValuePrimitive() && p.getValue().primitiveValue().startsWith(url+"|")) {
|
||||
url = p.getValue().primitiveValue();
|
||||
|
@ -153,7 +152,7 @@ public class TerminologyClientManager {
|
|||
}
|
||||
}
|
||||
}
|
||||
String request = Utilities.pathURL(monitorServiceURL, "resolve?fhirVersion="+factory.getVersion()+"&url="+url);
|
||||
String request = Utilities.pathURL(monitorServiceURL, "resolve?fhirVersion="+factory.getVersion()+"&url="+Utilities.URLEncode(url));
|
||||
if (usage != null) {
|
||||
request = request + "&usage="+usage;
|
||||
}
|
||||
|
@ -162,7 +161,7 @@ public class TerminologyClientManager {
|
|||
for (JsonObject item : json.getJsonObjects("authoritative")) {
|
||||
return item.asString("url");
|
||||
}
|
||||
for (JsonObject item : json.getJsonObjects("candidate")) {
|
||||
for (JsonObject item : json.getJsonObjects("candidates")) {
|
||||
return item.asString("url");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
@ -208,12 +207,14 @@ public class TerminologyClientManager {
|
|||
}
|
||||
}
|
||||
|
||||
public void setMasterClient(ITerminologyClient client) {
|
||||
TerminologyClientContext details = new TerminologyClientContext(client, true);
|
||||
public TerminologyClientContext setMasterClient(ITerminologyClient client) {
|
||||
TerminologyClientContext details = new TerminologyClientContext(client, cacheId, true);
|
||||
details.setTxCache(cache);
|
||||
serverList.clear();
|
||||
serverList.add(details);
|
||||
serverMap.put(client.getAddress(), details);
|
||||
monitorServiceURL = Utilities.pathURL(Utilities.getDirectoryForURL(client.getAddress()), "tx-reg");
|
||||
return details;
|
||||
}
|
||||
|
||||
public TerminologyClientContext getMaster() {
|
||||
|
@ -232,17 +233,9 @@ public class TerminologyClientManager {
|
|||
return map;
|
||||
}
|
||||
|
||||
public TerminologyCapabilities getTxCapabilities() {
|
||||
return hasClient() ? serverList.get(0).getTxcaps() : null;
|
||||
}
|
||||
|
||||
public void setTxCapabilities(TerminologyCapabilities txCaps) {
|
||||
serverList.get(0).setTxcaps(txCaps);
|
||||
}
|
||||
|
||||
public void setFactory(ITerminologyClientFactory factory) {
|
||||
this.factory = factory;
|
||||
System.out.println("tcc factory version = "+factory.getVersion());
|
||||
}
|
||||
|
||||
public void setCache(TerminologyCache cache) {
|
||||
|
@ -296,8 +289,6 @@ public class TerminologyClientManager {
|
|||
return monitorServiceURL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public Parameters getExpansionParameters() {
|
||||
return expParameters;
|
||||
}
|
||||
|
@ -314,4 +305,93 @@ public class TerminologyClientManager {
|
|||
this.usage = usage;
|
||||
}
|
||||
|
||||
public SourcedValueSet findValueSetOnServer(String canonical) {
|
||||
if (IGNORE_TX_REGISTRY || getMasterClient() == null) {
|
||||
return null;
|
||||
}
|
||||
String request = Utilities.pathURL(monitorServiceURL, "resolve?fhirVersion="+factory.getVersion()+"&valueSet="+Utilities.URLEncode(canonical));
|
||||
if (usage != null) {
|
||||
request = request + "&usage="+usage;
|
||||
}
|
||||
String server = null;
|
||||
try {
|
||||
JsonObject json = JsonParser.parseObjectFromUrl(request);
|
||||
for (JsonObject item : json.getJsonObjects("authoritative")) {
|
||||
if (server == null) {
|
||||
server = item.asString("url");
|
||||
}
|
||||
}
|
||||
for (JsonObject item : json.getJsonObjects("candidates")) {
|
||||
if (server == null) {
|
||||
server = item.asString("url");
|
||||
}
|
||||
}
|
||||
if (server == null) {
|
||||
return null;
|
||||
}
|
||||
if (server.contains("://tx.fhir.org")) {
|
||||
try {
|
||||
server = server.replace("tx.fhir.org", new URL(getMasterClient().getAddress()).getHost());
|
||||
} catch (MalformedURLException e) {
|
||||
}
|
||||
}
|
||||
TerminologyClientContext client = serverMap.get(server);
|
||||
if (client == null) {
|
||||
try {
|
||||
client = new TerminologyClientContext(factory.makeClient("id"+(serverList.size()+1), server, getMasterClient().getUserAgent(), getMasterClient().getLogger()), cacheId, false);
|
||||
} catch (URISyntaxException e) {
|
||||
throw new TerminologyServiceException(e);
|
||||
}
|
||||
client.setTxCache(cache);
|
||||
serverList.add(client);
|
||||
serverMap.put(server, client);
|
||||
}
|
||||
client.seeUse(canonical, TerminologyClientContextUseType.readVS);
|
||||
String criteria = canonical.contains("|") ?
|
||||
"?_format=json&url="+Utilities.URLEncode(canonical.substring(0, canonical.lastIndexOf("|")))+"&version="+Utilities.URLEncode(canonical.substring(canonical.lastIndexOf("|")+1)):
|
||||
"?_format=json&url="+Utilities.URLEncode(canonical);
|
||||
request = Utilities.pathURL(client.getAddress(), "ValueSet"+ criteria);
|
||||
Bundle bnd = client.getClient().search("ValueSet", criteria);
|
||||
String rid = null;
|
||||
if (bnd.getEntry().size() == 0) {
|
||||
return null;
|
||||
} else if (bnd.getEntry().size() > 1) {
|
||||
List<ValueSet> vslist = new ArrayList<>();
|
||||
for (BundleEntryComponent be : bnd.getEntry()) {
|
||||
if (be.hasResource() && be.getResource() instanceof ValueSet) {
|
||||
vslist.add((ValueSet) be.getResource());
|
||||
}
|
||||
}
|
||||
Collections.sort(vslist, new ValueSetUtilities.ValueSetSorter());
|
||||
rid = vslist.get(vslist.size()-1).getIdBase();
|
||||
} else {
|
||||
if (bnd.getEntryFirstRep().hasResource() && bnd.getEntryFirstRep().getResource() instanceof ValueSet) {
|
||||
rid = bnd.getEntryFirstRep().getResource().getIdBase();
|
||||
}
|
||||
}
|
||||
if (rid == null) {
|
||||
return null;
|
||||
}
|
||||
ValueSet vs = (ValueSet) client.getClient().read("ValueSet", rid);
|
||||
return new SourcedValueSet(server, vs);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
String msg = "Error resolving valueSet "+canonical+": "+e.getMessage()+" ("+request+")";
|
||||
if (!internalErrors.contains(msg)) {
|
||||
internalErrors.add(msg);
|
||||
}
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean supportsSystem(String system) throws IOException {
|
||||
for (TerminologyClientContext client : serverList) {
|
||||
if (client.supportsSystem(system)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ public class TerminologyClientR5 implements ITerminologyClient {
|
|||
public static class TerminologyClientR5Factory implements ITerminologyClientFactory {
|
||||
|
||||
@Override
|
||||
public ITerminologyClient makeClient(String id, String url, String userAgent) throws URISyntaxException {
|
||||
public ITerminologyClient makeClient(String id, String url, String userAgent, ToolingClientLogger logger) throws URISyntaxException {
|
||||
return new TerminologyClientR5(id, checkEndsWith("/r4", url), userAgent);
|
||||
}
|
||||
|
||||
|
@ -146,6 +146,11 @@ public class TerminologyClientR5 implements ITerminologyClient {
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ToolingClientLogger getLogger() {
|
||||
return client.getLogger();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITerminologyClient setLogger(ToolingClientLogger txLog) {
|
||||
client.setLogger(txLog);
|
||||
|
@ -246,4 +251,9 @@ public class TerminologyClientR5 implements ITerminologyClient {
|
|||
return new TerminologyClientR5Factory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bundle search(String type, String criteria) {
|
||||
return client.search(type, criteria);
|
||||
}
|
||||
|
||||
}
|
|
@ -166,6 +166,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
|
|||
|
||||
private boolean checkCodesWhenExpanding;
|
||||
private boolean includeAbstract = true;
|
||||
private boolean debug;
|
||||
|
||||
private AcceptLanguageHeader langs;
|
||||
private List<Token> designations = new ArrayList<>();
|
||||
|
@ -522,6 +523,32 @@ public class ValueSetExpander extends ValueSetProcessBase {
|
|||
}
|
||||
|
||||
|
||||
private void excludeCodeAndDescendents(WorkingContext wc, CodeSystem cs, String system, ConceptDefinitionComponent def, Parameters expParams, List<ValueSet> filters,
|
||||
ConceptDefinitionComponent exclusion, ConceptFilter filterFunc, List<WorkingContext> otherFilters, ValueSetExpansionComponent exp) throws FHIRException, ETooCostly {
|
||||
opContext.deadCheck();
|
||||
def.checkNoModifiers("Code in Code System", "expanding");
|
||||
if (exclusion != null) {
|
||||
if (exclusion.getCode().equals(def.getCode()))
|
||||
return; // excluded.
|
||||
}
|
||||
boolean abs = CodeSystemUtilities.isNotSelectable(cs, def);
|
||||
if ((includeAbstract || !abs) && filterFunc.includeConcept(cs, def) && passesOtherFilters(otherFilters, cs, def.getCode())) {
|
||||
for (String code : getCodesForConcept(def, expParams)) {
|
||||
if (!(filters != null && !filters.isEmpty() && !filterContainsCode(filters, system, code, exp)))
|
||||
excludeCode(wc, system, code);
|
||||
}
|
||||
}
|
||||
for (ConceptDefinitionComponent c : def.getConcept()) {
|
||||
excludeCodeAndDescendents(wc, cs, system, c, expParams, filters, exclusion, filterFunc, otherFilters, exp);
|
||||
}
|
||||
if (def.hasUserData(CodeSystemUtilities.USER_DATA_CROSS_LINK)) {
|
||||
List<ConceptDefinitionComponent> children = (List<ConceptDefinitionComponent>) def.getUserData(CodeSystemUtilities.USER_DATA_CROSS_LINK);
|
||||
for (ConceptDefinitionComponent c : children)
|
||||
excludeCodeAndDescendents(wc, cs, system, c, expParams, filters, exclusion, filterFunc, otherFilters, exp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private List<String> getCodesForConcept(ConceptDefinitionComponent focus, Parameters expParams) {
|
||||
List<String> codes = new ArrayList<>();
|
||||
codes.add(focus.getCode());
|
||||
|
@ -590,8 +617,20 @@ public class ValueSetExpander extends ValueSetProcessBase {
|
|||
excludeCode(wc, exc.getSystem(), c.getCode());
|
||||
}
|
||||
|
||||
if (exc.getFilter().size() > 0)
|
||||
throw fail("not done yet - multiple filters");
|
||||
if (exc.getFilter().size() > 0) {
|
||||
if (cs.getContent() == CodeSystemContentMode.FRAGMENT) {
|
||||
addFragmentWarning(exp, cs);
|
||||
}
|
||||
List<WorkingContext> filters = new ArrayList<>();
|
||||
for (int i = 1; i < exc.getFilter().size(); i++) {
|
||||
WorkingContext wc1 = new WorkingContext();
|
||||
filters.add(wc1);
|
||||
processFilter(exc, exp, expParams, null, cs, false, exc.getFilter().get(i), wc1, null, true);
|
||||
}
|
||||
ConceptSetFilterComponent fc = exc.getFilter().get(0);
|
||||
WorkingContext wc1 = dwc;
|
||||
processFilter(exc, exp, expParams, null, cs, false, fc, wc1, filters, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void excludeCodes(WorkingContext wc, ValueSetExpansionComponent expand) {
|
||||
|
@ -634,7 +673,9 @@ public class ValueSetExpander extends ValueSetProcessBase {
|
|||
} catch (ETooCostly e) {
|
||||
return new ValueSetExpansionOutcome(e.getMessage(), TerminologyServiceErrorClass.TOO_COSTLY, allErrors, false);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
if (debug) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
// well, we couldn't expand, so we'll return an interface to a checker that can check membership of the set
|
||||
// that might fail too, but it might not, later.
|
||||
return new ValueSetExpansionOutcome(e.getMessage(), TerminologyServiceErrorClass.UNKNOWN, allErrors, e instanceof EFhirClientException || e instanceof TerminologyServiceException);
|
||||
|
@ -814,7 +855,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
|
|||
private ValueSet importValueSet(WorkingContext wc, String value, ValueSetExpansionComponent exp, Parameters expParams, boolean noInactive, ValueSet valueSet) throws ETooCostly, TerminologyServiceException, FileNotFoundException, IOException, FHIRFormatError {
|
||||
if (value == null)
|
||||
throw fail("unable to find value set with no identity");
|
||||
ValueSet vs = context.fetchResource(ValueSet.class, value, valueSet);
|
||||
ValueSet vs = context.findTxResource(ValueSet.class, value, valueSet);
|
||||
if (vs == null) {
|
||||
if (context.fetchResource(CodeSystem.class, value, valueSet) != null) {
|
||||
throw fail("Cannot include value set "+value+" because it's actually a code system");
|
||||
|
@ -861,7 +902,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
|
|||
private ValueSet importValueSetForExclude(WorkingContext wc, String value, ValueSetExpansionComponent exp, Parameters expParams, boolean noInactive, ValueSet valueSet) throws ETooCostly, TerminologyServiceException, FileNotFoundException, IOException, FHIRFormatError {
|
||||
if (value == null)
|
||||
throw fail("unable to find value set with no identity");
|
||||
ValueSet vs = context.fetchResource(ValueSet.class, value, valueSet);
|
||||
ValueSet vs = context.findTxResource(ValueSet.class, value, valueSet);
|
||||
if (vs == null) {
|
||||
if (context.fetchResource(CodeSystem.class, value, valueSet) != null) {
|
||||
throw fail("Cannot include value set "+value+" because it's actually a code system");
|
||||
|
@ -1083,16 +1124,16 @@ public class ValueSetExpander extends ValueSetProcessBase {
|
|||
for (int i = 1; i < inc.getFilter().size(); i++) {
|
||||
WorkingContext wc = new WorkingContext();
|
||||
filters.add(wc);
|
||||
processFilter(inc, exp, expParams, imports, cs, noInactive, inc.getFilter().get(i), wc, null);
|
||||
processFilter(inc, exp, expParams, imports, cs, noInactive, inc.getFilter().get(i), wc, null, false);
|
||||
}
|
||||
ConceptSetFilterComponent fc = inc.getFilter().get(0);
|
||||
WorkingContext wc = dwc;
|
||||
processFilter(inc, exp, expParams, imports, cs, noInactive, fc, wc, filters);
|
||||
processFilter(inc, exp, expParams, imports, cs, noInactive, fc, wc, filters, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void processFilter(ConceptSetComponent inc, ValueSetExpansionComponent exp, Parameters expParams,
|
||||
List<ValueSet> imports, CodeSystem cs, boolean noInactive, ConceptSetFilterComponent fc, WorkingContext wc, List<WorkingContext> filters)
|
||||
private void processFilter(ConceptSetComponent inc, ValueSetExpansionComponent exp, Parameters expParams, List<ValueSet> imports, CodeSystem cs, boolean noInactive,
|
||||
ConceptSetFilterComponent fc, WorkingContext wc, List<WorkingContext> filters, boolean exclude)
|
||||
throws ETooCostly {
|
||||
opContext.deadCheck();
|
||||
if ("concept".equals(fc.getProperty()) && fc.getOp() == FilterOperator.ISA) {
|
||||
|
@ -1100,14 +1141,22 @@ public class ValueSetExpander extends ValueSetProcessBase {
|
|||
ConceptDefinitionComponent def = getConceptForCode(cs.getConcept(), fc.getValue());
|
||||
if (def == null)
|
||||
throw failTSE("Code '" + fc.getValue() + "' not found in system '" + inc.getSystem() + "'");
|
||||
addCodeAndDescendents(wc, cs, inc.getSystem(), def, null, expParams, imports, null, new AllConceptsFilter(allErrors), noInactive, exp.getProperty(), filters, exp);
|
||||
if (exclude) {
|
||||
excludeCodeAndDescendents(wc, cs, inc.getSystem(), def, null, imports, null, new AllConceptsFilter(allErrors), filters, exp);
|
||||
} else {
|
||||
addCodeAndDescendents(wc, cs, inc.getSystem(), def, null, expParams, imports, null, new AllConceptsFilter(allErrors), noInactive, exp.getProperty(), filters, exp);
|
||||
}
|
||||
} else if ("concept".equals(fc.getProperty()) && fc.getOp() == FilterOperator.ISNOTA) {
|
||||
// special: all codes in the target code system that are not under the value
|
||||
ConceptDefinitionComponent defEx = getConceptForCode(cs.getConcept(), fc.getValue());
|
||||
if (defEx == null)
|
||||
throw failTSE("Code '" + fc.getValue() + "' not found in system '" + inc.getSystem() + "'");
|
||||
for (ConceptDefinitionComponent def : cs.getConcept()) {
|
||||
addCodeAndDescendents(wc, cs, inc.getSystem(), def, null, expParams, imports, defEx, new AllConceptsFilter(allErrors), noInactive, exp.getProperty(), filters, exp);
|
||||
if (exclude) {
|
||||
excludeCodeAndDescendents(wc, cs, inc.getSystem(), def, null, imports, defEx, new AllConceptsFilter(allErrors), filters, exp);
|
||||
} else {
|
||||
addCodeAndDescendents(wc, cs, inc.getSystem(), def, null, expParams, imports, defEx, new AllConceptsFilter(allErrors), noInactive, exp.getProperty(), filters, exp);
|
||||
}
|
||||
}
|
||||
} else if ("concept".equals(fc.getProperty()) && fc.getOp() == FilterOperator.DESCENDENTOF) {
|
||||
// special: all codes in the target code system under the value
|
||||
|
@ -1115,11 +1164,20 @@ public class ValueSetExpander extends ValueSetProcessBase {
|
|||
if (def == null)
|
||||
throw failTSE("Code '" + fc.getValue() + "' not found in system '" + inc.getSystem() + "'");
|
||||
for (ConceptDefinitionComponent c : def.getConcept())
|
||||
addCodeAndDescendents(wc, cs, inc.getSystem(), c, null, expParams, imports, null, new AllConceptsFilter(allErrors), noInactive, exp.getProperty(), filters, exp);
|
||||
if (exclude) {
|
||||
excludeCodeAndDescendents(wc, cs, inc.getSystem(), c, null, imports, null, new AllConceptsFilter(allErrors), filters, exp);
|
||||
} else {
|
||||
addCodeAndDescendents(wc, cs, inc.getSystem(), c, null, expParams, imports, null, new AllConceptsFilter(allErrors), noInactive, exp.getProperty(), filters, exp);
|
||||
}
|
||||
if (def.hasUserData(CodeSystemUtilities.USER_DATA_CROSS_LINK)) {
|
||||
List<ConceptDefinitionComponent> children = (List<ConceptDefinitionComponent>) def.getUserData(CodeSystemUtilities.USER_DATA_CROSS_LINK);
|
||||
for (ConceptDefinitionComponent c : children)
|
||||
addCodeAndDescendents(wc, cs, inc.getSystem(), c, null, expParams, imports, null, new AllConceptsFilter(allErrors), noInactive, exp.getProperty(), filters, exp);
|
||||
for (ConceptDefinitionComponent c : children) {
|
||||
if (exclude) {
|
||||
excludeCodeAndDescendents(wc, cs, inc.getSystem(), c, null, imports, null, new AllConceptsFilter(allErrors), filters, exp);
|
||||
} else {
|
||||
addCodeAndDescendents(wc, cs, inc.getSystem(), c, null, expParams, imports, null, new AllConceptsFilter(allErrors), noInactive, exp.getProperty(), filters, exp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if ("display".equals(fc.getProperty()) && fc.getOp() == FilterOperator.EQUAL) {
|
||||
|
@ -1131,19 +1189,31 @@ public class ValueSetExpander extends ValueSetProcessBase {
|
|||
if (def.getDisplay().contains(fc.getValue()) && passesOtherFilters(filters, cs, def.getCode())) {
|
||||
for (String code : getCodesForConcept(def, expParams)) {
|
||||
opContext.deadCheck();
|
||||
ValueSetExpansionContainsComponent t = addCode(wc, inc.getSystem(), code, def.getDisplay(), cs.getLanguage(), null, def.getDesignation(), expParams, CodeSystemUtilities.isNotSelectable(cs, def), CodeSystemUtilities.isInactive(cs, def),
|
||||
if (exclude) {
|
||||
excludeCode(wc, inc.getSystem(), code);
|
||||
} else {
|
||||
addCode(wc, inc.getSystem(), code, def.getDisplay(), cs.getLanguage(), null, def.getDesignation(), expParams, CodeSystemUtilities.isNotSelectable(cs, def), CodeSystemUtilities.isInactive(cs, def),
|
||||
imports, noInactive, false, exp.getProperty(), makeCSProps(def.getDefinition(), def.getProperty()), cs, null, def.getExtension(), null, exp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (isDefinedProperty(cs, fc.getProperty())) {
|
||||
for (ConceptDefinitionComponent def : cs.getConcept()) {
|
||||
addCodeAndDescendents(wc, cs, inc.getSystem(), def, null, expParams, imports, null, new PropertyFilter(allErrors, fc, getPropertyDefinition(cs, fc.getProperty())), noInactive, exp.getProperty(), filters, exp);
|
||||
if (exclude) {
|
||||
excludeCodeAndDescendents(wc, cs, inc.getSystem(), def, null, imports, null, new PropertyFilter(allErrors, fc, getPropertyDefinition(cs, fc.getProperty())), filters, exp);
|
||||
} else {
|
||||
addCodeAndDescendents(wc, cs, inc.getSystem(), def, null, expParams, imports, null, new PropertyFilter(allErrors, fc, getPropertyDefinition(cs, fc.getProperty())), noInactive, exp.getProperty(), filters, exp);
|
||||
}
|
||||
}
|
||||
} else if ("code".equals(fc.getProperty()) && fc.getOp() == FilterOperator.REGEX) {
|
||||
for (ConceptDefinitionComponent def : cs.getConcept()) {
|
||||
addCodeAndDescendents(wc, cs, inc.getSystem(), def, null, expParams, imports, null, new RegexFilter(allErrors, fc.getValue()), noInactive, exp.getProperty(), filters, exp);
|
||||
if (exclude) {
|
||||
excludeCodeAndDescendents(wc, cs, inc.getSystem(), def, null, imports, null, new RegexFilter(allErrors, fc.getValue()), filters, exp);
|
||||
} else {
|
||||
addCodeAndDescendents(wc, cs, inc.getSystem(), def, null, expParams, imports, null, new RegexFilter(allErrors, fc.getValue()), noInactive, exp.getProperty(), filters, exp);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw fail("Filter by property[" + fc.getProperty() + "] and op[" + fc.getOp() + "] is not supported yet");
|
||||
|
@ -1258,4 +1328,15 @@ public class ValueSetExpander extends ValueSetProcessBase {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isDebug() {
|
||||
return debug;
|
||||
}
|
||||
|
||||
public ValueSetExpander setDebug(boolean debug) {
|
||||
this.debug = debug;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -32,6 +32,7 @@ package org.hl7.fhir.r5.terminologies.utilities;
|
|||
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
@ -43,7 +44,9 @@ import lombok.Setter;
|
|||
import lombok.experimental.Accessors;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.FHIRFormatError;
|
||||
import org.hl7.fhir.r5.formats.IParser.OutputStyle;
|
||||
import org.hl7.fhir.r5.context.ILoggingService.LogCategory;
|
||||
import org.hl7.fhir.r5.formats.JsonParser;
|
||||
import org.hl7.fhir.r5.model.*;
|
||||
import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent;
|
||||
|
@ -52,9 +55,14 @@ import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent;
|
|||
import org.hl7.fhir.r5.model.ValueSet.ConceptSetFilterComponent;
|
||||
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent;
|
||||
import org.hl7.fhir.r5.terminologies.expansion.ValueSetExpansionOutcome;
|
||||
import org.hl7.fhir.r5.terminologies.utilities.TerminologyCache.SourcedValueSet;
|
||||
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
|
||||
import org.hl7.fhir.utilities.IniFile;
|
||||
import org.hl7.fhir.utilities.StringPair;
|
||||
import org.hl7.fhir.utilities.TextFile;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.json.model.JsonNull;
|
||||
import org.hl7.fhir.utilities.json.model.JsonProperty;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||
import org.hl7.fhir.utilities.validation.ValidationOptions;
|
||||
|
||||
|
@ -74,6 +82,44 @@ import com.google.gson.JsonPrimitive;
|
|||
*/
|
||||
public class TerminologyCache {
|
||||
|
||||
public static class SourcedValueSet {
|
||||
private String server;
|
||||
private ValueSet vs;
|
||||
|
||||
public SourcedValueSet(String server, ValueSet vs) {
|
||||
super();
|
||||
this.server = server;
|
||||
this.vs = vs;
|
||||
}
|
||||
public String getServer() {
|
||||
return server;
|
||||
}
|
||||
public ValueSet getVs() {
|
||||
return vs;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static class SourcedValueSetEntry {
|
||||
private String server;
|
||||
private String filename;
|
||||
|
||||
public SourcedValueSetEntry(String server, String filename) {
|
||||
super();
|
||||
this.server = server;
|
||||
this.filename = filename;
|
||||
}
|
||||
public String getServer() {
|
||||
return server;
|
||||
}
|
||||
public String getFilename() {
|
||||
return filename;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static final boolean TRANSIENT = false;
|
||||
public static final boolean PERMANENT = true;
|
||||
private static final String NAME_FOR_NO_SYSTEM = "all-systems";
|
||||
|
@ -82,6 +128,7 @@ public class TerminologyCache {
|
|||
private static final String CACHE_FILE_EXTENSION = ".cache";
|
||||
private static final String CAPABILITY_STATEMENT_TITLE = ".capabilityStatement";
|
||||
private static final String TERMINOLOGY_CAPABILITIES_TITLE = ".terminologyCapabilities";
|
||||
private static final String FIXED_CACHE_VERSION = "3"; // last change: when multiple servers were introduced
|
||||
|
||||
|
||||
private SystemNameKeyGenerator systemNameKeyGenerator = new SystemNameKeyGenerator();
|
||||
|
@ -189,9 +236,11 @@ public class TerminologyCache {
|
|||
@Getter private int requestCount;
|
||||
@Getter private int hitCount;
|
||||
@Getter private int networkCount;
|
||||
private CapabilityStatement capabilityStatementCache = null;
|
||||
private TerminologyCapabilities terminologyCapabilitiesCache = null;
|
||||
private Map<String, CapabilityStatement> capabilityStatementCache = new HashMap<>();
|
||||
private Map<String, TerminologyCapabilities> terminologyCapabilitiesCache = new HashMap<>();
|
||||
private Map<String, NamedCache> caches = new HashMap<String, NamedCache>();
|
||||
private Map<String, SourcedValueSetEntry> vsCache = new HashMap<>();
|
||||
private Map<String, String> serverMap = new HashMap<>();
|
||||
@Getter @Setter private static boolean noCaching;
|
||||
|
||||
@Getter @Setter private static boolean cacheErrors;
|
||||
|
@ -201,54 +250,105 @@ public class TerminologyCache {
|
|||
public TerminologyCache(Object lock, String folder) throws FileNotFoundException, IOException, FHIRException {
|
||||
super();
|
||||
this.lock = lock;
|
||||
if (folder == null) {
|
||||
folder = Utilities.path("[tmp]", "default-tx-cache");
|
||||
}
|
||||
this.folder = folder;
|
||||
requestCount = 0;
|
||||
hitCount = 0;
|
||||
networkCount = 0;
|
||||
|
||||
if (folder != null) {
|
||||
load();
|
||||
|
||||
File f = new File(folder);
|
||||
if (!f.exists()) {
|
||||
Utilities.createDirectory(folder);
|
||||
}
|
||||
if (!f.exists()) {
|
||||
throw new IOException("Unable to create terminology cache at "+folder);
|
||||
}
|
||||
checkVersion();
|
||||
load();
|
||||
}
|
||||
|
||||
private void checkVersion() throws IOException {
|
||||
File verFile = new File(Utilities.path(folder, "version.ctl"));
|
||||
if (verFile.exists()) {
|
||||
String ver = TextFile.fileToString(verFile);
|
||||
if (!ver.equals(FIXED_CACHE_VERSION)) {
|
||||
System.out.println("Terminology Cache Version has changed from 1 to "+FIXED_CACHE_VERSION+", so clearing txCache");
|
||||
clear();
|
||||
}
|
||||
TextFile.stringToFile(FIXED_CACHE_VERSION, verFile);
|
||||
} else {
|
||||
TextFile.stringToFile(FIXED_CACHE_VERSION, verFile);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasCapabilityStatement() {
|
||||
return capabilityStatementCache != null;
|
||||
public String getServerId(String address) throws IOException {
|
||||
if (serverMap.containsKey(address)) {
|
||||
return serverMap.get(address);
|
||||
}
|
||||
String id = address.replace("http://", "").replace("https://", "").replace("/", ".");
|
||||
int i = 1;
|
||||
while (serverMap.containsValue(id)) {
|
||||
i++;
|
||||
id = address.replace("https:", "").replace("https:", "").replace("/", ".")+i;
|
||||
}
|
||||
serverMap.put(address, id);
|
||||
if (folder != null) {
|
||||
IniFile ini = new IniFile(Utilities.path(folder, "servers.ini"));
|
||||
ini.setStringProperty("servers", id, address, null);
|
||||
ini.save();
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
public void unload() {
|
||||
// not useable after this is called
|
||||
caches.clear();
|
||||
vsCache.clear();
|
||||
}
|
||||
|
||||
private void clear() throws IOException {
|
||||
Utilities.clearDirectory(folder);
|
||||
caches.clear();
|
||||
vsCache.clear();
|
||||
}
|
||||
|
||||
public boolean hasCapabilityStatement(String address) {
|
||||
return capabilityStatementCache.containsKey(address);
|
||||
}
|
||||
|
||||
public CapabilityStatement getCapabilityStatement() {
|
||||
return capabilityStatementCache;
|
||||
public CapabilityStatement getCapabilityStatement(String address) {
|
||||
return capabilityStatementCache.get(address);
|
||||
}
|
||||
|
||||
public void cacheCapabilityStatement(CapabilityStatement capabilityStatement) {
|
||||
public void cacheCapabilityStatement(String address, CapabilityStatement capabilityStatement) throws IOException {
|
||||
if (noCaching) {
|
||||
return;
|
||||
}
|
||||
this.capabilityStatementCache = capabilityStatement;
|
||||
save(capabilityStatementCache, CAPABILITY_STATEMENT_TITLE);
|
||||
this.capabilityStatementCache.put(address, capabilityStatement);
|
||||
save(capabilityStatement, CAPABILITY_STATEMENT_TITLE+"."+getServerId(address));
|
||||
}
|
||||
|
||||
|
||||
public boolean hasTerminologyCapabilities() {
|
||||
return terminologyCapabilitiesCache != null;
|
||||
public boolean hasTerminologyCapabilities(String address) {
|
||||
return terminologyCapabilitiesCache.containsKey(address);
|
||||
}
|
||||
|
||||
public TerminologyCapabilities getTerminologyCapabilities() {
|
||||
return terminologyCapabilitiesCache;
|
||||
public TerminologyCapabilities getTerminologyCapabilities(String address) {
|
||||
return terminologyCapabilitiesCache.get(address);
|
||||
}
|
||||
|
||||
public void cacheTerminologyCapabilities(TerminologyCapabilities terminologyCapabilities) {
|
||||
public void cacheTerminologyCapabilities(String address, TerminologyCapabilities terminologyCapabilities) throws IOException {
|
||||
if (noCaching) {
|
||||
return;
|
||||
}
|
||||
this.terminologyCapabilitiesCache = terminologyCapabilities;
|
||||
save(terminologyCapabilitiesCache, TERMINOLOGY_CAPABILITIES_TITLE);
|
||||
this.terminologyCapabilitiesCache.put(address, terminologyCapabilities);
|
||||
save(terminologyCapabilities, TERMINOLOGY_CAPABILITIES_TITLE+"."+getServerId(address));
|
||||
}
|
||||
|
||||
|
||||
public void clear() {
|
||||
caches.clear();
|
||||
}
|
||||
|
||||
public CacheToken generateValidationToken(ValidationOptions options, Coding code, ValueSet vs, Parameters expParameters) {
|
||||
try {
|
||||
CacheToken ct = new CacheToken();
|
||||
|
@ -614,14 +714,19 @@ public class TerminologyCache {
|
|||
private void loadCapabilityCache(String fn) {
|
||||
try {
|
||||
String src = TextFile.fileToString(Utilities.path(folder, fn));
|
||||
String serverId = Utilities.getFileNameForName(fn).replace(CACHE_FILE_EXTENSION, "");
|
||||
serverId = serverId.substring(serverId.indexOf(".")+1);
|
||||
serverId = serverId.substring(serverId.indexOf(".")+1);
|
||||
String address = getServerForId(serverId);
|
||||
if (address != null) {
|
||||
JsonObject o = (JsonObject) new com.google.gson.JsonParser().parse(src);
|
||||
Resource resource = new JsonParser().parse(o);
|
||||
|
||||
JsonObject o = (JsonObject) new com.google.gson.JsonParser().parse(src);
|
||||
Resource resource = new JsonParser().parse(o);
|
||||
|
||||
if (fn.startsWith(CAPABILITY_STATEMENT_TITLE)) {
|
||||
this.capabilityStatementCache = (CapabilityStatement) resource;
|
||||
} else if (fn.startsWith(TERMINOLOGY_CAPABILITIES_TITLE)) {
|
||||
this.terminologyCapabilitiesCache = (TerminologyCapabilities) resource;
|
||||
if (fn.startsWith(CAPABILITY_STATEMENT_TITLE)) {
|
||||
this.capabilityStatementCache.put(address, (CapabilityStatement) resource);
|
||||
} else if (fn.startsWith(TERMINOLOGY_CAPABILITIES_TITLE)) {
|
||||
this.terminologyCapabilitiesCache.put(address, (TerminologyCapabilities) resource);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
@ -629,6 +734,15 @@ public class TerminologyCache {
|
|||
}
|
||||
}
|
||||
|
||||
private String getServerForId(String serverId) {
|
||||
for (String n : serverMap.keySet()) {
|
||||
if (serverMap.get(n).equals(serverId)) {
|
||||
return n;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private CacheEntry getCacheEntry(String request, String resultString) throws IOException {
|
||||
CacheEntry ce = new CacheEntry();
|
||||
ce.persistent = true;
|
||||
|
@ -703,7 +817,14 @@ public class TerminologyCache {
|
|||
}
|
||||
}
|
||||
|
||||
private void load() throws FHIRException {
|
||||
private void load() throws FHIRException, IOException {
|
||||
IniFile ini = new IniFile(Utilities.path(folder, "servers.ini"));
|
||||
if (ini.hasSection("servers")) {
|
||||
for (String n : ini.getPropertyNames("servers")) {
|
||||
serverMap.put(ini.getStringProperty("servers", n), n);
|
||||
}
|
||||
}
|
||||
|
||||
for (String fn : new File(folder).list()) {
|
||||
if (fn.endsWith(CACHE_FILE_EXTENSION) && !fn.equals("validation" + CACHE_FILE_EXTENSION)) {
|
||||
try {
|
||||
|
@ -717,6 +838,22 @@ public class TerminologyCache {
|
|||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
File f = new File(Utilities.path(folder, "vs-externals.json"));
|
||||
if (f.exists()) {
|
||||
org.hl7.fhir.utilities.json.model.JsonObject json = org.hl7.fhir.utilities.json.parser.JsonParser.parseObject(f);
|
||||
for (JsonProperty p : json.getProperties()) {
|
||||
if (p.getValue().isJsonNull()) {
|
||||
vsCache.put(p.getName(), null);
|
||||
} else {
|
||||
org.hl7.fhir.utilities.json.model.JsonObject j = p.getValue().asJsonObject();
|
||||
vsCache.put(p.getName(), new SourcedValueSetEntry(j.asString("server"), j.asString("filename")));
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println("Error loading vs external cache: "+e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private String loadJS(JsonElement e) {
|
||||
|
@ -819,5 +956,55 @@ public class TerminologyCache {
|
|||
return servers;
|
||||
}
|
||||
|
||||
public boolean hasValueSet(String canonical) {
|
||||
return vsCache.containsKey(canonical);
|
||||
}
|
||||
|
||||
public SourcedValueSet getValueSet(String canonical) {
|
||||
SourcedValueSetEntry sp = vsCache.get(canonical);
|
||||
if (sp == null) {
|
||||
return null;
|
||||
} else {
|
||||
try {
|
||||
return new SourcedValueSet(sp.getServer(), sp.getFilename() == null ? null : (ValueSet) new JsonParser().parse(new FileInputStream(Utilities.path(folder, sp.getFilename()))));
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void cacheValueSet(String canonical, SourcedValueSet svs) {
|
||||
if (canonical == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (svs == null) {
|
||||
vsCache.put(canonical, null);
|
||||
} else {
|
||||
String uuid = Utilities.makeUuidLC();
|
||||
String fn = "vs-"+uuid+".json";
|
||||
new JsonParser().compose(new FileOutputStream(Utilities.path(folder, fn)), svs.getVs());
|
||||
vsCache.put(canonical, new SourcedValueSetEntry(svs.getServer(), fn));
|
||||
}
|
||||
org.hl7.fhir.utilities.json.model.JsonObject j = new org.hl7.fhir.utilities.json.model.JsonObject();
|
||||
for (String k : vsCache.keySet()) {
|
||||
SourcedValueSetEntry sve = vsCache.get(k);
|
||||
if (sve == null) {
|
||||
j.add(k, new JsonNull());
|
||||
} else {
|
||||
org.hl7.fhir.utilities.json.model.JsonObject e = new org.hl7.fhir.utilities.json.model.JsonObject();
|
||||
e.set("server", sve.getServer());
|
||||
if (sve.getFilename() != null) {
|
||||
e.set("filename", sve.getFilename());
|
||||
}
|
||||
j.add(k, e);
|
||||
}
|
||||
}
|
||||
org.hl7.fhir.utilities.json.parser.JsonParser.compose(j, new File(Utilities.path(folder, "vs-externals.json")), true);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -148,6 +148,21 @@ public class ValidationResult {
|
|||
return CommaSeparatedStringBuilder.join("; ", messages);
|
||||
}
|
||||
|
||||
public String getTrimmedMessage() {
|
||||
List<String> toTrim = new ArrayList<>();
|
||||
for (OperationOutcomeIssueComponent iss : getIssues()) {
|
||||
toTrim.add(iss.getDetails().getText());
|
||||
}
|
||||
List<String> trimmed = new ArrayList<>();
|
||||
trimmed.addAll(messages);
|
||||
trimmed.removeAll(toTrim);
|
||||
if (trimmed.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
Collections.sort(trimmed);
|
||||
return CommaSeparatedStringBuilder.join("; ", trimmed);
|
||||
}
|
||||
|
||||
public boolean IsNoService() {
|
||||
return errorClass == TerminologyServiceErrorClass.NOSERVICE;
|
||||
}
|
||||
|
|
|
@ -57,4 +57,23 @@ public class ValidationProcessInfo {
|
|||
Collections.sort(msgs);
|
||||
return msgs;
|
||||
}
|
||||
|
||||
public boolean hasMessage(String msg) {
|
||||
for (OperationOutcomeIssueComponent iss : issues) {
|
||||
if (msg.equals(iss.getDetails().getText())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean hasNotFound(String system) {
|
||||
for (OperationOutcomeIssueComponent iss : issues) {
|
||||
if (iss.getDetails().hasCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", "not-found") &&
|
||||
iss.getDetails().hasText() && iss.getDetails().getText().contains(system)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
package org.hl7.fhir.r5.terminologies.validation;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/*
|
||||
Copyright (c) 2011+, HL7, Inc.
|
||||
All rights reserved.
|
||||
|
@ -58,6 +60,7 @@ import org.hl7.fhir.r5.model.CodeableConcept;
|
|||
import org.hl7.fhir.r5.model.Coding;
|
||||
import org.hl7.fhir.r5.model.DataType;
|
||||
import org.hl7.fhir.r5.model.Extension;
|
||||
import org.hl7.fhir.r5.model.NamingSystem;
|
||||
import org.hl7.fhir.r5.model.Enumerations.PublicationStatus;
|
||||
import org.hl7.fhir.r5.model.OperationOutcome.IssueType;
|
||||
import org.hl7.fhir.r5.model.OperationOutcome.OperationOutcomeIssueComponent;
|
||||
|
@ -75,6 +78,7 @@ import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent;
|
|||
import org.hl7.fhir.r5.model.ValueSet.ConceptSetFilterComponent;
|
||||
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent;
|
||||
import org.hl7.fhir.r5.terminologies.CodeSystemUtilities;
|
||||
import org.hl7.fhir.r5.terminologies.client.TerminologyClientManager;
|
||||
import org.hl7.fhir.r5.terminologies.expansion.ValueSetExpansionOutcome;
|
||||
import org.hl7.fhir.r5.terminologies.providers.CodeSystemProvider;
|
||||
import org.hl7.fhir.r5.terminologies.providers.SpecialCodeSystem;
|
||||
|
@ -130,27 +134,28 @@ public class ValueSetValidator extends ValueSetProcessBase {
|
|||
private ValidationContextCarrier localContext;
|
||||
private List<CodeSystem> localSystems = new ArrayList<>();
|
||||
protected Parameters expansionProfile;
|
||||
private TerminologyCapabilities txCaps;
|
||||
private TerminologyClientManager tcm;
|
||||
private Set<String> unknownSystems;
|
||||
private Set<String> unknownValueSets = new HashSet<>();
|
||||
private boolean throwToServer;
|
||||
|
||||
public ValueSetValidator(IWorkerContext context, TerminologyOperationContext opContext, ValidationOptions options, ValueSet source, Parameters expansionProfile, TerminologyCapabilities txCaps) {
|
||||
public ValueSetValidator(IWorkerContext context, TerminologyOperationContext opContext, ValidationOptions options, ValueSet source, Parameters expansionProfile, TerminologyClientManager tcm) {
|
||||
super(context, opContext);
|
||||
this.valueset = source;
|
||||
this.options = options;
|
||||
this.expansionProfile = expansionProfile;
|
||||
this.txCaps = txCaps;
|
||||
this.tcm = tcm;
|
||||
analyseValueSet();
|
||||
}
|
||||
|
||||
public ValueSetValidator(IWorkerContext context, TerminologyOperationContext opContext, ValidationOptions options, ValueSet source, ValidationContextCarrier ctxt, Parameters expansionProfile, TerminologyCapabilities txCaps) {
|
||||
public ValueSetValidator(IWorkerContext context, TerminologyOperationContext opContext, ValidationOptions options, ValueSet source, ValidationContextCarrier ctxt, Parameters expansionProfile, TerminologyClientManager tcm) {
|
||||
super(context, opContext);
|
||||
this.valueset = source;
|
||||
this.options = options.copy();
|
||||
this.options.setEnglishOk(true);
|
||||
this.localContext = ctxt;
|
||||
this.expansionProfile = expansionProfile;
|
||||
this.txCaps = txCaps;
|
||||
this.tcm = tcm;
|
||||
analyseValueSet();
|
||||
}
|
||||
|
||||
|
@ -249,16 +254,20 @@ public class ValueSetValidator extends ValueSetProcessBase {
|
|||
}
|
||||
} else {
|
||||
res = context.validateCode(options.withNoClient(), c, null);
|
||||
if (res.isOk()) {
|
||||
vcc.addCoding(new Coding().setCode(res.getCode()).setVersion(res.getVersion()).setSystem(res.getSystem()).setDisplay(res.getDisplay()));
|
||||
}
|
||||
for (OperationOutcomeIssueComponent iss : res.getIssues()) {
|
||||
if (iss.getSeverity() == org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.ERROR && iss.getDetails().hasCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", "not-found")) {
|
||||
iss.setSeverity(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.WARNING);
|
||||
res.setSeverity(IssueSeverity.WARNING);
|
||||
}
|
||||
iss.resetPath("Coding", path+".coding["+i+"]");
|
||||
}
|
||||
if (res.isInactive()) {
|
||||
String msg = context.formatMessage(I18nConstants.STATUS_CODE_WARNING_CODE, "not active", c.getCode());
|
||||
res.getIssues().addAll(makeIssue(IssueSeverity.INFORMATION, IssueType.INVALID, path+".coding["+i+"].code", msg, OpIssueCode.CodeRule, res.getServer()));
|
||||
}
|
||||
if (res.isOk()) {
|
||||
vcc.addCoding(new Coding().setCode(res.getCode()).setVersion(res.getVersion()).setSystem(res.getSystem()).setDisplay(res.getDisplay()));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
c.setUserData("cs", cs);
|
||||
|
@ -314,8 +323,12 @@ public class ValueSetValidator extends ValueSetProcessBase {
|
|||
i++;
|
||||
}
|
||||
if (result == null) {
|
||||
msg = context.formatMessage(I18nConstants.UNABLE_TO_CHECK_IF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_, valueset.getVersionedUrl(), b.toString());
|
||||
info.getIssues().addAll(makeIssue(IssueSeverity.WARNING, unknownSystems.isEmpty() ? IssueType.CODEINVALID : IssueType.NOTFOUND, cpath.size() == 1 ? cpath.get(0) : path, msg, OpIssueCode.VSProcessing, null));
|
||||
if (!unknownValueSets.isEmpty()) {
|
||||
msg = context.formatMessage(I18nConstants.UNABLE_TO_CHECK_IF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_VS, valueset.getVersionedUrl(), CommaSeparatedStringBuilder.join(", ", unknownValueSets));
|
||||
} else {
|
||||
msg = context.formatMessage(I18nConstants.UNABLE_TO_CHECK_IF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_CS, valueset.getVersionedUrl(), b.toString());
|
||||
}
|
||||
info.getIssues().addAll(makeIssue(IssueSeverity.WARNING, unknownSystems.isEmpty() && unknownValueSets.isEmpty() ? IssueType.CODEINVALID : IssueType.NOTFOUND, null, msg, OpIssueCode.VSProcessing, null));
|
||||
} else if (!result) {
|
||||
// to match Ontoserver
|
||||
OperationOutcomeIssueComponent iss = new OperationOutcomeIssueComponent(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.ERROR, org.hl7.fhir.r5.model.OperationOutcome.IssueType.CODEINVALID);
|
||||
|
@ -629,9 +642,18 @@ public class ValueSetValidator extends ValueSetProcessBase {
|
|||
res.setErrorClass(info.getErr());
|
||||
}
|
||||
if (ok == null) {
|
||||
String m = context.formatMessage(I18nConstants.UNABLE_TO_CHECK_IF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_, valueset.getVersionedUrl(), CommaSeparatedStringBuilder.join(",", unknownSystems));
|
||||
String m = null;
|
||||
if (!unknownSystems.isEmpty()) {
|
||||
m = context.formatMessage(I18nConstants.UNABLE_TO_CHECK_IF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_CS, valueset.getVersionedUrl(), CommaSeparatedStringBuilder.join(",", unknownSystems));
|
||||
} else if (!unknownValueSets.isEmpty()) {
|
||||
res.addMessage(info.getIssues().get(0).getDetails().getText());
|
||||
m = context.formatMessage(I18nConstants.UNABLE_TO_CHECK_IF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_VS, valueset.getVersionedUrl(), CommaSeparatedStringBuilder.join(",", unknownValueSets));
|
||||
} else {
|
||||
// not sure why we'd get to here?
|
||||
m = context.formatMessage(I18nConstants.UNABLE_TO_CHECK_IF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_, valueset.getVersionedUrl());
|
||||
}
|
||||
res.addMessage(m);
|
||||
res.getIssues().addAll(makeIssue(IssueSeverity.WARNING, IssueType.NOTFOUND, path, m, OpIssueCode.VSProcessing, null));
|
||||
res.getIssues().addAll(makeIssue(IssueSeverity.WARNING, IssueType.NOTFOUND, null, m, OpIssueCode.VSProcessing, null));
|
||||
res.setUnknownSystems(unknownSystems);
|
||||
res.setSeverity(IssueSeverity.ERROR); // back patching for display logic issue
|
||||
res.setErrorClass(TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED);
|
||||
|
@ -697,14 +719,15 @@ public class ValueSetValidator extends ValueSetProcessBase {
|
|||
if (SERVER_SIDE_LIST.contains(system)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (txCaps != null) {
|
||||
for (TerminologyCapabilitiesCodeSystemComponent tccs : txCaps.getCodeSystem()) {
|
||||
if (system.equals(tccs.getUri())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
if (tcm.supportsSystem(system)) {
|
||||
return true;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -951,7 +974,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
|
|||
}
|
||||
}
|
||||
for (CanonicalType url : inc.getValueSet()) {
|
||||
ConceptReferencePair cc = getVs(url.asStringValue()).findValueSetRef(system, code);
|
||||
ConceptReferencePair cc = getVs(url.asStringValue(), null).findValueSetRef(system, code);
|
||||
if (cc != null) {
|
||||
return cc;
|
||||
}
|
||||
|
@ -1155,7 +1178,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
|
|||
}
|
||||
|
||||
private boolean checkForCodeInValueSet(String code, String uri, Set<String> sys, List<StringWithCode> problems) {
|
||||
ValueSetValidator vs = getVs(uri);
|
||||
ValueSetValidator vs = getVs(uri, null);
|
||||
return vs.scanForCodeInValueSet(code, sys, problems);
|
||||
}
|
||||
|
||||
|
@ -1177,7 +1200,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
|
|||
|
||||
public Boolean codeInValueSet(String path, String system, String version, String code, ValidationProcessInfo info) throws FHIRException {
|
||||
if (valueset == null) {
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
opContext.deadCheck();
|
||||
checkCanonical(info.getIssues(), path, valueset, valueset);
|
||||
|
@ -1226,7 +1249,11 @@ public class ValueSetValidator extends ValueSetProcessBase {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
ok = inImport(path, vsi.getValueSet().get(0).getValue(), system, version, code, info);
|
||||
Boolean bok = inImport(path, vsi.getValueSet().get(0).getValue(), system, version, code, info);
|
||||
if (bok == null) {
|
||||
return bok;
|
||||
}
|
||||
ok = bok;
|
||||
for (int i = 1; i < vsi.getValueSet().size(); i++) {
|
||||
UriType uri = vsi.getValueSet().get(i);
|
||||
ok = ok && inImport(path, uri.getValue(), system, version, code, info);
|
||||
|
@ -1263,10 +1290,13 @@ public class ValueSetValidator extends ValueSetProcessBase {
|
|||
if (res.getErrorClass() == TerminologyServiceErrorClass.UNKNOWN || res.getErrorClass() == TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED || res.getErrorClass() == TerminologyServiceErrorClass.VALUESET_UNSUPPORTED) {
|
||||
if (info != null && res.getErrorClass() == TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED) {
|
||||
// server didn't know the code system either - we'll take it face value
|
||||
info.addIssue(makeIssue(IssueSeverity.WARNING, IssueType.UNKNOWN, path, context.formatMessage(I18nConstants.TERMINOLOGY_TX_SYSTEM_NOTKNOWN, system), OpIssueCode.NotFound, null));
|
||||
for (ConceptReferenceComponent cc : vsi.getConcept()) {
|
||||
if (cc.getCode().equals(code)) {
|
||||
return true;
|
||||
if (!info.hasNotFound(system)) {
|
||||
String msg = context.formatMessage(I18nConstants.TERMINOLOGY_TX_SYSTEM_NOTKNOWN, system);
|
||||
info.addIssue(makeIssue(IssueSeverity.WARNING, IssueType.UNKNOWN, path, msg, OpIssueCode.NotFound, null));
|
||||
for (ConceptReferenceComponent cc : vsi.getConcept()) {
|
||||
if (cc.getCode().equals(code)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
info.setErr(TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED);
|
||||
|
@ -1423,24 +1453,28 @@ public class ValueSetValidator extends ValueSetProcessBase {
|
|||
return false;
|
||||
}
|
||||
|
||||
private ValueSetValidator getVs(String url) {
|
||||
private ValueSetValidator getVs(String url, ValidationProcessInfo info) {
|
||||
if (inner.containsKey(url)) {
|
||||
return inner.get(url);
|
||||
}
|
||||
ValueSet vs = context.fetchResource(ValueSet.class, url, valueset);
|
||||
ValueSetValidator vsc = new ValueSetValidator(context, opContext.copy(), options, vs, localContext, expansionProfile, txCaps);
|
||||
ValueSet vs = context.findTxResource(ValueSet.class, url, valueset);
|
||||
if (vs == null && info != null) {
|
||||
unknownValueSets.add(url);
|
||||
info.addIssue(makeIssue(IssueSeverity.ERROR, IssueType.NOTFOUND, null, context.formatMessage(I18nConstants.UNABLE_TO_RESOLVE_VALUE_SET_, url), OpIssueCode.NotFound, null));
|
||||
}
|
||||
ValueSetValidator vsc = new ValueSetValidator(context, opContext.copy(), options, vs, localContext, expansionProfile, tcm);
|
||||
vsc.setThrowToServer(throwToServer);
|
||||
inner.put(url, vsc);
|
||||
return vsc;
|
||||
}
|
||||
|
||||
private boolean inImport(String path, String uri, String system, String version, String code, ValidationProcessInfo info) throws FHIRException {
|
||||
ValueSetValidator vs = getVs(uri);
|
||||
private Boolean inImport(String path, String uri, String system, String version, String code, ValidationProcessInfo info) throws FHIRException {
|
||||
ValueSetValidator vs = getVs(uri, info);
|
||||
if (vs == null) {
|
||||
return false;
|
||||
} else {
|
||||
Boolean ok = vs.codeInValueSet(path, system, version, code, info);
|
||||
return ok != null && ok;
|
||||
return ok;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -140,7 +140,7 @@ public class TestingUtilities extends BaseTestingUtilities {
|
|||
if (!Utilities.noString(s))
|
||||
return s;
|
||||
s = "C:\\work\\org.hl7.fhir\\build";
|
||||
// FIXME: change this back
|
||||
// #TODO - what should we do with this?
|
||||
s = "/Users/jamesagnew/git/fhir";
|
||||
if (new File(s).exists())
|
||||
return s;
|
||||
|
|
|
@ -380,11 +380,11 @@ public class NPMPackageGenerator {
|
|||
TextFile.bytesToFile(OutputStream.toByteArray(), destFile);
|
||||
// also, for cache management on current builds, generate a little manifest
|
||||
String json = JsonParser.compose(packageManifest, true);
|
||||
TextFile.stringToFile(json, Utilities.changeFileExt(destFile, ".manifest.json"), false);
|
||||
TextFile.stringToFile(json, Utilities.changeFileExt(destFile, ".manifest.json"));
|
||||
}
|
||||
|
||||
private void buildIndexJson() throws IOException {
|
||||
byte[] content = TextFile.stringToBytes(indexer.build(), false);
|
||||
byte[] content = TextFile.stringToBytes(indexer.build());
|
||||
addFile(Category.RESOURCE, ".index.json", content);
|
||||
content = TextFile.fileToBytes(indexdb);
|
||||
new File(indexdb).delete();
|
||||
|
|
|
@ -268,6 +268,7 @@ public class ToolingExtensions {
|
|||
public static final String EXT_SEARCH_PARAMETER_BASE = "http://hl7.org/fhir/tools/StructureDefinition/searchparameter-base-type";
|
||||
public static final String EXT_ISSUE_SLICE_INFO = "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-slicetext";
|
||||
public static final String EXT_ISSUE_SERVER = "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-server";
|
||||
public static final String EXT_WEB_SOURCE = "http://hl7.org/fhir/tools/StructureDefinition/web-source";
|
||||
|
||||
// specific extension helpers
|
||||
|
||||
|
|
|
@ -658,7 +658,7 @@ public class FHIRToolingClient extends FHIRBaseToolingClient {
|
|||
try {
|
||||
getCapabilitiesStatementQuick();
|
||||
} catch (Throwable e) {
|
||||
//FIXME This is creepy. Shouldn't we report this at some level?
|
||||
//#TODO This is creepy. Shouldn't we report this at some level?
|
||||
}
|
||||
}
|
||||
return capabilities == null ? null : capabilities.getSoftware().getVersion();
|
||||
|
|
|
@ -38,7 +38,9 @@ public class FhirLoggingInterceptor implements Interceptor {
|
|||
request.body().writeTo(buf);
|
||||
cnt = buf.readByteArray();
|
||||
}
|
||||
logger.logRequest(request.method(), request.url().toString(), hdrs, cnt);
|
||||
if (logger != null) {
|
||||
logger.logRequest(request.method(), request.url().toString(), hdrs, cnt);
|
||||
}
|
||||
|
||||
// Log Response
|
||||
Response response = null;
|
||||
|
@ -56,7 +58,9 @@ public class FhirLoggingInterceptor implements Interceptor {
|
|||
Map<String, List<String>> headerMap = response.headers().toMultimap();
|
||||
headerMap.keySet().forEach(key -> headerMap.get(key).forEach(value -> headerList.add(key + ":" + value)));
|
||||
|
||||
logger.logResponse(Integer.toString(response.code()), headerList, bodyBytes);
|
||||
if (logger != null) {
|
||||
logger.logResponse(Integer.toString(response.code()), headerList, bodyBytes);
|
||||
}
|
||||
|
||||
// Reading byte[] clears body. Need to recreate.
|
||||
ResponseBody body = ResponseBody.create(bodyBytes, contentType);
|
||||
|
|
|
@ -97,7 +97,7 @@ public class FHIRPathHostServices implements FHIRPathEngine.IEvaluationContext {
|
|||
|
||||
@Override
|
||||
public ValueSet resolveValueSet(FHIRPathEngine engine, Object appContext, String url) {
|
||||
return structureMapUtilities.getWorker().fetchResource(ValueSet.class, url);
|
||||
return structureMapUtilities.getWorker().findTxResource(ValueSet.class, url);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -2119,22 +2119,23 @@ public class StructureMapUtilities {
|
|||
StructureMapAnalysis result = new StructureMapAnalysis();
|
||||
TransformContext context = new TransformContext(appInfo);
|
||||
VariablesForProfiling vars = new VariablesForProfiling(this, false, false);
|
||||
StructureMapGroupComponent start = map.getGroup().get(0);
|
||||
for (StructureMapGroupInputComponent t : start.getInput()) {
|
||||
PropertyWithType ti = resolveType(map, t.getType(), t.getMode());
|
||||
if (t.getMode() == StructureMapInputMode.SOURCE)
|
||||
vars.add(VariableMode.INPUT, t.getName(), ti);
|
||||
else
|
||||
vars.add(VariableMode.OUTPUT, t.getName(), createProfile(map, result.profiles, ti, start.getName(), start));
|
||||
if (map.hasGroup()) {
|
||||
StructureMapGroupComponent start = map.getGroup().get(0);
|
||||
for (StructureMapGroupInputComponent t : start.getInput()) {
|
||||
PropertyWithType ti = resolveType(map, t.getType(), t.getMode());
|
||||
if (t.getMode() == StructureMapInputMode.SOURCE)
|
||||
vars.add(VariableMode.INPUT, t.getName(), ti);
|
||||
else
|
||||
vars.add(VariableMode.OUTPUT, t.getName(), createProfile(map, result.profiles, ti, start.getName(), start));
|
||||
}
|
||||
result.summary = new XhtmlNode(NodeType.Element, "table").setAttribute("class", "grid");
|
||||
XhtmlNode tr = result.summary.addTag("tr");
|
||||
tr.addTag("td").addTag("b").addText("Source");
|
||||
tr.addTag("td").addTag("b").addText("Target");
|
||||
|
||||
log("Start Profiling Transform " + map.getUrl());
|
||||
analyseGroup("", context, map, vars, start, result);
|
||||
}
|
||||
|
||||
result.summary = new XhtmlNode(NodeType.Element, "table").setAttribute("class", "grid");
|
||||
XhtmlNode tr = result.summary.addTag("tr");
|
||||
tr.addTag("td").addTag("b").addText("Source");
|
||||
tr.addTag("td").addTag("b").addText("Target");
|
||||
|
||||
log("Start Profiling Transform " + map.getUrl());
|
||||
analyseGroup("", context, map, vars, start, result);
|
||||
ProfileUtilities pu = new ProfileUtilities(worker, null, pkp);
|
||||
for (StructureDefinition sd : result.getProfiles())
|
||||
pu.cleanUpDifferential(sd);
|
||||
|
|
|
@ -95,7 +95,7 @@ public class SimpleWorkerContextTests {
|
|||
public void beforeEach() {
|
||||
|
||||
Mockito.doReturn(DUMMY_URL).when(terminologyClient).getAddress();
|
||||
context.txCache = terminologyCache;
|
||||
context.initTxCache(terminologyCache);
|
||||
context.expParameters = expParameters;
|
||||
context.terminologyClientManager.setMasterClient(terminologyClient);
|
||||
context.txLog = txLog;
|
||||
|
@ -427,46 +427,41 @@ public class SimpleWorkerContextTests {
|
|||
|
||||
@Test
|
||||
public void testInitializationWithCache() {
|
||||
|
||||
Mockito.doReturn(true).when(terminologyCache).hasTerminologyCapabilities();
|
||||
Mockito.doReturn(true).when(terminologyCache).hasCapabilityStatement();
|
||||
|
||||
Mockito.doReturn(terminologyCapabilities).when(terminologyCache).getTerminologyCapabilities();
|
||||
Mockito.doReturn(capabilitiesStatement).when(terminologyCache).getCapabilityStatement();
|
||||
|
||||
String actual = context.connectToTSServer(new TerminologyClientR5Factory(), terminologyClient, null);
|
||||
|
||||
assertEquals("dummyVersion", actual);
|
||||
|
||||
Mockito.verify(terminologyCache).getTerminologyCapabilities();
|
||||
Mockito.verify(terminologyCache).getCapabilityStatement();
|
||||
|
||||
Mockito.verify(terminologyClient, times(0)).getTerminologyCapabilities();
|
||||
Mockito.verify(terminologyClient, times(0)).getCapabilitiesStatementQuick();
|
||||
|
||||
Mockito.verify(context).setTxCaps(terminologyCapabilities);
|
||||
// String address = "/...";
|
||||
//
|
||||
// Mockito.doReturn(true).when(terminologyCache).hasTerminologyCapabilities(address);
|
||||
//// Mockito.doReturn(true).when(terminologyCache).hasCapabilityStatement();
|
||||
//
|
||||
// Mockito.doReturn(terminologyCapabilities).when(terminologyCache).getTerminologyCapabilities(address);
|
||||
//// Mockito.doReturn(capabilitiesStatement).when(terminologyCache).getCapabilityStatement();
|
||||
//
|
||||
// context.connectToTSServer(new TerminologyClientR5Factory(), terminologyClient);
|
||||
//
|
||||
// Mockito.verify(terminologyCache).getTerminologyCapabilities(address);
|
||||
// Mockito.verify(terminologyClient).getCapabilitiesStatementQuick();
|
||||
//
|
||||
// Mockito.verify(terminologyCache, times(0)).getCapabilityStatement(address);
|
||||
// Mockito.verify(terminologyClient, times(0)).getTerminologyCapabilities();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInitializationWithClient() {
|
||||
// String address = "/...";
|
||||
//
|
||||
// Mockito.doReturn(false).when(terminologyCache).hasTerminologyCapabilities(address);
|
||||
//// Mockito.doReturn(false).when(terminologyCache).hasCapabilityStatement();
|
||||
//
|
||||
// Mockito.doReturn(terminologyCapabilities).when(terminologyClient).getTerminologyCapabilities();
|
||||
// Mockito.doReturn(capabilitiesStatement).when(terminologyClient).getCapabilitiesStatementQuick();
|
||||
//
|
||||
// context.connectToTSServer(new TerminologyClientR5Factory(), terminologyClient);
|
||||
//
|
||||
// Mockito.verify(terminologyCache, times(0)).getTerminologyCapabilities(address);
|
||||
// Mockito.verify(terminologyCache, times(0)).getCapabilityStatement(address);
|
||||
//
|
||||
// Mockito.verify(terminologyClient).getTerminologyCapabilities();
|
||||
// Mockito.verify(terminologyClient).getCapabilitiesStatementQuick();
|
||||
|
||||
Mockito.doReturn(false).when(terminologyCache).hasTerminologyCapabilities();
|
||||
Mockito.doReturn(false).when(terminologyCache).hasCapabilityStatement();
|
||||
|
||||
Mockito.doReturn(terminologyCapabilities).when(terminologyClient).getTerminologyCapabilities();
|
||||
Mockito.doReturn(capabilitiesStatement).when(terminologyClient).getCapabilitiesStatementQuick();
|
||||
|
||||
String actual = context.connectToTSServer(new TerminologyClientR5Factory(), terminologyClient, null);
|
||||
|
||||
assertEquals("dummyVersion", actual);
|
||||
|
||||
Mockito.verify(terminologyCache, times(0)).getTerminologyCapabilities();
|
||||
Mockito.verify(terminologyCache, times(0)).getCapabilityStatement();
|
||||
|
||||
Mockito.verify(terminologyClient).getTerminologyCapabilities();
|
||||
Mockito.verify(terminologyClient).getCapabilitiesStatementQuick();
|
||||
|
||||
Mockito.verify(context).setTxCaps(terminologyCapabilities);
|
||||
}
|
||||
|
||||
public static Stream<Arguments> zipSlipData() {
|
||||
|
|
|
@ -31,6 +31,7 @@ import org.hl7.fhir.r5.model.ValueSet;
|
|||
import org.hl7.fhir.r5.terminologies.expansion.ValueSetExpansionOutcome;
|
||||
import org.hl7.fhir.r5.terminologies.utilities.TerminologyCache;
|
||||
import org.hl7.fhir.r5.terminologies.utilities.ValidationResult;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.tests.ResourceLoaderTests;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -92,6 +93,8 @@ public class TerminologyCacheTests implements ResourceLoaderTests {
|
|||
|
||||
@Test
|
||||
public void testCachePersistence() throws IOException, URISyntaxException {
|
||||
String address = "/...";
|
||||
|
||||
Object lock = new Object();
|
||||
Path tempCacheDirectory = createTempCacheDirectory();
|
||||
ValueSet valueSet = new ValueSet();
|
||||
|
@ -117,8 +120,8 @@ public class TerminologyCacheTests implements ResourceLoaderTests {
|
|||
// Add dummy results to the cache
|
||||
TerminologyCache terminologyCacheA = new TerminologyCache(lock, tempCacheDirectory.toString());
|
||||
|
||||
terminologyCacheA.cacheTerminologyCapabilities(terminologyCapabilities);
|
||||
terminologyCacheA.cacheCapabilityStatement(capabilityStatement);
|
||||
terminologyCacheA.cacheTerminologyCapabilities(address, terminologyCapabilities);
|
||||
terminologyCacheA.cacheCapabilityStatement(address, capabilityStatement);
|
||||
|
||||
ValidationResult codingResultA = new ValidationResult(ValidationMessage.IssueSeverity.INFORMATION, "dummyInfo", null);
|
||||
TerminologyCache.CacheToken codingTokenA = terminologyCacheA.generateValidationToken(CacheTestUtils.validationOptions,
|
||||
|
@ -136,8 +139,8 @@ public class TerminologyCacheTests implements ResourceLoaderTests {
|
|||
terminologyCacheA.cacheExpansion(expansionTokenA, expansionOutcomeA, true);
|
||||
// Check that the in-memory cache is returning what we put in
|
||||
{
|
||||
assertEquals(terminologyCapabilities, terminologyCacheA.getTerminologyCapabilities());
|
||||
assertEquals(capabilityStatement, terminologyCacheA.getCapabilityStatement());
|
||||
assertEquals(terminologyCapabilities, terminologyCacheA.getTerminologyCapabilities(address));
|
||||
assertEquals(capabilityStatement, terminologyCacheA.getCapabilityStatement(address));
|
||||
|
||||
assertValidationResultEquals(codingResultA, terminologyCacheA.getValidation(codingTokenA));
|
||||
assertValidationResultEquals(codeableConceptResultA, terminologyCacheA.getValidation(codeableConceptTokenA));
|
||||
|
@ -148,8 +151,8 @@ public class TerminologyCacheTests implements ResourceLoaderTests {
|
|||
{
|
||||
TerminologyCache terminologyCacheB = new TerminologyCache(lock, tempCacheDirectory.toString());
|
||||
|
||||
assertCanonicalResourceEquals(terminologyCapabilities, terminologyCacheB.getTerminologyCapabilities());
|
||||
assertCanonicalResourceEquals(capabilityStatement, terminologyCacheB.getCapabilityStatement());
|
||||
assertCanonicalResourceEquals(terminologyCapabilities, terminologyCacheB.getTerminologyCapabilities(address));
|
||||
assertCanonicalResourceEquals(capabilityStatement, terminologyCacheB.getCapabilityStatement(address));
|
||||
|
||||
assertValidationResultEquals(codingResultA, terminologyCacheB.getValidation(terminologyCacheA.generateValidationToken(CacheTestUtils.validationOptions, coding, valueSet, new Parameters())));
|
||||
assertValidationResultEquals(codeableConceptResultA, terminologyCacheB.getValidation(terminologyCacheA.generateValidationToken(CacheTestUtils.validationOptions, concept, valueSet, new Parameters())));
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
3
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"http://somewhere/something-else" : null,
|
||||
"http://loinc.org/vs/LL715-4" : null,
|
||||
"http://hl7.org/fhir/us/vrdr/ValueSet/vrdr-PlaceOfDeath" : null,
|
||||
"http://somewhere/something" : null
|
||||
}
|
|
@ -43,8 +43,11 @@ import java.io.InputStream;
|
|||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -59,230 +62,141 @@ public class TextFile {
|
|||
|
||||
public static List<String> readAllLines(String path) throws IOException
|
||||
{
|
||||
List<String> result = new ArrayList<String>();
|
||||
|
||||
File file = new CSFile(path);
|
||||
FileInputStream fs = new FileInputStream(file);
|
||||
try {
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(fs,"UTF-8"));
|
||||
|
||||
while( reader.ready() )
|
||||
result.add(reader.readLine());
|
||||
|
||||
reader.close();
|
||||
return result;
|
||||
} finally {
|
||||
fs.close();
|
||||
}
|
||||
final File file = new CSFile(path);
|
||||
return Files.readAllLines(file.toPath(), StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
public static void writeAllLines(String path, List<String> lines) throws IOException
|
||||
{
|
||||
File file = new CSFile(path);
|
||||
FileOutputStream s = new FileOutputStream(file);
|
||||
OutputStreamWriter sw = new OutputStreamWriter(s, "UTF-8");
|
||||
for( String line : lines )
|
||||
sw.write(line + "\r\n");
|
||||
|
||||
sw.flush();
|
||||
s.close();
|
||||
final File file = new CSFile(path);
|
||||
Files.write(file.toPath(), lines, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
|
||||
public static void stringToFile(String content, File file) throws IOException {
|
||||
FileOutputStream fs = new FileOutputStream(file);
|
||||
try {
|
||||
OutputStreamWriter sw = new OutputStreamWriter(fs, "UTF-8");
|
||||
sw.write('\ufeff'); // Unicode BOM, translates to UTF-8 with the configured outputstreamwriter
|
||||
sw.write(content);
|
||||
sw.flush();
|
||||
sw.close();
|
||||
} finally {
|
||||
fs.close();
|
||||
}
|
||||
public static void stringToStream(final String content, final OutputStream stream) throws IOException {
|
||||
stream.write(content.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
public static void stringToStream(String content, OutputStream stream, boolean bom) throws IOException {
|
||||
OutputStreamWriter sw = new OutputStreamWriter(stream, "UTF-8");
|
||||
if (bom) {
|
||||
sw.write('\ufeff'); // Unicode BOM, translates to UTF-8 with the configured outputstreamwriter
|
||||
}
|
||||
sw.write(content);
|
||||
sw.flush();
|
||||
sw.close();
|
||||
public static byte[] stringToBytes(final String content) throws IOException {
|
||||
return content.getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
public static byte[] stringToBytes(String content, boolean bom) throws IOException {
|
||||
ByteArrayOutputStream bs = new ByteArrayOutputStream();
|
||||
OutputStreamWriter sw = new OutputStreamWriter(bs, "UTF-8");
|
||||
if (bom)
|
||||
sw.write('\ufeff'); // Unicode BOM, translates to UTF-8 with the configured outputstreamwriter
|
||||
sw.write(content);
|
||||
sw.flush();
|
||||
sw.close();
|
||||
return bs.toByteArray();
|
||||
}
|
||||
|
||||
public static void stringToFile(String content, String path) throws IOException {
|
||||
File file = new CSFile(path);
|
||||
public static void stringToFile(final String content, final String path) throws IOException {
|
||||
final File file = new CSFile(path);
|
||||
stringToFile(content, file);
|
||||
}
|
||||
|
||||
public static void stringToFile(String content, File file, boolean bom) throws IOException {
|
||||
FileOutputStream fs = new FileOutputStream(file);
|
||||
OutputStreamWriter sw = new OutputStreamWriter(fs, "UTF-8");
|
||||
if (bom)
|
||||
sw.write('\ufeff'); // Unicode BOM, translates to UTF-8 with the configured outputstreamwriter
|
||||
sw.write(content);
|
||||
sw.flush();
|
||||
sw.close();
|
||||
}
|
||||
|
||||
public static void stringToFile(final String content, final File file) throws IOException {
|
||||
try (final OutputStream output = Files.newOutputStream(file.toPath())) {
|
||||
output.write(content.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
}
|
||||
|
||||
public static void stringToFile(String content, String path, boolean bom) throws IOException {
|
||||
File file = new CSFile(path);
|
||||
stringToFile(content, file, bom);
|
||||
}
|
||||
|
||||
public static void stringToFileNoPrefix(String content, String path) throws IOException {
|
||||
File file = new CSFile(path);
|
||||
OutputStreamWriter sw = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
|
||||
sw.write(content);
|
||||
sw.flush();
|
||||
sw.close();
|
||||
}
|
||||
|
||||
public static String fileToString(File f) throws FileNotFoundException, IOException {
|
||||
FileInputStream fs = new FileInputStream(f);
|
||||
try {
|
||||
return streamToString(fs);
|
||||
} finally {
|
||||
fs.close();
|
||||
public static void stringToFileWithBOM(final String content, final File file) throws IOException {
|
||||
try (final OutputStream output = Files.newOutputStream(file.toPath())) {
|
||||
output.write(new byte[]{(byte)239, (byte)187, (byte)191});
|
||||
output.write(content.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
}
|
||||
|
||||
public static String fileToString(String src) throws FileNotFoundException, IOException {
|
||||
CSFile f = new CSFile(src);
|
||||
public static void stringToFileWithBOM(final String content, final String path) throws IOException {
|
||||
final File file = new CSFile(path);
|
||||
stringToFileWithBOM(content, file);
|
||||
}
|
||||
|
||||
|
||||
public static String fileToString(final File f) throws FileNotFoundException, IOException {
|
||||
// Files.readString(Path) will fail on invalid UTF-8 byte sequences, so we use Files.readAllBytes() instead.
|
||||
// This would happen when reading an XSLX file, for example.
|
||||
return new String(Files.readAllBytes(f.toPath()), StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
public static String fileToString(final String src) throws FileNotFoundException, IOException {
|
||||
final CSFile f = new CSFile(src);
|
||||
if (!f.exists()) {
|
||||
throw new IOException("File "+src+" not found");
|
||||
}
|
||||
FileInputStream fs = new FileInputStream(f);
|
||||
try {
|
||||
return streamToString(fs);
|
||||
} finally {
|
||||
fs.close();
|
||||
}
|
||||
return fileToString(f);
|
||||
}
|
||||
|
||||
public static String streamToString(InputStream input) throws IOException {
|
||||
InputStreamReader sr = new InputStreamReader(input, "UTF-8");
|
||||
StringBuilder b = new StringBuilder();
|
||||
//while (sr.ready()) { Commented out by Claude Nanjo (1/14/2014) - sr.ready() always returns false - please remove if change does not impact other areas of codebase
|
||||
int i = -1;
|
||||
while((i = sr.read()) > -1) {
|
||||
String s = Character.toString(i);
|
||||
b.append(s);
|
||||
}
|
||||
sr.close();
|
||||
|
||||
return b.toString().replace("\uFEFF", "");
|
||||
public static String streamToString(final InputStream input) throws IOException {
|
||||
return new String(input.readAllBytes(), StandardCharsets.UTF_8).replace("\uFEFF", "");
|
||||
}
|
||||
|
||||
public static byte[] streamToBytes(InputStream input) throws IOException {
|
||||
if (input== null) {
|
||||
public static byte[] streamToBytes(final InputStream input) throws IOException {
|
||||
if (input == null) {
|
||||
return null;
|
||||
}
|
||||
ByteArrayOutputStream r = new ByteArrayOutputStream(2048);
|
||||
byte[] read = new byte[512];
|
||||
for (int i; -1 != (i = input.read(read)); r.write(read, 0, i));
|
||||
final byte[] read = input.readAllBytes();
|
||||
input.close();
|
||||
return r.toByteArray();
|
||||
return read;
|
||||
}
|
||||
|
||||
public static byte[] streamToBytesNoClose(InputStream input) throws IOException {
|
||||
if (input== null) {
|
||||
public static byte[] streamToBytesNoClose(final InputStream input) throws IOException {
|
||||
if (input == null) {
|
||||
return null;
|
||||
}
|
||||
ByteArrayOutputStream r = new ByteArrayOutputStream(2048);
|
||||
byte[] read = new byte[512];
|
||||
for (int i; -1 != (i = input.read(read)); r.write(read, 0, i));
|
||||
return r.toByteArray();
|
||||
return input.readAllBytes();
|
||||
}
|
||||
|
||||
public static void bytesToFile(byte[] bytes, String path) throws IOException {
|
||||
File file = new CSFile(path);
|
||||
OutputStream sw = new FileOutputStream(file);
|
||||
sw.write(bytes);
|
||||
sw.flush();
|
||||
sw.close();
|
||||
public static void bytesToFile(final byte[] bytes, final String path) throws IOException {
|
||||
try (final OutputStream sw = new FileOutputStream(new CSFile(path))) {
|
||||
sw.write(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
public static void bytesToFile(byte[] bytes, File f) throws IOException {
|
||||
OutputStream sw = new FileOutputStream(f);
|
||||
sw.write(bytes);
|
||||
sw.flush();
|
||||
sw.close();
|
||||
public static void bytesToFile(final byte[] bytes, final File f) throws IOException {
|
||||
try (final OutputStream sw = new FileOutputStream(f)) {
|
||||
sw.write(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
public static void appendBytesToFile(byte[] bytes, String path) throws IOException {
|
||||
public static void appendBytesToFile(final byte[] bytes, final String path) throws IOException {
|
||||
byte[] linebreak = new byte[] {13, 10};
|
||||
Files.write(Paths.get(path), linebreak, StandardOpenOption.APPEND);
|
||||
Files.write(Paths.get(path), bytes, StandardOpenOption.APPEND);
|
||||
}
|
||||
|
||||
public static byte[] fileToBytes(String srcFile) throws FileNotFoundException, IOException {
|
||||
FileInputStream fs = new FileInputStream(new CSFile(srcFile));
|
||||
try {
|
||||
return streamToBytes(fs);
|
||||
} finally {
|
||||
fs.close();
|
||||
}
|
||||
public static byte[] fileToBytes(final String srcFile) throws FileNotFoundException, IOException {
|
||||
final File f = new CSFile(srcFile);
|
||||
return Files.readAllBytes(f.toPath());
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* fileToBytes insists in case correctness to ensure that stuff works across linux and windows, but it's not always appropriate to ceheck case (e.g. validator parameters)
|
||||
* fileToBytes insists in case correctness to ensure that stuff works across linux and windows, but it's not always appropriate to check case (e.g. validator parameters)
|
||||
*
|
||||
* @param srcFile
|
||||
* @return
|
||||
* @throws FileNotFoundException
|
||||
* @throws IOException
|
||||
*/
|
||||
public static byte[] fileToBytesNCS(String srcFile) throws FileNotFoundException, IOException {
|
||||
FileInputStream fs = new FileInputStream(new File(srcFile));
|
||||
try {
|
||||
return streamToBytes(fs);
|
||||
} finally {
|
||||
fs.close();
|
||||
}
|
||||
public static byte[] fileToBytesNCS(final String srcFile) throws FileNotFoundException, IOException {
|
||||
return Files.readAllBytes(Path.of(srcFile));
|
||||
}
|
||||
|
||||
public static byte[] fileToBytes(File file) throws FileNotFoundException, IOException {
|
||||
FileInputStream fs = new FileInputStream(file);
|
||||
try {
|
||||
return streamToBytes(fs);
|
||||
} finally {
|
||||
fs.close();
|
||||
}
|
||||
public static byte[] fileToBytes(final File file) throws FileNotFoundException, IOException {
|
||||
return Files.readAllBytes(file.toPath());
|
||||
}
|
||||
|
||||
public static String bytesToString(byte[] bs) throws IOException {
|
||||
return streamToString(new ByteArrayInputStream(bs));
|
||||
public static String bytesToString(final byte[] bs) throws IOException {
|
||||
return new String(bs, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
public static String bytesToString(byte[] bs, boolean removeBOM) throws IOException {
|
||||
public static String bytesToString(final byte[] bs, final boolean removeBOM) throws IOException {
|
||||
final String read = new String(bs, StandardCharsets.UTF_8);
|
||||
if (removeBOM)
|
||||
return streamToString(new ByteArrayInputStream(bs)).replace("\uFEFF", "");
|
||||
return read.replace("\uFEFF", "");
|
||||
else
|
||||
return streamToString(new ByteArrayInputStream(bs));
|
||||
return read;
|
||||
}
|
||||
|
||||
public static void streamToFile(InputStream stream, String filename) throws IOException {
|
||||
byte[] cnt = streamToBytes(stream);
|
||||
bytesToFile(cnt, filename);
|
||||
public static void streamToFile(final InputStream stream, final String filename) throws IOException {
|
||||
Files.copy(stream, Path.of(filename), StandardCopyOption.REPLACE_EXISTING);
|
||||
stream.close();
|
||||
}
|
||||
|
||||
public static void streamToFileNoClose(InputStream stream, String filename) throws IOException {
|
||||
byte[] cnt = streamToBytesNoClose(stream);
|
||||
bytesToFile(cnt, filename);
|
||||
public static void streamToFileNoClose(final InputStream stream, final String filename) throws IOException {
|
||||
Files.copy(stream, Path.of(filename), StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
}
|
|
@ -1,11 +1,13 @@
|
|||
package org.hl7.fhir.utilities;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.utilities.VersionUtilities.SemVer;
|
||||
|
||||
/*
|
||||
Copyright (c) 2011+, HL7, Inc.
|
||||
|
@ -40,6 +42,71 @@ import org.hl7.fhir.exceptions.FHIRException;
|
|||
public class VersionUtilities {
|
||||
|
||||
|
||||
public static class SemVerSorter implements Comparator<String> {
|
||||
|
||||
@Override
|
||||
public int compare(String s1, String s2) {
|
||||
return compareVersions(s1, s2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class SemVer {
|
||||
private String major;
|
||||
private String minor;
|
||||
private String patch;
|
||||
private String label;
|
||||
|
||||
public SemVer(String ver) {
|
||||
String[] p = ver.split("\\.");
|
||||
if (p.length > 0) {
|
||||
major = p[0];
|
||||
}
|
||||
if (p.length > 1) {
|
||||
minor = p[1];
|
||||
}
|
||||
if (p.length > 2) {
|
||||
patch = p[2];
|
||||
if (patch.contains("-")) {
|
||||
label = patch.substring(patch.indexOf("-")+1);
|
||||
patch = patch.substring(0, patch.indexOf("-"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int compareString(String s1, String s2) {
|
||||
if (s1 == null) {
|
||||
return s2 == null ? 0 : 1;
|
||||
} else {
|
||||
return s1.compareTo(s2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private int compareInteger(String s1, String s2) {
|
||||
if (s1 == null) {
|
||||
return s2 == null ? 0 : 1;
|
||||
} else {
|
||||
return Integer.compare(Integer.parseInt(s1), Integer.parseInt(s2));
|
||||
}
|
||||
}
|
||||
|
||||
public int compareTo(SemVer sv2) {
|
||||
int c = compareInteger(major, sv2.major);
|
||||
if (c == 0) {
|
||||
c = compareInteger(minor, sv2.minor);
|
||||
}
|
||||
if (c == 0) {
|
||||
c = compareInteger(patch, sv2.patch);
|
||||
}
|
||||
if (c == 0) {
|
||||
c = compareString(label, sv2.label);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static final String[] SUPPORTED_MAJOR_VERSIONS = {"1.0", "1.4", "3.0", "4.0", "5.0", "6.0"};
|
||||
public static final String[] SUPPORTED_VERSIONS = {"1.0.2", "1.4.0", "3.0.2", "4.0.1", "4.1.0", "4.3.0", "5.0.0", "6.0.0"};
|
||||
|
||||
|
@ -650,5 +717,17 @@ public class VersionUtilities {
|
|||
return version != null && version.startsWith("6.");
|
||||
}
|
||||
|
||||
public static int compareVersions(String ver1, String ver2) {
|
||||
if (ver1 == null) {
|
||||
return ver2 == null ? 0 : 1;
|
||||
} else if (isSemVer(ver1) && isSemVer(ver2)) {
|
||||
SemVer sv1 = new SemVer(ver1);
|
||||
SemVer sv2 = new SemVer(ver2);
|
||||
return sv1.compareTo(sv2);
|
||||
} else {
|
||||
return ver1.compareTo(ver2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -266,6 +266,8 @@ public class I18nConstants {
|
|||
public static final String NODE_TYPE__IS_NOT_ALLOWED = "Node_type__is_not_allowed";
|
||||
public static final String NONE_OF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_ = "None_of_the_provided_codes_are_in_the_value_set";
|
||||
public static final String NONE_OF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_ONE = "None_of_the_provided_codes_are_in_the_value_set_one";
|
||||
public static final String UNABLE_TO_CHECK_IF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_CS = "UNABLE_TO_CHECK_IF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_CS";
|
||||
public static final String UNABLE_TO_CHECK_IF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_VS = "UNABLE_TO_CHECK_IF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_VS";
|
||||
public static final String UNABLE_TO_CHECK_IF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_ = "UNABLE_TO_CHECK_IF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_";
|
||||
public static final String NOT_DONE_YET = "Not_done_yet";
|
||||
public static final String NOT_DONE_YET_CANT_FETCH_ = "not_done_yet_cant_fetch_";
|
||||
|
|
|
@ -191,7 +191,7 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple
|
|||
File packagesIniFile = new File(packagesIniPath);
|
||||
if (!(packagesIniFile.exists()))
|
||||
packagesIniFile.createNewFile();
|
||||
TextFile.stringToFile("[cache]\r\nversion=" + CACHE_VERSION + "\r\n\r\n[urls]\r\n\r\n[local]\r\n\r\n", packagesIniPath, false);
|
||||
TextFile.stringToFile("[cache]\r\nversion=" + CACHE_VERSION + "\r\n\r\n[urls]\r\n\r\n[local]\r\n\r\n", packagesIniPath);
|
||||
createIniFile();
|
||||
for (File f : cacheFolder.listFiles()) {
|
||||
if (f.isDirectory() && Utilities.isValidUUID(f.getName())) {
|
||||
|
@ -541,7 +541,7 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple
|
|||
npm.getNpm().remove("version");
|
||||
npm.getNpm().add("version", v);
|
||||
}
|
||||
TextFile.stringToFile(JsonParser.compose(npm.getNpm(), true), Utilities.path(cacheFolder, id + "#" + v, "package", "package.json"), false);
|
||||
TextFile.stringToFile(JsonParser.compose(npm.getNpm(), true), Utilities.path(cacheFolder, id + "#" + v, "package", "package.json"));
|
||||
}
|
||||
pck = loadPackageInfo(packRoot);
|
||||
} catch (Exception e) {
|
||||
|
|
|
@ -1125,7 +1125,7 @@ public class NpmPackage {
|
|||
byte[] cnt = indexer.build().getBytes(StandardCharsets.UTF_8);
|
||||
TextFile.bytesToFile(cnt, Utilities.path(dir.getAbsolutePath(), n, ".index.json"));
|
||||
}
|
||||
byte[] cnt = TextFile.stringToBytes(JsonParser.compose(npm, true), false);
|
||||
byte[] cnt = TextFile.stringToBytes(JsonParser.compose(npm, true));
|
||||
TextFile.bytesToFile(cnt, Utilities.path(dir.getAbsolutePath(), "package", "package.json"));
|
||||
}
|
||||
|
||||
|
@ -1185,7 +1185,7 @@ public class NpmPackage {
|
|||
tar.closeArchiveEntry();
|
||||
}
|
||||
}
|
||||
byte[] cnt = TextFile.stringToBytes(JsonParser.compose(npm, true), false);
|
||||
byte[] cnt = TextFile.stringToBytes(JsonParser.compose(npm, true));
|
||||
TarArchiveEntry entry = new TarArchiveEntry("package/package.json");
|
||||
entry.setSize(cnt.length);
|
||||
tar.putArchiveEntry(entry);
|
||||
|
|
|
@ -23,9 +23,11 @@ public class CacheVerificationLogger implements ToolingClientLogger {
|
|||
System.err.println("Header: " + header);
|
||||
}
|
||||
}
|
||||
System.err.println("Body");
|
||||
System.err.println("----");
|
||||
System.err.println(new String(body, StandardCharsets.UTF_8));
|
||||
if (body != null) {
|
||||
System.err.println("Body");
|
||||
System.err.println("----");
|
||||
System.err.println(new String(body, StandardCharsets.UTF_8));
|
||||
}
|
||||
}
|
||||
requests++;
|
||||
}
|
||||
|
|
|
@ -141,6 +141,7 @@ public class HierarchicalTableGenerator extends TranslatingUtilities {
|
|||
private String text;
|
||||
private String hint;
|
||||
private String style;
|
||||
private String tagImg;
|
||||
private Map<String, String> attributes;
|
||||
private XhtmlNodeList children;
|
||||
|
||||
|
@ -231,6 +232,16 @@ public class HierarchicalTableGenerator extends TranslatingUtilities {
|
|||
attributes.put(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getTagImg() {
|
||||
return tagImg;
|
||||
}
|
||||
|
||||
public Piece setTagImg(String tagImg) {
|
||||
this.tagImg = tagImg;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class Cell {
|
||||
|
@ -671,7 +682,7 @@ public class HierarchicalTableGenerator extends TranslatingUtilities {
|
|||
|
||||
model.setAlternating(true);
|
||||
if (mode == TableGenerationMode.XML) {
|
||||
model.setDocoImg(help16AsData()); // #FIXME
|
||||
model.setDocoImg(help16AsData());
|
||||
} else {
|
||||
model.setDocoImg(Utilities.pathURL(prefix, "help16.png"));
|
||||
}
|
||||
|
@ -879,6 +890,14 @@ public class HierarchicalTableGenerator extends TranslatingUtilities {
|
|||
a.addChildren(p.getChildren());
|
||||
}
|
||||
addStyle(a, p);
|
||||
if (p.getTagImg() != null) {
|
||||
a.tx(" ");
|
||||
a.img(p.getTagImg(), null);
|
||||
}
|
||||
|
||||
if (p.hasChildren()) {
|
||||
tc.getChildNodes().addAll(p.getChildren());
|
||||
}
|
||||
} else {
|
||||
if (!Utilities.noString(p.getHint())) {
|
||||
XhtmlNode s = addStyle(tc.addTag("span"), p);
|
||||
|
@ -893,6 +912,10 @@ public class HierarchicalTableGenerator extends TranslatingUtilities {
|
|||
if (p.hasChildren()) {
|
||||
tc.getChildNodes().addAll(p.getChildren());
|
||||
}
|
||||
if (p.getTagImg() != null) {
|
||||
tc.tx(" ");
|
||||
tc.img(p.getTagImg(), null);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (makeTargets && !Utilities.noString(anchor))
|
||||
|
|
|
@ -181,7 +181,11 @@ public abstract class XhtmlFluent {
|
|||
}
|
||||
|
||||
public XhtmlNode img(String src, String alt) {
|
||||
return addTag("img").attribute("src", src).attribute("alt", alt);
|
||||
if (alt == null) {
|
||||
return addTag("img").attribute("src", src);
|
||||
} else {
|
||||
return addTag("img").attribute("src", src).attribute("alt", alt);
|
||||
}
|
||||
}
|
||||
|
||||
public XhtmlNode img(String src, String alt, String title) {
|
||||
|
@ -276,6 +280,18 @@ public abstract class XhtmlFluent {
|
|||
}
|
||||
}
|
||||
|
||||
// differs from tx because it returns the owner node, not the created text
|
||||
public XhtmlFluent txN(String cnt) {
|
||||
addText(cnt);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public XhtmlFluent iff(boolean test) {
|
||||
if (test) {
|
||||
return this;
|
||||
} else {
|
||||
return new XhtmlNode(NodeType.Element, "span"); // which will never be connected
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -783,11 +783,6 @@ public class XhtmlNode extends XhtmlFluent implements IBaseXhtml {
|
|||
return setAttribute("colspan", Integer.toString(n));
|
||||
}
|
||||
|
||||
// differs from tx because it returns the owner node, not the created text
|
||||
public XhtmlNode txN(String cnt) {
|
||||
addText(cnt);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
|
@ -938,5 +933,31 @@ public class XhtmlNode extends XhtmlFluent implements IBaseXhtml {
|
|||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
// differs from tx because it returns the owner node, not the created text
|
||||
public XhtmlNode txN(String cnt) {
|
||||
addText(cnt);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public XhtmlNode iff(boolean test) {
|
||||
if (test) {
|
||||
return this;
|
||||
} else {
|
||||
return new XhtmlNode(NodeType.Element, "span"); // which will never be connected
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public XhtmlNode button(String class_, String title) {
|
||||
XhtmlNode btn = addTag("button");
|
||||
btn.attribute("class", class_);
|
||||
if (title != null) {
|
||||
btn.attribute("title", title);
|
||||
}
|
||||
return btn;
|
||||
}
|
||||
|
||||
}
|
|
@ -126,7 +126,7 @@ public class XLSXmlNormaliser {
|
|||
String s = TextFile.fileToString(dest);
|
||||
s = s.replaceAll("\r\n","\n");
|
||||
s = replaceSignificantEoln(s);
|
||||
TextFile.stringToFile(s, dest, false);
|
||||
TextFile.stringToFile(s, dest);
|
||||
new File(dest).setLastModified(time);
|
||||
} catch (Exception e) {
|
||||
System.out.println("The file "+dest+" is still open in Excel, and you will have to run the build after closing Excel before committing");
|
||||
|
|
|
@ -192,8 +192,8 @@ Terminology_TX_System_Relative = Coding.system must be an absolute reference, no
|
|||
Terminology_TX_System_Unknown = Unknown Code System ''{0}''
|
||||
Terminology_TX_System_ValueSet = Invalid System URI: {0} - cannot use a value set URI as a system
|
||||
Terminology_TX_System_ValueSet2 = The Coding references a value set, not a code system (''{0}'')
|
||||
Terminology_TX_ValueSet_NotFound = ValueSet {0} not found
|
||||
Terminology_TX_ValueSet_NotFound_CS = Found a reference to a CodeSystem ({0}) where a ValueSet belongs
|
||||
Terminology_TX_ValueSet_NotFound = ValueSet ''{0}'' not found
|
||||
Terminology_TX_ValueSet_NotFound_CS = Found a reference to a CodeSystem ''{0}'' where a ValueSet belongs
|
||||
Type_Specific_Checks_DT_Base64_Valid = The value ''{0}'' is not a valid Base64 value
|
||||
Type_Specific_Checks_DT_Boolean_Value = Boolean values must be ''true'' or ''false''
|
||||
Type_Specific_Checks_DT_Code_WS = The code ''{0}'' is not valid (whitespace rules)
|
||||
|
@ -453,12 +453,12 @@ no_url_in_expand_value_set = No url in expand value set
|
|||
no_value_set = ValueSet has no url property
|
||||
No_Parameters_provided_to_expandVS = No Parameters provided to expandVS
|
||||
No_Expansion_Parameters_provided = No Expansion Parameters provided
|
||||
Unable_to_resolve_value_Set_ = Unable to resolve value Set {0}
|
||||
Unable_to_resolve_value_Set_ = A definition for the value Set ''{0}'' could not be found
|
||||
Delimited_versions_have_exact_match_for_delimiter____vs_ = Delimited versions have exact match for delimiter ''{0}'' : {1} vs {2}
|
||||
Duplicate_Resource_ = Duplicate Resource {0} of type {3} (existing version {2}, new version {1})
|
||||
DUPLICATE_RESOURCE_VERSION = Duplicate Resource {0} Version {1} of type {2}
|
||||
Error_expanding_ValueSet_running_without_terminology_services = Error expanding ValueSet: running without terminology services
|
||||
Error_validating_code_running_without_terminology_services = Error validating code: running without terminology services
|
||||
Error_validating_code_running_without_terminology_services = Unable to validate code ''{0}'' in system ''{1}'' because the validator is running without terminology services
|
||||
Unable_to_validate_code_without_using_server = Unable to validate code without using server because: {0}
|
||||
UNABLE_TO_VALIDATE_LOCALLY = Unable to validate code locally: {0}
|
||||
Profile___Error_generating_snapshot = Profile {0} ({1}). Error generating snapshot
|
||||
|
@ -471,10 +471,10 @@ Version_mismatch_The_context_has_version__loaded_and_the_new_content_being_loade
|
|||
Error_reading__from_package__ = Error reading {0} from package {1}#{2}: {3}
|
||||
Error_parsing_ = Error parsing {0}:{1}
|
||||
Unable_to_connect_to_terminology_server_Use_parameter_tx_na_tun_run_without_using_terminology_services_to_validate_LOINC_SNOMED_ICDX_etc_Error__ = Unable to connect to terminology server at {1}. Use parameter ''-tx n/a'' to run without using terminology services to validate LOINC, SNOMED, ICD-X etc. Error = {0}
|
||||
Display_Name_for__should_be_one_of__instead_of_one = Wrong Display Name ''{4}'' for {1}#{2} - should be {3} (for the language(s) ''{5}'')
|
||||
Display_Name_for__should_be_one_of__instead_of_other = Wrong Display Name ''{4}'' for {1}#{2} - should be one of {0} choices: {3} (for the language(s) ''{5}'')
|
||||
Display_Name_WS_for__should_be_one_of__instead_of_one = Wrong whitespace in Display Name ''{4}'' for {1}#{2} - should be {3} (for the language(s) ''{5}'')
|
||||
Display_Name_WS_for__should_be_one_of__instead_of_other = Wrong whitespace in Display Name ''{4}'' for {1}#{2} - should be one of {0} choices: {3} (for the language(s) ''{5}'')
|
||||
Display_Name_for__should_be_one_of__instead_of_one = Wrong Display Name ''{4}'' for {1}#{2}. Valid display is {3} (for the language(s) ''{5}'')
|
||||
Display_Name_for__should_be_one_of__instead_of_other = Wrong Display Name ''{4}'' for {1}#{2}. Valid display is one of {0} choices: {3} (for the language(s) ''{5}'')
|
||||
Display_Name_WS_for__should_be_one_of__instead_of_one = Wrong whitespace in Display Name ''{4}'' for {1}#{2}. Valid display is {3} (for the language(s) ''{5}'')
|
||||
Display_Name_WS_for__should_be_one_of__instead_of_other = Wrong whitespace in Display Name ''{4}'' for {1}#{2}. Valid display is one of {0} choices: {3} (for the language(s) ''{5}'')
|
||||
Unknown_Code_in = Unknown code ''{0}'' in the CodeSystem ''{1}''
|
||||
Unknown_Code_in_Version = Unknown code ''{0}'' in the CodeSystem ''{1}'' version ''{2}''
|
||||
UNKNOWN_CODE_IN_FRAGMENT = Unknown Code ''{0}'' in the system ''{1}'' version ''{2}'' - note that the code system is labeled as a fragment, so the code may be valid in some other fragment
|
||||
|
@ -684,7 +684,9 @@ RENDER_BUNDLE_DOCUMENT_CONTENT = Additional Document Content
|
|||
RENDER_BUNDLE_HEADER_DOC_ENTRY_URD = {0}. {1} ({2}/{3})
|
||||
RENDER_BUNDLE_HEADER_DOC_ENTRY_U = {0}. {1}
|
||||
RENDER_BUNDLE_HEADER_DOC_ENTRY_RD = {0}. {2}/{3}
|
||||
UNABLE_TO_CHECK_IF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_ = Unable to check whether the code is in the value set {0} because the code system {1} was not found
|
||||
UNABLE_TO_CHECK_IF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_CS = Unable to check whether the code is in the value set ''{0}'' because the code system {1} was not found
|
||||
UNABLE_TO_CHECK_IF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_VS = Unable to check whether the code is in the value set ''{0}'' because the value set {1} was not found
|
||||
UNABLE_TO_CHECK_IF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET = Unable to check whether the code is in the value set ''{0}''
|
||||
TERMINOLOGY_TX_SYSTEM_WRONG_HTML = The code system reference {0} is wrong - the code system reference cannot be to an HTML page. This may be the correct reference: {1}
|
||||
TERMINOLOGY_TX_SYSTEM_WRONG_BUILD = The code system reference {0} is wrong - the code system reference cannot be a reference to build.fhir.org. This may be the correct reference: {1}
|
||||
FHIRPATH_BAD_DATE = Unable to parse Date {0}
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
package org.hl7.fhir.utilities;
|
||||
|
||||
import org.junit.jupiter.api.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* Test bench for {@link TextFile}.
|
||||
*
|
||||
* @author Quentin Ligier
|
||||
**/
|
||||
class TextFileTest {
|
||||
|
||||
private static final String SAMPLE_CONTENT = "Line 1\nLine 2\nLine 3";
|
||||
private static final List<String> SAMPLE_CONTENT_LINES = List.of("Line 1", "Line 2", "Line 3");
|
||||
private static final String BOM = "\uFEFF";
|
||||
|
||||
private static File readFile;
|
||||
private final static List<File> createdFiles = new ArrayList<>(4);
|
||||
|
||||
@BeforeAll
|
||||
static void setUp() throws IOException {
|
||||
readFile = createTempFile();
|
||||
readFile.deleteOnExit();
|
||||
Files.writeString(readFile.toPath(), SAMPLE_CONTENT);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void tearDown() throws IOException {
|
||||
for (final var file : createdFiles) {
|
||||
Files.deleteIfExists(file.toPath());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testReadAllLines() throws IOException {
|
||||
final var readLines = TextFile.readAllLines(readFile.getAbsolutePath());
|
||||
assertEquals(3, readLines.size());
|
||||
assertEquals(SAMPLE_CONTENT_LINES, readLines);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBytesToString1() throws IOException {
|
||||
final var converted = TextFile.bytesToString(SAMPLE_CONTENT.getBytes(StandardCharsets.UTF_8));
|
||||
assertEquals(SAMPLE_CONTENT, converted);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBytesToString2() throws IOException {
|
||||
final var bytesWithoutBom = SAMPLE_CONTENT.getBytes(StandardCharsets.UTF_8);
|
||||
final var bomBytes = BOM.getBytes(StandardCharsets.UTF_8);
|
||||
final var bytesWithBom = Arrays.copyOf(bomBytes, bomBytes.length + bytesWithoutBom.length);
|
||||
System.arraycopy(bytesWithoutBom, 0, bytesWithBom, bomBytes.length, bytesWithoutBom.length);
|
||||
|
||||
var converted = TextFile.bytesToString(bytesWithoutBom, true);
|
||||
assertEquals(SAMPLE_CONTENT, converted);
|
||||
|
||||
converted = TextFile.bytesToString(bytesWithoutBom, false);
|
||||
assertEquals(SAMPLE_CONTENT, converted);
|
||||
|
||||
converted = TextFile.bytesToString(bytesWithBom, true);
|
||||
assertEquals(SAMPLE_CONTENT, converted);
|
||||
|
||||
converted = TextFile.bytesToString(bytesWithBom, false);
|
||||
assertEquals(BOM + SAMPLE_CONTENT, converted);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFileToString1() throws IOException {
|
||||
final var read = TextFile.fileToString(readFile);
|
||||
assertEquals(SAMPLE_CONTENT, read);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFileToString2() throws IOException {
|
||||
final var read = TextFile.fileToString(readFile.getAbsolutePath());
|
||||
assertEquals(SAMPLE_CONTENT, read);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFileToBytes1() throws IOException {
|
||||
final var read = TextFile.fileToBytes(readFile);
|
||||
assertArrayEquals(SAMPLE_CONTENT.getBytes(StandardCharsets.UTF_8), read);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFileToBytesNCS() throws IOException {
|
||||
final var read = TextFile.fileToBytesNCS(readFile.getAbsolutePath());
|
||||
assertArrayEquals(SAMPLE_CONTENT.getBytes(StandardCharsets.UTF_8), read);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFileToBytes2() throws IOException {
|
||||
final var read = TextFile.fileToBytes(readFile.getAbsolutePath());
|
||||
assertArrayEquals(SAMPLE_CONTENT.getBytes(StandardCharsets.UTF_8), read);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testStringToFile() throws IOException {
|
||||
final var writeFile = createTempFile();
|
||||
TextFile.stringToFileWithBOM(SAMPLE_CONTENT, writeFile);
|
||||
assertEquals(BOM + SAMPLE_CONTENT, Files.readString(writeFile.toPath()));
|
||||
|
||||
TextFile.stringToFile(SAMPLE_CONTENT, writeFile);
|
||||
assertEquals(SAMPLE_CONTENT, Files.readString(writeFile.toPath()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testWriteAllLines() throws IOException {
|
||||
final var writeFile = createTempFile();
|
||||
TextFile.writeAllLines(writeFile.getAbsolutePath(), SAMPLE_CONTENT_LINES);
|
||||
assertEquals(SAMPLE_CONTENT_LINES, Files.readAllLines(writeFile.toPath()));
|
||||
}
|
||||
|
||||
private static File createTempFile() throws IOException {
|
||||
final var file = Files.createTempFile("test_fhir_utilities_", ".txt").toFile();
|
||||
file.deleteOnExit();
|
||||
createdFiles.add(file);
|
||||
return file;
|
||||
}
|
||||
}
|
|
@ -978,11 +978,11 @@ public class BaseValidator implements IValidationContextResourceLoader {
|
|||
return null;
|
||||
} else {
|
||||
long t = System.nanoTime();
|
||||
ValueSet fr = context.fetchResource(ValueSet.class, reference, src);
|
||||
ValueSet fr = context.findTxResource(ValueSet.class, reference, src);
|
||||
if (fr == null) {
|
||||
if (!Utilities.isAbsoluteUrl(reference)) {
|
||||
reference = resolve(uri, reference);
|
||||
fr = context.fetchResource(ValueSet.class, reference, src);
|
||||
fr = context.findTxResource(ValueSet.class, reference, src);
|
||||
}
|
||||
}
|
||||
if (fr == null) {
|
||||
|
|
|
@ -554,7 +554,7 @@ public class IgLoader implements IValidationEngineLoader {
|
|||
private String readInfoVersion(ByteProvider bs) throws IOException {
|
||||
String is = TextFile.bytesToString(bs.getBytes());
|
||||
is = is.trim();
|
||||
IniFile ini = new IniFile(new ByteArrayInputStream(TextFile.stringToBytes(is, false)));
|
||||
IniFile ini = new IniFile(new ByteArrayInputStream(TextFile.stringToBytes(is)));
|
||||
return ini.getStringProperty("FHIR", "version");
|
||||
}
|
||||
|
||||
|
@ -863,7 +863,9 @@ public class IgLoader implements IValidationEngineLoader {
|
|||
}
|
||||
|
||||
private void log(String s) {
|
||||
if (isDebug()) System.out.println(s);
|
||||
if (isDebug()) {
|
||||
System.out.println(s);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -475,7 +475,6 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
|
|||
|
||||
protected void initContext(TimeTracker tt) throws IOException {
|
||||
context.setCanNoTS(true);
|
||||
context.setCacheId(UUID.randomUUID().toString());
|
||||
context.setAllowLoadingDuplicates(true); // because of Forge
|
||||
context.setExpansionParameters(makeExpProfile());
|
||||
if (tt != null) {
|
||||
|
@ -524,7 +523,8 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
|
|||
} else {
|
||||
try {
|
||||
TerminologyClientFactory factory = new TerminologyClientFactory(version);
|
||||
return context.connectToTSServer(factory, factory.makeClient("Tx-Server", url, context.getUserAgent()), log);
|
||||
context.connectToTSServer(factory, url, context.getUserAgent(), log);
|
||||
return "Connected to Terminology Server at "+url;
|
||||
} catch (Exception e) {
|
||||
if (context.isCanRunWithoutTerminology()) {
|
||||
return "n/a: Running without Terminology Server (error: " + e.getMessage() + ")";
|
||||
|
@ -927,7 +927,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
|
|||
else if (fn.endsWith(".json") && !fn.endsWith("template.json"))
|
||||
new org.hl7.fhir.dstu3.formats.JsonParser().setOutputStyle(org.hl7.fhir.dstu3.formats.IParser.OutputStyle.PRETTY).compose(s, res);
|
||||
else if (fn.endsWith(".txt") || fn.endsWith(".map") || fn.endsWith(".fml"))
|
||||
TextFile.stringToStream(org.hl7.fhir.dstu3.utils.StructureMapUtilities.render((org.hl7.fhir.dstu3.model.StructureMap) res), s, false);
|
||||
TextFile.stringToStream(org.hl7.fhir.dstu3.utils.StructureMapUtilities.render((org.hl7.fhir.dstu3.model.StructureMap) res), s);
|
||||
else
|
||||
throw new FHIRException("Unsupported format for " + fn);
|
||||
} else if (VersionUtilities.isR4Ver(version)) {
|
||||
|
@ -937,7 +937,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
|
|||
else if (fn.endsWith(".json") && !fn.endsWith("template.json"))
|
||||
new org.hl7.fhir.r4.formats.JsonParser().setOutputStyle(org.hl7.fhir.r4.formats.IParser.OutputStyle.PRETTY).compose(s, res);
|
||||
else if (fn.endsWith(".txt") || fn.endsWith(".map") || fn.endsWith(".fml"))
|
||||
TextFile.stringToStream(org.hl7.fhir.r4.utils.StructureMapUtilities.render((org.hl7.fhir.r4.model.StructureMap) res), s, false);
|
||||
TextFile.stringToStream(org.hl7.fhir.r4.utils.StructureMapUtilities.render((org.hl7.fhir.r4.model.StructureMap) res), s);
|
||||
else
|
||||
throw new FHIRException("Unsupported format for " + fn);
|
||||
} else if (VersionUtilities.isR2BVer(version)) {
|
||||
|
@ -962,7 +962,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
|
|||
else if (fn.endsWith(".json") && !fn.endsWith("template.json"))
|
||||
new JsonParser().setOutputStyle(org.hl7.fhir.r5.formats.IParser.OutputStyle.PRETTY).compose(s, r);
|
||||
else if (fn.endsWith(".txt") || fn.endsWith(".map") || fn.endsWith(".fml"))
|
||||
TextFile.stringToStream(StructureMapUtilities.render((org.hl7.fhir.r5.model.StructureMap) r), s, false);
|
||||
TextFile.stringToStream(StructureMapUtilities.render((org.hl7.fhir.r5.model.StructureMap) r), s);
|
||||
else
|
||||
throw new FHIRException("Unsupported format for " + fn);
|
||||
} else
|
||||
|
|
|
@ -363,8 +363,6 @@ public class ValidatorCli {
|
|||
private void readParamsAndExecuteTask(TimeTracker tt, TimeTracker.Session tts, CliContext cliContext, String[] params) throws Exception {
|
||||
Display.printCliParamsAndInfo(params);
|
||||
|
||||
|
||||
|
||||
final CliTask cliTask = selectCliTask(cliContext, params);
|
||||
|
||||
if (cliTask instanceof ValidationEngineTask) {
|
||||
|
|
|
@ -289,7 +289,7 @@ public class StandAloneValidatorFetcher implements IValidatorResourceFetcher, IV
|
|||
|
||||
@Nonnull
|
||||
protected ITerminologyClient getTerminologyClient(String root) throws URISyntaxException {
|
||||
return new TerminologyClientFactory(context.getVersion()).makeClient("source", root, Common.getValidatorUserAgent());
|
||||
return new TerminologyClientFactory(context.getVersion()).makeClient("source", root, Common.getValidatorUserAgent(), null);
|
||||
}
|
||||
|
||||
private String getRoot(String[] p, String url) {
|
||||
|
|
|
@ -537,7 +537,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
}
|
||||
return null;
|
||||
}
|
||||
return context.fetchResource(ValueSet.class, url);
|
||||
return context.findTxResource(ValueSet.class, url);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1135,7 +1135,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
timeTracker.tx(t, "vc "+system+"#"+code+" '"+display+"'");
|
||||
if (s == null)
|
||||
return true;
|
||||
ok = processTxIssues(errors, s, element, path, null, false) & ok;
|
||||
ok = processTxIssues(errors, s, element, path, null, false, null) & ok;
|
||||
|
||||
if (s.isOk()) {
|
||||
if (s.getMessage() != null && !s.messageIsInIssues()) {
|
||||
|
@ -1175,6 +1175,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
return false;
|
||||
}
|
||||
} else if (context.isNoTerminologyServer() && NO_TX_SYSTEM_EXEMPT.contains(system)) {
|
||||
txWarning(errors, NO_RULE_DATE, null, IssueType.BUSINESSRULE, element.line(), element.col(), path, false, I18nConstants.ERROR_VALIDATING_CODE_RUNNING_WITHOUT_TERMINOLOGY_SERVICES, code, system);
|
||||
return ok; // no checks in this case
|
||||
} else if (startsWithButIsNot(system, "http://snomed.info/sct", "http://loinc.org", "http://unitsofmeasure.org", "http://www.nlm.nih.gov/research/umls/rxnorm")) {
|
||||
rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_SYSTEM_INVALID, system);
|
||||
|
@ -1399,7 +1400,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
} else {
|
||||
checked = true;
|
||||
ValidationResult vr = checkCodeOnServer(stack, valueset, cc);
|
||||
bh.see(processTxIssues(errors, vr, element, path, notFoundSeverityForBinding(binding), false));
|
||||
bh.see(processTxIssues(errors, vr, element, path, notFoundSeverityForBinding(binding), false, binding.getValueSet()));
|
||||
if (!vr.isOk()) {
|
||||
bindingsOk = false;
|
||||
if (vr.getErrorClass() != null && vr.getErrorClass() == TerminologyServiceErrorClass.NOSERVICE) {
|
||||
|
@ -1436,12 +1437,12 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
}
|
||||
}
|
||||
} else if (vr.getMessage() != null) {
|
||||
if (vr.getSeverity() == IssueSeverity.INFORMATION) {
|
||||
txHint(errors, "2023-07-03", vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, vr.getMessage());
|
||||
} else {
|
||||
checkDisp = false;
|
||||
if (!vr.messageIsInIssues()) {
|
||||
txWarning(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, vr.getMessage());
|
||||
if (vr.getTrimmedMessage() != null) {
|
||||
if (vr.getSeverity() == IssueSeverity.INFORMATION) {
|
||||
txHint(errors, "2023-07-03", vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, vr.getMessage());
|
||||
} else {
|
||||
checkDisp = false;
|
||||
txWarning(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, vr.getTrimmedMessage());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -1478,7 +1479,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
if (cc.hasCoding()) {
|
||||
long t = System.nanoTime();
|
||||
ValidationResult vr = checkCodeOnServer(stack, null, cc);
|
||||
bh.see(processTxIssues(errors, vr, element, path, org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.INFORMATION, false));
|
||||
bh.see(processTxIssues(errors, vr, element, path, org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.INFORMATION, false, null));
|
||||
timeTracker.tx(t, "vc "+cc.toString());
|
||||
}
|
||||
}
|
||||
|
@ -1503,7 +1504,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
}
|
||||
|
||||
private boolean processTxIssues(List<ValidationMessage> errors, ValidationResult vr, Element element, String path,
|
||||
org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity notFoundLevel, boolean ignoreCantInfer) {
|
||||
org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity notFoundLevel, boolean ignoreCantInfer, String vsurl) {
|
||||
boolean ok = true;
|
||||
if (vr != null) {
|
||||
for (OperationOutcomeIssueComponent iss : vr.getIssues()) {
|
||||
|
@ -1511,8 +1512,10 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
!iss.getDetails().hasCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", "this-code-not-in-vs")
|
||||
&& !(ignoreCantInfer || iss.getDetails().hasCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", "cannot-infer"))) {
|
||||
OperationOutcomeIssueComponent i = iss.copy();
|
||||
if (notFoundLevel != null && (i.getDetails().hasCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", "not-found"))) {
|
||||
i.setSeverity(notFoundLevel);
|
||||
if (notFoundLevel != null && i.getDetails().hasCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", "not-found")) {
|
||||
if (i.getSeverity().isHigherThan(notFoundLevel) || (vsurl != null && i.getDetails().getText().contains(vsurl))) {
|
||||
i.setSeverity(notFoundLevel);
|
||||
}
|
||||
}
|
||||
if (baseOptions.isDisplayWarningMode() && i.getSeverity() == org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.ERROR && i.getDetails().hasCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", "invalid-display")) {
|
||||
i.setSeverity(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.WARNING);
|
||||
|
@ -1531,7 +1534,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
boolean ok = true;
|
||||
if (isNotBlank(nextCoding.getCode()) && isNotBlank(nextCoding.getSystem()) && context.supportsSystem(nextCoding.getSystem(), baseOptions.getFhirVersion())) {
|
||||
ValidationResult vr = checkCodeOnServer(stack, valueset, nextCoding);
|
||||
ok = processTxIssues(errors, vr, element, path, null, false) && ok;
|
||||
ok = processTxIssues(errors, vr, element, path, null, false, null) && ok;
|
||||
|
||||
if (vr.getSeverity() != null && !vr.messageIsInIssues()) {
|
||||
if (vr.getSeverity() == IssueSeverity.INFORMATION) {
|
||||
|
@ -1597,7 +1600,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
// ignore this since we can't validate but it doesn't matter..
|
||||
} else {
|
||||
ValidationResult vr = checkCodeOnServer(stack, valueset, cc);
|
||||
ok = processTxIssues(errors, vr, element, path, notFoundSeverityForBinding(binding), false) && ok;
|
||||
ok = processTxIssues(errors, vr, element, path, notFoundSeverityForBinding(binding), false, binding.getValueSet()) && ok;
|
||||
if (!vr.isOk()) {
|
||||
bindingsOk = false;
|
||||
if (vr.getErrorClass() != null && vr.getErrorClass().isInfrastructure()) {
|
||||
|
@ -1646,7 +1649,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
String nextVersion = nextCoding.getVersion();
|
||||
if (isNotBlank(nextCode) && isNotBlank(nextSystem) && context.supportsSystem(nextSystem, baseOptions.getFhirVersion())) {
|
||||
ValidationResult vr = checkCodeOnServer(stack, nextCode, nextSystem, nextVersion, null, false);
|
||||
ok = (processTxIssues(errors, vr, element, path, null, false)) && ok;
|
||||
ok = (processTxIssues(errors, vr, element, path, null, false, null)) && ok;
|
||||
if (!vr.isOk()) {
|
||||
txWarning(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CODE_NOTVALID, nextCode, nextSystem);
|
||||
}
|
||||
|
@ -1710,7 +1713,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
if (binding.getStrength() == BindingStrength.REQUIRED) {
|
||||
removeTrackedMessagesForLocation(errors, element, path);
|
||||
}
|
||||
ok = processTxIssues(errors, vr, element, path, notFoundSeverityForBinding(binding), false) && ok;
|
||||
ok = processTxIssues(errors, vr, element, path, notFoundSeverityForBinding(binding), false, binding.getValueSet()) && ok;
|
||||
timeTracker.tx(t, "vc "+system+"#"+code+" '"+display+"'");
|
||||
if (vr != null && !vr.isOk()) {
|
||||
if (vr.IsNoService())
|
||||
|
@ -1852,7 +1855,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
try {
|
||||
long t = System.nanoTime();
|
||||
ValidationResult vr = checkCodeOnServer(stack, valueset, cc);
|
||||
ok = processTxIssues(errors, vr, element, path, null, false) && ok;
|
||||
ok = processTxIssues(errors, vr, element, path, null, false, maxVSUrl) && ok;
|
||||
timeTracker.tx(t, "vc "+cc.toString());
|
||||
if (!vr.isOk()) {
|
||||
if (vr.getErrorClass() != null && vr.getErrorClass().isInfrastructure())
|
||||
|
@ -1869,7 +1872,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
}
|
||||
|
||||
// private String describeValueSet(String url) {
|
||||
// ValueSet vs = context.fetchResource(ValueSet.class, url);
|
||||
// ValueSet vs = context.findTxResource(ValueSet.class, url);
|
||||
// if (vs != null) {
|
||||
// return "'"+vs.present()+"' ("+url+")";
|
||||
// } else {
|
||||
|
@ -1891,7 +1894,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
try {
|
||||
long t = System.nanoTime();
|
||||
ValidationResult vr = checkCodeOnServer(stack, valueset, c);
|
||||
ok = processTxIssues(errors, vr, element, path, null, false) && ok;
|
||||
ok = processTxIssues(errors, vr, element, path, null, false, maxVSUrl) && ok;
|
||||
|
||||
timeTracker.tx(t, "vc "+c.getSystem()+"#"+c.getCode()+" '"+c.getDisplay()+"'");
|
||||
if (!vr.isOk()) {
|
||||
|
@ -1922,7 +1925,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
try {
|
||||
long t = System.nanoTime();
|
||||
ValidationResult vr = checkCodeOnServer(stack, valueset, value, baseOptions.withLanguage(stack.getWorkingLang()));
|
||||
ok = processTxIssues(errors, vr, element, path, null, false) && ok;
|
||||
ok = processTxIssues(errors, vr, element, path, null, false, maxVSUrl) && ok;
|
||||
timeTracker.tx(t, "vc "+value);
|
||||
if (!vr.isOk()) {
|
||||
if (vr.getErrorClass() != null && vr.getErrorClass().isInfrastructure())
|
||||
|
@ -1999,7 +2002,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
checked = true;
|
||||
vr = checkCodeOnServer(stack, valueset, c);
|
||||
}
|
||||
ok = processTxIssues(errors, vr, element, path, notFoundSeverityForBinding(binding), binding.getStrength() == BindingStrength.EXTENSIBLE) && ok;
|
||||
ok = processTxIssues(errors, vr, element, path, notFoundSeverityForBinding(binding), binding.getStrength() == BindingStrength.EXTENSIBLE, binding.getValueSet()) && ok;
|
||||
|
||||
timeTracker.tx(t, "vc "+c.getSystem()+"#"+c.getCode()+" '"+c.getDisplay()+"'");
|
||||
if (binding.getStrength() == BindingStrength.REQUIRED) {
|
||||
|
@ -3451,7 +3454,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
}
|
||||
vr = checkCodeOnServer(stack, vs, value, options);
|
||||
}
|
||||
ok = processTxIssues(errors, vr, element, path, notFoundSeverityForBinding(binding), binding.getStrength() == BindingStrength.EXTENSIBLE) && ok;
|
||||
ok = processTxIssues(errors, vr, element, path, notFoundSeverityForBinding(binding), binding.getStrength() == BindingStrength.EXTENSIBLE, binding.getValueSet()) && ok;
|
||||
|
||||
timeTracker.tx(t, "vc "+value+"");
|
||||
if (binding.getStrength() == BindingStrength.REQUIRED) {
|
||||
|
@ -7264,20 +7267,12 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
|
||||
public ValidationResult checkCodeOnServer(NodeStack stack, ValueSet valueset, Coding c) {
|
||||
codingObserver.seeCode(stack, c);
|
||||
if (false) { // #FIXME
|
||||
return checkForInactive(filterOutSpecials(stack.getLiteralPath(), valueset, context.validateCode(baseOptions.withLanguage(stack.getWorkingLang()).withCheckValueSetOnly(), c, valueset)), c);
|
||||
} else {
|
||||
return checkForInactive(filterOutSpecials(stack.getLiteralPath(), valueset, context.validateCode(baseOptions.withLanguage(stack.getWorkingLang()), c, valueset)), c);
|
||||
}
|
||||
return checkForInactive(filterOutSpecials(stack.getLiteralPath(), valueset, context.validateCode(baseOptions.withLanguage(stack.getWorkingLang()), c, valueset)), c);
|
||||
}
|
||||
|
||||
public ValidationResult checkCodeOnServer(NodeStack stack, ValueSet valueset, CodeableConcept cc) {
|
||||
codingObserver.seeCode(stack, cc);
|
||||
if (false) { // #FIXME
|
||||
return checkForInactive(filterOutSpecials(stack.getLiteralPath(), valueset, context.validateCode(baseOptions.withLanguage(stack.getWorkingLang()).withCheckValueSetOnly(), cc, valueset)), cc);
|
||||
} else {
|
||||
return checkForInactive(filterOutSpecials(stack.getLiteralPath(), valueset, context.validateCode(baseOptions.withLanguage(stack.getWorkingLang()), cc, valueset)), cc);
|
||||
}
|
||||
return checkForInactive(filterOutSpecials(stack.getLiteralPath(), valueset, context.validateCode(baseOptions.withLanguage(stack.getWorkingLang()), cc, valueset)), cc);
|
||||
}
|
||||
|
||||
private ValidationResult filterOutSpecials(String path, ValueSet vs, ValidationResult vr) {
|
||||
|
|
|
@ -194,10 +194,10 @@ public class ConceptMapValidator extends BaseValidator {
|
|||
if (ref.contains("|")) {
|
||||
res.url = ref.substring(0, ref.indexOf("|"));
|
||||
res.version = ref.substring(ref.indexOf("|")+1);
|
||||
res.vs = context.fetchResource(ValueSet.class, res.url, res.version);
|
||||
res.vs = context.findTxResource(ValueSet.class, res.url, res.version);
|
||||
} else {
|
||||
res.url = ref;
|
||||
res.vs = context.fetchResource(ValueSet.class, res.url);
|
||||
res.vs = context.findTxResource(ValueSet.class, res.url);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -894,7 +894,7 @@ public class StructureMapValidator extends BaseValidator {
|
|||
ValueSet srcVS = null;
|
||||
if (srcED != null) {
|
||||
if (warning(errors, "2023-03-01", IssueType.INVALID, line, col, literalPath, srcED.getBinding().hasValueSet() && srcED.getBinding().getStrength() == BindingStrength.REQUIRED, I18nConstants.SM_TARGET_TRANSLATE_BINDING_SOURCE)) {
|
||||
srcVS = context.fetchResource(ValueSet.class, srcED.getBinding().getValueSet());
|
||||
srcVS = context.findTxResource(ValueSet.class, srcED.getBinding().getValueSet());
|
||||
if (warning(errors, "2023-03-01", IssueType.INVALID, line, col, literalPath, srcVS != null, I18nConstants.SM_TARGET_TRANSLATE_BINDING_VS_SOURCE)) {
|
||||
ValueSetExpansionOutcome vse = context.expandVS(srcVS, true, false);
|
||||
if (warning(errors, "2023-03-01", IssueType.INVALID, line, col, literalPath, vse.isOk(), I18nConstants.SM_TARGET_TRANSLATE_BINDING_VSE_SOURCE, vse.getError())) {
|
||||
|
@ -913,7 +913,7 @@ public class StructureMapValidator extends BaseValidator {
|
|||
}
|
||||
if (srcED != null) {
|
||||
if (warning(errors, "2023-03-01", IssueType.INVALID, line, col, literalPath, tgtED.getBinding().hasValueSet() && tgtED.getBinding().getStrength() == BindingStrength.REQUIRED, I18nConstants.SM_TARGET_TRANSLATE_BINDING_TARGET)) {
|
||||
ValueSet vs = context.fetchResource(ValueSet.class, tgtED.getBinding().getValueSet());
|
||||
ValueSet vs = context.findTxResource(ValueSet.class, tgtED.getBinding().getValueSet());
|
||||
if (warning(errors, "2023-03-01", IssueType.INVALID, line, col, literalPath, vs != null, I18nConstants.SM_TARGET_TRANSLATE_BINDING_VS_TARGET)) {
|
||||
ValueSetExpansionOutcome vse = context.expandVS(vs, true, false);
|
||||
if (warning(errors, "2023-03-01", IssueType.INVALID, line, col, literalPath, vse.isOk(), I18nConstants.SM_TARGET_TRANSLATE_BINDING_VSE_TARGET, vse.getError())) {
|
||||
|
|
|
@ -123,7 +123,7 @@ public class ValueSetValidator extends BaseValidator {
|
|||
int i = 0;
|
||||
for (Element ve : valuesets) {
|
||||
String v = ve.getValue();
|
||||
ValueSet vs = context.fetchResource(ValueSet.class, v);
|
||||
ValueSet vs = context.findTxResource(ValueSet.class, v);
|
||||
if (vs == null) {
|
||||
NodeStack ns = stack.push(ve, i, ve.getProperty().getDefinition(), ve.getProperty().getDefinition());
|
||||
|
||||
|
|
|
@ -26,92 +26,92 @@ public class ElementInfo {
|
|||
this.count = count;
|
||||
}
|
||||
|
||||
public List<ValidationMessage> getSliceInfo() {
|
||||
return sliceInfo;
|
||||
}
|
||||
public List<ValidationMessage> getSliceInfo() {
|
||||
return sliceInfo;
|
||||
}
|
||||
|
||||
public ElementInfo setSliceInfo(List<ValidationMessage> sliceInfo) {
|
||||
this.sliceInfo = sliceInfo;
|
||||
return this;
|
||||
}
|
||||
public ElementInfo setSliceInfo(List<ValidationMessage> sliceInfo) {
|
||||
this.sliceInfo = sliceInfo;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
public ElementInfo setIndex(int index) {
|
||||
this.index = index;
|
||||
return this;
|
||||
}
|
||||
public ElementInfo setIndex(int index) {
|
||||
this.index = index;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getSliceindex() {
|
||||
return sliceindex;
|
||||
}
|
||||
public int getSliceindex() {
|
||||
return sliceindex;
|
||||
}
|
||||
|
||||
public ElementInfo setSliceindex(int sliceindex) {
|
||||
this.sliceindex = sliceindex;
|
||||
return this;
|
||||
}
|
||||
public ElementInfo setSliceindex(int sliceindex) {
|
||||
this.sliceindex = sliceindex;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return count;
|
||||
}
|
||||
public int getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
public ElementInfo setCount(int count) {
|
||||
this.count = count;
|
||||
return this;
|
||||
}
|
||||
public ElementInfo setCount(int count) {
|
||||
this.count = count;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ElementDefinition getDefinition() {
|
||||
return definition;
|
||||
}
|
||||
public ElementDefinition getDefinition() {
|
||||
return definition;
|
||||
}
|
||||
|
||||
public ElementInfo setDefinition(ElementDefinition definition) {
|
||||
this.definition = definition;
|
||||
return this;
|
||||
}
|
||||
public ElementInfo setDefinition(ElementDefinition definition) {
|
||||
this.definition = definition;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ElementDefinition getSlice() {
|
||||
return slice;
|
||||
}
|
||||
public ElementDefinition getSlice() {
|
||||
return slice;
|
||||
}
|
||||
|
||||
public ElementInfo setSlice(ElementDefinition slice) {
|
||||
this.slice = slice;
|
||||
return this;
|
||||
}
|
||||
public ElementInfo setSlice(ElementDefinition slice) {
|
||||
this.slice = slice;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isAdditionalSlice() {
|
||||
return additionalSlice;
|
||||
}
|
||||
public boolean isAdditionalSlice() {
|
||||
return additionalSlice;
|
||||
}
|
||||
|
||||
public ElementInfo setAdditionalSlice(boolean additionalSlice) {
|
||||
this.additionalSlice = additionalSlice;
|
||||
return this;
|
||||
}
|
||||
public ElementInfo setAdditionalSlice(boolean additionalSlice) {
|
||||
this.additionalSlice = additionalSlice;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Element getElement() {
|
||||
return element;
|
||||
}
|
||||
public Element getElement() {
|
||||
return element;
|
||||
}
|
||||
|
||||
public ElementInfo setElement(Element element) {
|
||||
this.element = element;
|
||||
return this;
|
||||
}
|
||||
public ElementInfo setElement(Element element) {
|
||||
this.element = element;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public ElementInfo setName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
public ElementInfo setName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public int col() {
|
||||
public int col() {
|
||||
return element.col();
|
||||
}
|
||||
|
||||
|
|
|
@ -139,7 +139,7 @@ public class TxTester {
|
|||
|
||||
private ITerminologyClient connectToServer() throws URISyntaxException {
|
||||
System.out.println("Connect to "+server);
|
||||
return new TerminologyClientFactory(FhirPublication.R4).makeClient("Test-Server", server, "Tools/Java");
|
||||
return new TerminologyClientFactory(FhirPublication.R4).makeClient("Test-Server", server, "Tools/Java", null);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -89,6 +89,7 @@ public class TxTesterScrubbers {
|
|||
|
||||
public static void scrubOO(OperationOutcome po, boolean tight) {
|
||||
scrubDR(po, tight);
|
||||
po.getIssue().removeIf(i -> i.hasDiagnostics() & !i.hasDetails());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
package org.hl7.fhir.validation.special;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.ParametersParameter;
|
||||
import org.hl7.fhir.r5.model.Base;
|
||||
|
@ -10,12 +12,14 @@ import org.hl7.fhir.r5.model.OperationOutcome;
|
|||
import org.hl7.fhir.r5.model.OperationOutcome.OperationOutcomeIssueComponent;
|
||||
import org.hl7.fhir.r5.model.Parameters;
|
||||
import org.hl7.fhir.r5.model.Parameters.ParametersParameterComponent;
|
||||
import org.hl7.fhir.r5.model.StringType;
|
||||
import org.hl7.fhir.r5.model.ValueSet;
|
||||
import org.hl7.fhir.r5.model.ValueSet.ConceptPropertyComponent;
|
||||
import org.hl7.fhir.r5.model.ValueSet.ConceptReferenceDesignationComponent;
|
||||
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent;
|
||||
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionParameterComponent;
|
||||
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionPropertyComponent;
|
||||
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
|
||||
|
||||
public class TxTesterSorters {
|
||||
|
||||
|
@ -27,6 +31,17 @@ public class TxTesterSorters {
|
|||
if (p.getResource() != null && p.getResource() instanceof OperationOutcome) {
|
||||
Collections.sort(((OperationOutcome) p.getResource()).getIssue(), new TxTesterSorters.OperationIssueSorter());
|
||||
}
|
||||
if ("message".equals(p.getName()) && p.hasValuePrimitive()) {
|
||||
String pv = p.getValue().primitiveValue();
|
||||
if (pv.contains("; ")) {
|
||||
List<String> bits = new ArrayList<>();
|
||||
for (String s : pv.split("\\; ")) {
|
||||
bits.add(s);
|
||||
}
|
||||
Collections.sort(bits);
|
||||
p.setValue(new StringType(CommaSeparatedStringBuilder.join("; ", bits)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -125,7 +125,7 @@ public class UtilitiesXTests {
|
|||
if (!Utilities.noString(s))
|
||||
return s;
|
||||
s = "C:\\work\\org.hl7.fhir\\build";
|
||||
// FIXME: change this back
|
||||
// TODO - what should we do here?
|
||||
s = "/Users/jamesagnew/git/fhir";
|
||||
if (new File(s).exists())
|
||||
return s;
|
||||
|
|
|
@ -43,6 +43,7 @@ import org.hl7.fhir.r5.test.utils.TestingUtilities;
|
|||
import org.hl7.fhir.utilities.FhirPublication;
|
||||
import org.hl7.fhir.utilities.TextFile;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.i18n.I18nConstants;
|
||||
import org.hl7.fhir.utilities.json.model.JsonObject;
|
||||
import org.hl7.fhir.utilities.validation.ValidationOptions;
|
||||
import org.hl7.fhir.validation.ValidationEngine;
|
||||
|
@ -244,64 +245,80 @@ public class TerminologyServiceTests {
|
|||
private void validate(ValidationEngine engine, String name, Resource req, String resp, String lang, String fp, JsonObject ext, boolean isCS) throws JsonSyntaxException, FileNotFoundException, IOException {
|
||||
org.hl7.fhir.r5.model.Parameters p = (org.hl7.fhir.r5.model.Parameters) req;
|
||||
ValueSet vs = null;
|
||||
String vsurl = null;
|
||||
if (!isCS) {
|
||||
if (p.hasParameter("valueSetVersion")) {
|
||||
vsurl = p.getParameterValue("url").primitiveValue()+"|"+p.getParameterValue("valueSetVersion").primitiveValue();
|
||||
vs = engine.getContext().fetchResource(ValueSet.class, p.getParameterValue("url").primitiveValue(), p.getParameterValue("valueSetVersion").primitiveValue());
|
||||
} else {
|
||||
vsurl = p.getParameterValue("url").primitiveValue();
|
||||
vs = engine.getContext().fetchResource(ValueSet.class, p.getParameterValue("url").primitiveValue());
|
||||
}
|
||||
}
|
||||
ValidationOptions options = new ValidationOptions(FhirPublication.R5);
|
||||
if (p.hasParameter("displayLanguage")) {
|
||||
options = options.withLanguage(p.getParameterString("displayLanguage"));
|
||||
} else if (lang != null ) {
|
||||
options = options.withLanguage(lang);
|
||||
}
|
||||
if (p.hasParameter("valueset-membership-only") && "true".equals(p.getParameterString("valueset-membership-only"))) {
|
||||
options = options.withCheckValueSetOnly();
|
||||
}
|
||||
if (p.hasParameter("lenient-display-validation") && "true".equals(p.getParameterString("lenient-display-validation"))) {
|
||||
options = options.setDisplayWarningMode(true);
|
||||
}
|
||||
if (p.hasParameter("activeOnly") && "true".equals(p.getParameterString("activeOnly"))) {
|
||||
options = options.setActiveOnly(true);
|
||||
}
|
||||
engine.getContext().getExpansionParameters().clearParameters("includeAlternateCodes");
|
||||
for (ParametersParameterComponent pp : p.getParameter()) {
|
||||
if ("includeAlternateCodes".equals(pp.getName())) {
|
||||
engine.getContext().getExpansionParameters().addParameter(pp.copy());
|
||||
}
|
||||
}
|
||||
ValidationResult vm;
|
||||
ValidationResult vm = null;
|
||||
String code = null;
|
||||
String system = null;
|
||||
String version = null;
|
||||
String display = null;
|
||||
CodeableConcept cc = null;
|
||||
if (p.hasParameter("code")) {
|
||||
code = p.getParameterString("code");
|
||||
system = p.getParameterString(isCS ? "url" : "system");
|
||||
version = p.getParameterString(isCS ? "version" : "systemVersion");
|
||||
display = p.getParameterString("display");
|
||||
vm = engine.getContext().validateCode(options.withGuessSystem(),
|
||||
p.getParameterString(isCS ? "url" : "system"), p.getParameterString(isCS ? "version" : "systemVersion"),
|
||||
p.getParameterString("code"), p.getParameterString("display"), vs);
|
||||
} else if (p.hasParameter("coding")) {
|
||||
Coding coding = (Coding) p.getParameterValue("coding");
|
||||
code = coding.getCode();
|
||||
system = coding.getSystem();
|
||||
version = coding.getVersion();
|
||||
display = coding.getDisplay();
|
||||
vm = engine.getContext().validateCode(options, coding, vs);
|
||||
} else if (p.hasParameter("codeableConcept")) {
|
||||
cc = (CodeableConcept) p.getParameterValue("codeableConcept");
|
||||
vm = engine.getContext().validateCode(options, cc, vs);
|
||||
org.hl7.fhir.r5.model.Parameters res = null;
|
||||
OperationOutcome oo = null;
|
||||
|
||||
if (vs == null && vsurl != null) {
|
||||
String msg = engine.getContext().formatMessage(I18nConstants.UNABLE_TO_RESOLVE_VALUE_SET_, vsurl);
|
||||
oo = new OperationOutcome();
|
||||
CodeableConcept cct = oo.addIssue().setSeverity(IssueSeverity.ERROR).setCode(IssueType.NOTFOUND).getDetails();
|
||||
cct.addCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", "not-found", null);
|
||||
cct.setText(msg);
|
||||
} else {
|
||||
throw new Error("validate not done yet for this steup");
|
||||
ValidationOptions options = new ValidationOptions(FhirPublication.R5);
|
||||
if (p.hasParameter("displayLanguage")) {
|
||||
options = options.withLanguage(p.getParameterString("displayLanguage"));
|
||||
} else if (lang != null ) {
|
||||
options = options.withLanguage(lang);
|
||||
}
|
||||
if (p.hasParameter("valueset-membership-only") && "true".equals(p.getParameterString("valueset-membership-only"))) {
|
||||
options = options.withCheckValueSetOnly();
|
||||
}
|
||||
if (p.hasParameter("lenient-display-validation") && "true".equals(p.getParameterString("lenient-display-validation"))) {
|
||||
options = options.setDisplayWarningMode(true);
|
||||
}
|
||||
if (p.hasParameter("activeOnly") && "true".equals(p.getParameterString("activeOnly"))) {
|
||||
options = options.setActiveOnly(true);
|
||||
}
|
||||
engine.getContext().getExpansionParameters().clearParameters("includeAlternateCodes");
|
||||
for (ParametersParameterComponent pp : p.getParameter()) {
|
||||
if ("includeAlternateCodes".equals(pp.getName())) {
|
||||
engine.getContext().getExpansionParameters().addParameter(pp.copy());
|
||||
}
|
||||
}
|
||||
if (p.hasParameter("code")) {
|
||||
code = p.getParameterString("code");
|
||||
system = p.getParameterString(isCS ? "url" : "system");
|
||||
version = p.getParameterString(isCS ? "version" : "systemVersion");
|
||||
display = p.getParameterString("display");
|
||||
vm = engine.getContext().validateCode(options.withGuessSystem(),
|
||||
p.getParameterString(isCS ? "url" : "system"), p.getParameterString(isCS ? "version" : "systemVersion"),
|
||||
p.getParameterString("code"), p.getParameterString("display"), vs);
|
||||
} else if (p.hasParameter("coding")) {
|
||||
Coding coding = (Coding) p.getParameterValue("coding");
|
||||
code = coding.getCode();
|
||||
system = coding.getSystem();
|
||||
version = coding.getVersion();
|
||||
display = coding.getDisplay();
|
||||
vm = engine.getContext().validateCode(options, coding, vs);
|
||||
} else if (p.hasParameter("codeableConcept")) {
|
||||
cc = (CodeableConcept) p.getParameterValue("codeableConcept");
|
||||
vm = engine.getContext().validateCode(options, cc, vs);
|
||||
} else {
|
||||
throw new Error("validate not done yet for this steup");
|
||||
}
|
||||
}
|
||||
if (vm.getSeverity() == org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity.FATAL) {
|
||||
OperationOutcome oo = new OperationOutcome();
|
||||
if (oo == null && vm != null && vm.getSeverity() == org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity.FATAL) {
|
||||
oo = new OperationOutcome();
|
||||
oo.getIssue().addAll(vm.getIssues());
|
||||
}
|
||||
if (oo != null) {
|
||||
TxTesterSorters.sortOperationOutcome(oo);
|
||||
TxTesterScrubbers.scrubOO(oo, false);
|
||||
|
||||
|
@ -314,57 +331,60 @@ public class TerminologyServiceTests {
|
|||
}
|
||||
Assertions.assertTrue(diff == null, diff);
|
||||
} else {
|
||||
org.hl7.fhir.r5.model.Parameters res = new org.hl7.fhir.r5.model.Parameters();
|
||||
if (vm.getSystem() != null) {
|
||||
res.addParameter("system", new UriType(vm.getSystem()));
|
||||
} else if (system != null) {
|
||||
res.addParameter("system", new UriType(system));
|
||||
}
|
||||
if (vm.getCode() != null) {
|
||||
res.addParameter("code", new CodeType(vm.getCode()));
|
||||
} else if (code != null) {
|
||||
res.addParameter("code", new CodeType(code));
|
||||
}
|
||||
if (vm.getSeverity() == org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity.ERROR) {
|
||||
res.addParameter("result", false);
|
||||
} else {
|
||||
res.addParameter("result", true);
|
||||
}
|
||||
if (vm.getMessage() != null) {
|
||||
res.addParameter("message", vm.getMessage());
|
||||
}
|
||||
if (vm.getVersion() != null) {
|
||||
res.addParameter("version", vm.getVersion());
|
||||
} else if (version != null) {
|
||||
res.addParameter("version", new StringType(version));
|
||||
}
|
||||
if (vm.getDisplay() != null) {
|
||||
res.addParameter("display", vm.getDisplay());
|
||||
} else if (display != null) {
|
||||
res.addParameter("display", new StringType(display));
|
||||
}
|
||||
// if (vm.getCodeableConcept() != null) {
|
||||
// res.addParameter("codeableConcept", vm.getCodeableConcept());
|
||||
// } else
|
||||
if (cc != null) {
|
||||
res.addParameter("codeableConcept", cc);
|
||||
}
|
||||
if (vm.isInactive()) {
|
||||
res.addParameter("inactive", true);
|
||||
}
|
||||
if (vm.getStatus() != null) {
|
||||
res.addParameter("status", vm.getStatus());
|
||||
}
|
||||
if (vm.getUnknownSystems() != null) {
|
||||
for (String s : vm.getUnknownSystems()) {
|
||||
res.addParameter("x-caused-by-unknown-system", new CanonicalType(s));
|
||||
if (res == null) {
|
||||
res = new org.hl7.fhir.r5.model.Parameters();
|
||||
if (vm.getSystem() != null) {
|
||||
res.addParameter("system", new UriType(vm.getSystem()));
|
||||
} else if (system != null) {
|
||||
res.addParameter("system", new UriType(system));
|
||||
}
|
||||
if (vm.getCode() != null) {
|
||||
res.addParameter("code", new CodeType(vm.getCode()));
|
||||
} else if (code != null) {
|
||||
res.addParameter("code", new CodeType(code));
|
||||
}
|
||||
if (vm.getSeverity() == org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity.ERROR) {
|
||||
res.addParameter("result", false);
|
||||
} else {
|
||||
res.addParameter("result", true);
|
||||
}
|
||||
if (vm.getMessage() != null) {
|
||||
res.addParameter("message", vm.getMessage());
|
||||
}
|
||||
if (vm.getVersion() != null) {
|
||||
res.addParameter("version", vm.getVersion());
|
||||
} else if (version != null) {
|
||||
res.addParameter("version", new StringType(version));
|
||||
}
|
||||
if (vm.getDisplay() != null) {
|
||||
res.addParameter("display", vm.getDisplay());
|
||||
} else if (display != null) {
|
||||
res.addParameter("display", new StringType(display));
|
||||
}
|
||||
// if (vm.getCodeableConcept() != null) {
|
||||
// res.addParameter("codeableConcept", vm.getCodeableConcept());
|
||||
// } else
|
||||
if (cc != null) {
|
||||
res.addParameter("codeableConcept", cc);
|
||||
}
|
||||
if (vm.isInactive()) {
|
||||
res.addParameter("inactive", true);
|
||||
}
|
||||
if (vm.getStatus() != null) {
|
||||
res.addParameter("status", vm.getStatus());
|
||||
}
|
||||
if (vm.getUnknownSystems() != null) {
|
||||
for (String s : vm.getUnknownSystems()) {
|
||||
res.addParameter("x-caused-by-unknown-system", new CanonicalType(s));
|
||||
}
|
||||
}
|
||||
if (vm.getIssues().size() > 0) {
|
||||
oo = new OperationOutcome();
|
||||
oo.getIssue().addAll(vm.getIssues());
|
||||
res.addParameter().setName("issues").setResource(oo);
|
||||
}
|
||||
}
|
||||
if (vm.getIssues().size() > 0) {
|
||||
OperationOutcome oo = new OperationOutcome();
|
||||
oo.getIssue().addAll(vm.getIssues());
|
||||
res.addParameter().setName("issues").setResource(oo);
|
||||
}
|
||||
|
||||
TxTesterSorters.sortParameters(res);
|
||||
TxTesterScrubbers.scrubParams(res);
|
||||
|
||||
|
|
|
@ -186,7 +186,7 @@ public class ValidationEngineTests {
|
|||
OperationOutcome op = ve.validate(FhirFormat.JSON, TestingUtilities.loadTestResourceStream("validator", "observation102.json"), null);
|
||||
if (!TestUtilities.silent)
|
||||
for (OperationOutcomeIssueComponent iss : op.getIssue()) {
|
||||
System.out.println(" " + iss.getDetails().getText());
|
||||
System.out.println(" "+iss.getSeverity().toCode()+": "+ iss.getDetails().getText());
|
||||
}
|
||||
int e = errors(op);
|
||||
int w = warnings(op);
|
||||
|
@ -265,12 +265,12 @@ public class ValidationEngineTests {
|
|||
OperationOutcome op = ve.validate(FhirFormat.JSON, TestingUtilities.loadTestResourceStream("validator", "observation401_ucum.json"), profiles);
|
||||
if (!TestUtilities.silent)
|
||||
for (OperationOutcomeIssueComponent issue : op.getIssue())
|
||||
System.out.println(" - " + issue.getDetails().getText());
|
||||
System.out.println(" - "+issue.getSeverity().toCode()+": " + issue.getDetails().getText());
|
||||
int e = errors(op);
|
||||
int w = warnings(op);
|
||||
int h = hints(op);
|
||||
Assertions.assertEquals(0, e);
|
||||
Assertions.assertEquals(5, w);
|
||||
Assertions.assertEquals(6, w);
|
||||
Assertions.assertEquals(2, h);
|
||||
assertTrue(logger.verifyHasNoRequests(), "Unexpected request to TX server");
|
||||
if (!TestUtilities.silent)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
3
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"http://somewhere/something-else" : null,
|
||||
"http://loinc.org/vs/LL715-4" : null,
|
||||
"http://hl7.org/fhir/us/vrdr/ValueSet/vrdr-PlaceOfDeath" : null,
|
||||
"http://somewhere/something" : null
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
{
|
||||
"resourceType" : "CapabilityStatement",
|
||||
"id" : "FhirServer",
|
||||
"meta" : {
|
||||
"tag" : [{
|
||||
"system" : "http://hl7.org/fhir/v3/ObservationValue",
|
||||
"code" : "SUBSETTED",
|
||||
"display" : "Subsetted"
|
||||
}]
|
||||
},
|
||||
"extension" : [{
|
||||
"url" : "http://hl7.org/fhir/3.0/StructureDefinition/extension-CapabilityStatement.acceptUnknown",
|
||||
"valueCode" : "both"
|
||||
}],
|
||||
"url" : "http://tx-dev.fhir.org/r2/metadata",
|
||||
"version" : "1.0.2-3.1.0",
|
||||
"name" : "FHIR Reference Server Conformance Statement",
|
||||
"status" : "active",
|
||||
"date" : "2024-01-10T05:45:51.112Z",
|
||||
"contact" : [{
|
||||
"telecom" : [{
|
||||
"system" : "other",
|
||||
"value" : "http://healthintersections.com.au/"
|
||||
}]
|
||||
}],
|
||||
"description" : "Standard Conformance Statement for the open source Reference FHIR Server provided by Health Intersections",
|
||||
"kind" : "instance",
|
||||
"software" : {
|
||||
"name" : "Reference Server",
|
||||
"version" : "3.1.0",
|
||||
"releaseDate" : "2024-01-08T12:29:45.425Z"
|
||||
},
|
||||
"implementation" : {
|
||||
"description" : "FHIR Server running at http://tx-dev.fhir.org/r2",
|
||||
"url" : "http://tx-dev.fhir.org/r2"
|
||||
},
|
||||
"fhirVersion" : "1.0.2",
|
||||
"format" : ["application/xml+fhir",
|
||||
"application/json+fhir"],
|
||||
"rest" : [{
|
||||
"mode" : "server"
|
||||
}]
|
||||
}
|
|
@ -1,44 +1,4 @@
|
|||
-------------------------------------------------------------------------------------
|
||||
{"code" : {
|
||||
"system" : "http://acme.org/devices/clinical-codes",
|
||||
"code" : "body-weight",
|
||||
"display" : "Body Weight"
|
||||
}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"false", "guessSystem":"false", "activeOnly":"false", "membershipOnly":"false", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
|
||||
"resourceType" : "Parameters",
|
||||
"parameter" : [{
|
||||
"name" : "profile-url",
|
||||
"valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891"
|
||||
}]
|
||||
}}####
|
||||
v: {
|
||||
"code" : "body-weight",
|
||||
"severity" : "error",
|
||||
"error" : "A definition for CodeSystem 'http://acme.org/devices/clinical-codes' could not be found, so the code cannot be validated",
|
||||
"class" : "CODESYSTEM_UNSUPPORTED",
|
||||
"server" : "http://tx-dev.fhir.org/r2",
|
||||
"unknown-systems" : "http://acme.org/devices/clinical-codes",
|
||||
"issues" : {
|
||||
"resourceType" : "OperationOutcome",
|
||||
"issue" : [{
|
||||
"extension" : [{
|
||||
"url" : "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-server",
|
||||
"valueUrl" : "http://tx-dev.fhir.org/r2"
|
||||
}],
|
||||
"severity" : "error",
|
||||
"code" : "not-found",
|
||||
"details" : {
|
||||
"coding" : [{
|
||||
"system" : "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type",
|
||||
"code" : "not-found"
|
||||
}],
|
||||
"text" : "A definition for CodeSystem 'http://acme.org/devices/clinical-codes' could not be found, so the code cannot be validated"
|
||||
},
|
||||
"location" : ["Coding.system"]
|
||||
}]
|
||||
}
|
||||
|
||||
}
|
||||
-------------------------------------------------------------------------------------
|
||||
{"code" : {
|
||||
"system" : "http://acme.org/devices/clinical-codes",
|
||||
"code" : "body-weight",
|
||||
|
@ -79,3 +39,43 @@ v: {
|
|||
|
||||
}
|
||||
-------------------------------------------------------------------------------------
|
||||
{"code" : {
|
||||
"system" : "http://acme.org/devices/clinical-codes",
|
||||
"code" : "body-weight",
|
||||
"display" : "Body Weight"
|
||||
}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"false", "guessSystem":"false", "activeOnly":"false", "membershipOnly":"false", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
|
||||
"resourceType" : "Parameters",
|
||||
"parameter" : [{
|
||||
"name" : "profile-url",
|
||||
"valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891"
|
||||
}]
|
||||
}}####
|
||||
v: {
|
||||
"code" : "body-weight",
|
||||
"severity" : "error",
|
||||
"error" : "A definition for CodeSystem 'http://acme.org/devices/clinical-codes' could not be found, so the code cannot be validated",
|
||||
"class" : "CODESYSTEM_UNSUPPORTED",
|
||||
"server" : "http://tx-dev.fhir.org/r2",
|
||||
"unknown-systems" : "http://acme.org/devices/clinical-codes",
|
||||
"issues" : {
|
||||
"resourceType" : "OperationOutcome",
|
||||
"issue" : [{
|
||||
"extension" : [{
|
||||
"url" : "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-server",
|
||||
"valueUrl" : "http://tx-dev.fhir.org/r2"
|
||||
}],
|
||||
"severity" : "error",
|
||||
"code" : "not-found",
|
||||
"details" : {
|
||||
"coding" : [{
|
||||
"system" : "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type",
|
||||
"code" : "not-found"
|
||||
}],
|
||||
"text" : "A definition for CodeSystem 'http://acme.org/devices/clinical-codes' could not be found, so the code cannot be validated"
|
||||
},
|
||||
"location" : ["Coding.system"]
|
||||
}]
|
||||
}
|
||||
|
||||
}
|
||||
-------------------------------------------------------------------------------------
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"system" : "http://loinc.org",
|
||||
"code" : "3141-9",
|
||||
"display" : "Weight Measured"
|
||||
}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"false", "guessSystem":"false", "activeOnly":"false", "membershipOnly":"false", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
|
||||
}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"false", "guessSystem":"false", "activeOnly":"false", "membershipOnly":"false", "displayWarningMode":"false", "versionFlexible":"true", "profile": {
|
||||
"resourceType" : "Parameters",
|
||||
"parameter" : [{
|
||||
"name" : "profile-url",
|
||||
|
@ -26,7 +26,7 @@ v: {
|
|||
"system" : "http://loinc.org",
|
||||
"code" : "3141-9",
|
||||
"display" : "Weight Measured"
|
||||
}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"false", "guessSystem":"false", "activeOnly":"false", "membershipOnly":"false", "displayWarningMode":"false", "versionFlexible":"true", "profile": {
|
||||
}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"false", "guessSystem":"false", "activeOnly":"false", "membershipOnly":"false", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
|
||||
"resourceType" : "Parameters",
|
||||
"parameter" : [{
|
||||
"name" : "profile-url",
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
[servers]
|
||||
tx-dev.fhir.org.r2 = http://tx-dev.fhir.org/r2
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
"system" : "http://snomed.info/sct",
|
||||
"code" : "27113001",
|
||||
"display" : "Body weight"
|
||||
}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"false", "guessSystem":"false", "activeOnly":"false", "membershipOnly":"false", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
|
||||
}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"false", "guessSystem":"false", "activeOnly":"false", "membershipOnly":"false", "displayWarningMode":"false", "versionFlexible":"true", "profile": {
|
||||
"resourceType" : "Parameters",
|
||||
"parameter" : [{
|
||||
"name" : "profile-url",
|
||||
|
@ -26,7 +26,7 @@ v: {
|
|||
"system" : "http://snomed.info/sct",
|
||||
"code" : "27113001",
|
||||
"display" : "Body weight"
|
||||
}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"false", "guessSystem":"false", "activeOnly":"false", "membershipOnly":"false", "displayWarningMode":"false", "versionFlexible":"true", "profile": {
|
||||
}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"false", "guessSystem":"false", "activeOnly":"false", "membershipOnly":"false", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
|
||||
"resourceType" : "Parameters",
|
||||
"parameter" : [{
|
||||
"name" : "profile-url",
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
{"code" : {
|
||||
"system" : "http://unitsofmeasure.org",
|
||||
"code" : "[lb_av]"
|
||||
}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"true", "guessSystem":"false", "activeOnly":"false", "membershipOnly":"false", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
|
||||
}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"true", "guessSystem":"false", "activeOnly":"false", "membershipOnly":"false", "displayWarningMode":"false", "versionFlexible":"true", "profile": {
|
||||
"resourceType" : "Parameters",
|
||||
"parameter" : [{
|
||||
"name" : "profile-url",
|
||||
|
@ -24,7 +24,7 @@ v: {
|
|||
{"code" : {
|
||||
"system" : "http://unitsofmeasure.org",
|
||||
"code" : "[lb_av]"
|
||||
}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"true", "guessSystem":"false", "activeOnly":"false", "membershipOnly":"false", "displayWarningMode":"false", "versionFlexible":"true", "profile": {
|
||||
}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"true", "guessSystem":"false", "activeOnly":"false", "membershipOnly":"false", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
|
||||
"resourceType" : "Parameters",
|
||||
"parameter" : [{
|
||||
"name" : "profile-url",
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
3
|
|
@ -1,70 +0,0 @@
|
|||
{
|
||||
"resourceType" : "CapabilityStatement",
|
||||
"id" : "FhirServer",
|
||||
"meta" : {
|
||||
"tag" : [{
|
||||
"system" : "http://hl7.org/fhir/v3/ObservationValue",
|
||||
"code" : "SUBSETTED",
|
||||
"display" : "Subsetted"
|
||||
}]
|
||||
},
|
||||
"extension" : [{
|
||||
"url" : "http://hl7.org/fhir/3.0/StructureDefinition/extension-CapabilityStatement.acceptUnknown",
|
||||
"valueCode" : "both"
|
||||
}],
|
||||
"url" : "http://tx-dev.fhir.org/r3/metadata",
|
||||
"version" : "3.0.2-3.1.0",
|
||||
"name" : "FHIR Reference Server Conformance Statement",
|
||||
"status" : "active",
|
||||
"date" : "2024-01-10T05:46:10.065Z",
|
||||
"contact" : [{
|
||||
"telecom" : [{
|
||||
"system" : "other",
|
||||
"value" : "http://healthintersections.com.au/"
|
||||
}]
|
||||
}],
|
||||
"kind" : "instance",
|
||||
"instantiates" : ["http://hl7.org/fhir/CapabilityStatement/terminology-server"],
|
||||
"software" : {
|
||||
"name" : "Reference Server",
|
||||
"version" : "3.1.0",
|
||||
"releaseDate" : "2024-01-08T12:29:45.425Z"
|
||||
},
|
||||
"implementation" : {
|
||||
"description" : "FHIR Server running at http://tx-dev.fhir.org/r3",
|
||||
"url" : "http://tx-dev.fhir.org/r3"
|
||||
},
|
||||
"fhirVersion" : "3.0.2",
|
||||
"format" : ["application/fhir+xml",
|
||||
"application/fhir+json"],
|
||||
"rest" : [{
|
||||
"mode" : "server",
|
||||
"security" : {
|
||||
"cors" : true
|
||||
},
|
||||
"operation" : [{
|
||||
"name" : "expand",
|
||||
"definition" : "http://hl7.org/fhir/OperationDefinition/ValueSet-expand"
|
||||
},
|
||||
{
|
||||
"name" : "lookup",
|
||||
"definition" : "http://hl7.org/fhir/OperationDefinition/ValueSet-lookup"
|
||||
},
|
||||
{
|
||||
"name" : "validate-code",
|
||||
"definition" : "http://hl7.org/fhir/OperationDefinition/Resource-validate"
|
||||
},
|
||||
{
|
||||
"name" : "translate",
|
||||
"definition" : "http://hl7.org/fhir/OperationDefinition/ConceptMap-translate"
|
||||
},
|
||||
{
|
||||
"name" : "closure",
|
||||
"definition" : "http://hl7.org/fhir/OperationDefinition/ConceptMap-closure"
|
||||
},
|
||||
{
|
||||
"name" : "versions",
|
||||
"definition" : "http://tx-dev.fhir.org/r3/OperationDefinition/fso-versions"
|
||||
}]
|
||||
}]
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
[servers]
|
||||
tx-dev.fhir.org.r3 = http://tx-dev.fhir.org/r3
|
||||
|
|
@ -0,0 +1 @@
|
|||
3
|
|
@ -1,70 +0,0 @@
|
|||
{
|
||||
"resourceType" : "CapabilityStatement",
|
||||
"id" : "FhirServer",
|
||||
"meta" : {
|
||||
"tag" : [{
|
||||
"system" : "http://hl7.org/fhir/v3/ObservationValue",
|
||||
"code" : "SUBSETTED",
|
||||
"display" : "Subsetted"
|
||||
}]
|
||||
},
|
||||
"extension" : [{
|
||||
"url" : "http://hl7.org/fhir/3.0/StructureDefinition/extension-CapabilityStatement.acceptUnknown",
|
||||
"valueCode" : "both"
|
||||
}],
|
||||
"url" : "http://tx-dev.fhir.org/r3/metadata",
|
||||
"version" : "3.0.2-3.1.0",
|
||||
"name" : "FHIR Reference Server Conformance Statement",
|
||||
"status" : "active",
|
||||
"date" : "2024-01-10T05:46:15.222Z",
|
||||
"contact" : [{
|
||||
"telecom" : [{
|
||||
"system" : "other",
|
||||
"value" : "http://healthintersections.com.au/"
|
||||
}]
|
||||
}],
|
||||
"kind" : "instance",
|
||||
"instantiates" : ["http://hl7.org/fhir/CapabilityStatement/terminology-server"],
|
||||
"software" : {
|
||||
"name" : "Reference Server",
|
||||
"version" : "3.1.0",
|
||||
"releaseDate" : "2024-01-08T12:29:45.425Z"
|
||||
},
|
||||
"implementation" : {
|
||||
"description" : "FHIR Server running at http://tx-dev.fhir.org/r3",
|
||||
"url" : "http://tx-dev.fhir.org/r3"
|
||||
},
|
||||
"fhirVersion" : "3.0.2",
|
||||
"format" : ["application/fhir+xml",
|
||||
"application/fhir+json"],
|
||||
"rest" : [{
|
||||
"mode" : "server",
|
||||
"security" : {
|
||||
"cors" : true
|
||||
},
|
||||
"operation" : [{
|
||||
"name" : "expand",
|
||||
"definition" : "http://hl7.org/fhir/OperationDefinition/ValueSet-expand"
|
||||
},
|
||||
{
|
||||
"name" : "lookup",
|
||||
"definition" : "http://hl7.org/fhir/OperationDefinition/ValueSet-lookup"
|
||||
},
|
||||
{
|
||||
"name" : "validate-code",
|
||||
"definition" : "http://hl7.org/fhir/OperationDefinition/Resource-validate"
|
||||
},
|
||||
{
|
||||
"name" : "translate",
|
||||
"definition" : "http://hl7.org/fhir/OperationDefinition/ConceptMap-translate"
|
||||
},
|
||||
{
|
||||
"name" : "closure",
|
||||
"definition" : "http://hl7.org/fhir/OperationDefinition/ConceptMap-closure"
|
||||
},
|
||||
{
|
||||
"name" : "versions",
|
||||
"definition" : "http://tx-dev.fhir.org/r3/OperationDefinition/fso-versions"
|
||||
}]
|
||||
}]
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue