Validation sessions (#443)
* Sessions are working, * adding javadocs to cache * These changes were already added, the merge re-added them to the RELEASE_NOTES by mistake. * cleaning code a little
This commit is contained in:
parent
f08f4aec85
commit
b700d82eab
|
@ -0,0 +1 @@
|
|||
* adding session ids to validator service
|
|
@ -100,6 +100,11 @@
|
|||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-collections4</artifactId>
|
||||
<version>4.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.fhir</groupId>
|
||||
<artifactId>ucum</artifactId>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package org.hl7.fhir.validation;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import lombok.Getter;
|
||||
import org.hl7.fhir.convertors.*;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
|
@ -15,12 +16,15 @@ import org.hl7.fhir.utilities.IniFile;
|
|||
import org.hl7.fhir.utilities.TextFile;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.VersionUtilities;
|
||||
import org.hl7.fhir.utilities.json.JSONUtil;
|
||||
import org.hl7.fhir.utilities.json.JsonTrackingParser;
|
||||
import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager;
|
||||
import org.hl7.fhir.utilities.npm.NpmPackage;
|
||||
import org.hl7.fhir.utilities.turtle.Turtle;
|
||||
import org.hl7.fhir.utilities.xml.XMLUtil;
|
||||
import org.hl7.fhir.validation.cli.utils.Common;
|
||||
import org.hl7.fhir.validation.cli.utils.VersionSourceInformation;
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.HttpURLConnection;
|
||||
|
@ -199,6 +203,43 @@ public class IgLoader {
|
|||
versions.see(readInfoVersion(source.get("version.info")), "version.info in " + src);
|
||||
}
|
||||
|
||||
public void scanForVersions(List<String> sources, VersionSourceInformation versions) throws FHIRException, IOException {
|
||||
List<String> refs = new ArrayList<String>();
|
||||
ValidatorUtils.parseSources(sources, refs, context);
|
||||
for (String ref : refs) {
|
||||
Content cnt = loadContent(ref, "validate", false);
|
||||
String s = TextFile.bytesToString(cnt.focus);
|
||||
if (s.contains("http://hl7.org/fhir/3.0")) {
|
||||
versions.see("3.0", "Profile in " + ref);
|
||||
}
|
||||
if (s.contains("http://hl7.org/fhir/1.0")) {
|
||||
versions.see("1.0", "Profile in " + ref);
|
||||
}
|
||||
if (s.contains("http://hl7.org/fhir/4.0")) {
|
||||
versions.see("4.0", "Profile in " + ref);
|
||||
}
|
||||
if (s.contains("http://hl7.org/fhir/1.4")) {
|
||||
versions.see("1.4", "Profile in " + ref);
|
||||
}
|
||||
try {
|
||||
if (s.startsWith("{")) {
|
||||
JsonObject json = JsonTrackingParser.parse(s, null);
|
||||
if (json.has("fhirVersion")) {
|
||||
versions.see(VersionUtilities.getMajMin(JSONUtil.str(json, "fhirVersion")), "fhirVersion in " + ref);
|
||||
}
|
||||
} else {
|
||||
Document doc = ValidatorUtils.parseXml(cnt.focus);
|
||||
String v = XMLUtil.getNamedChildValue(doc.getDocumentElement(), "fhirVersion");
|
||||
if (v != null) {
|
||||
versions.see(VersionUtilities.getMajMin(v), "fhirVersion in " + ref);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected Map<String, byte[]> readZip(InputStream stream) throws IOException {
|
||||
Map<String, byte[]> res = new HashMap<>();
|
||||
ZipInputStream zip = new ZipInputStream(stream);
|
||||
|
@ -645,7 +686,7 @@ public class IgLoader {
|
|||
else if (fn.endsWith(".json") && !fn.endsWith("template.json"))
|
||||
r = new JsonParser().parse(new ByteArrayInputStream(content));
|
||||
else if (fn.endsWith(".txt"))
|
||||
r = new StructureMapUtilities(context, null, null).parse(TextFile.bytesToString(content), fn);
|
||||
r = new StructureMapUtilities(getContext(), null, null).parse(TextFile.bytesToString(content), fn);
|
||||
else if (fn.endsWith(".map"))
|
||||
r = new StructureMapUtilities(null).parse(new String(content), fn);
|
||||
else
|
||||
|
|
|
@ -193,49 +193,12 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst
|
|||
igLoader = new IgLoader(getPcm(), getContext(), getVersion(), isDebug());
|
||||
}
|
||||
|
||||
public ValidationEngine(String src, FhirPublication version, String vString, TimeTracker tt) throws FHIRException, IOException, URISyntaxException {
|
||||
public ValidationEngine(String src, String vString, TimeTracker tt) throws FHIRException, IOException, URISyntaxException {
|
||||
loadCoreDefinitions(src, false, tt);
|
||||
setVersion(vString);
|
||||
igLoader = new IgLoader(getPcm(), getContext(), getVersion(), isDebug());
|
||||
}
|
||||
|
||||
public void scanForVersions(List<String> sources, VersionSourceInformation versions) throws FHIRException, IOException {
|
||||
List<String> refs = new ArrayList<String>();
|
||||
ValidatorUtils.parseSources(sources, refs, context);
|
||||
for (String ref : refs) {
|
||||
Content cnt = igLoader.loadContent(ref, "validate", false);
|
||||
String s = TextFile.bytesToString(cnt.focus);
|
||||
if (s.contains("http://hl7.org/fhir/3.0")) {
|
||||
versions.see("3.0", "Profile in " + ref);
|
||||
}
|
||||
if (s.contains("http://hl7.org/fhir/1.0")) {
|
||||
versions.see("1.0", "Profile in " + ref);
|
||||
}
|
||||
if (s.contains("http://hl7.org/fhir/4.0")) {
|
||||
versions.see("4.0", "Profile in " + ref);
|
||||
}
|
||||
if (s.contains("http://hl7.org/fhir/1.4")) {
|
||||
versions.see("1.4", "Profile in " + ref);
|
||||
}
|
||||
try {
|
||||
if (s.startsWith("{")) {
|
||||
JsonObject json = JsonTrackingParser.parse(s, null);
|
||||
if (json.has("fhirVersion")) {
|
||||
versions.see(VersionUtilities.getMajMin(JSONUtil.str(json, "fhirVersion")), "fhirVersion in " + ref);
|
||||
}
|
||||
} else {
|
||||
Document doc = ValidatorUtils.parseXml(cnt.focus);
|
||||
String v = XMLUtil.getNamedChildValue(doc.getDocumentElement(), "fhirVersion");
|
||||
if (v != null) {
|
||||
versions.see(VersionUtilities.getMajMin(v), "fhirVersion in " + ref);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void loadCoreDefinitions(String src, boolean recursive, TimeTracker tt) throws FHIRException, IOException {
|
||||
NpmPackage npm = getPcm().loadPackage(src, null);
|
||||
if (npm != null) {
|
||||
|
@ -252,7 +215,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst
|
|||
initContext(tt);
|
||||
}
|
||||
|
||||
public void initContext(TimeTracker tt) throws IOException, FileNotFoundException {
|
||||
public void initContext(TimeTracker tt) throws IOException {
|
||||
context.setCanNoTS(true);
|
||||
context.setCacheId(UUID.randomUUID().toString());
|
||||
context.setAllowLoadingDuplicates(true); // because of Forge
|
||||
|
|
|
@ -94,6 +94,8 @@ public class ValidatorCli {
|
|||
public static final String JAVA_DISABLED_PROXY_SCHEMES = "jdk.http.auth.proxying.disabledSchemes";
|
||||
public static final String JAVA_USE_SYSTEM_PROXIES = "java.net.useSystemProxies";
|
||||
|
||||
private static ValidationService validationService = new ValidationService();
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
TimeTracker tt = new TimeTracker();
|
||||
TimeTracker.Session tts = tt.start("Loading");
|
||||
|
@ -181,42 +183,42 @@ public class ValidatorCli {
|
|||
private static void doLeftRightComparison(String[] args, CliContext cliContext, TimeTracker tt) throws Exception {
|
||||
Display.printCliArgumentsAndInfo(args);
|
||||
if (cliContext.getSv() == null) {
|
||||
cliContext.setSv(ValidationService.determineVersion(cliContext));
|
||||
cliContext.setSv(validationService.determineVersion(cliContext));
|
||||
}
|
||||
String v = VersionUtilities.getCurrentVersion(cliContext.getSv());
|
||||
String definitions = VersionUtilities.packageForVersion(v) + "#" + v;
|
||||
ValidationEngine validator = ValidationService.getValidator(cliContext, definitions, tt);
|
||||
ValidationEngine validator = validationService.initializeValidator(cliContext, definitions, tt);
|
||||
ComparisonService.doLeftRightComparison(args, Params.getParam(args, Params.DESTINATION), validator);
|
||||
}
|
||||
|
||||
private static void doValidation(TimeTracker tt, TimeTracker.Session tts, CliContext cliContext) throws Exception {
|
||||
if (cliContext.getSv() == null) {
|
||||
cliContext.setSv(ValidationService.determineVersion(cliContext));
|
||||
cliContext.setSv(validationService.determineVersion(cliContext));
|
||||
}
|
||||
System.out.println("Loading");
|
||||
// Comment this out because definitions filename doesn't necessarily contain version (and many not even be 14 characters long).
|
||||
// Version gets spit out a couple of lines later after we've loaded the context
|
||||
String definitions = VersionUtilities.packageForVersion(cliContext.getSv()) + "#" + VersionUtilities.getCurrentVersion(cliContext.getSv());
|
||||
ValidationEngine validator = ValidationService.getValidator(cliContext, definitions, tt);
|
||||
ValidationEngine validator = validationService.initializeValidator(cliContext, definitions, tt);
|
||||
tts.end();
|
||||
switch (cliContext.getMode()) {
|
||||
case TRANSFORM:
|
||||
ValidationService.transform(cliContext, validator);
|
||||
validationService.transform(cliContext, validator);
|
||||
break;
|
||||
case NARRATIVE:
|
||||
ValidationService.generateNarrative(cliContext, validator);
|
||||
validationService.generateNarrative(cliContext, validator);
|
||||
break;
|
||||
case SNAPSHOT:
|
||||
ValidationService.generateSnapshot(cliContext, validator);
|
||||
validationService.generateSnapshot(cliContext, validator);
|
||||
break;
|
||||
case CONVERT:
|
||||
ValidationService.convertSources(cliContext, validator);
|
||||
validationService.convertSources(cliContext, validator);
|
||||
break;
|
||||
case FHIRPATH:
|
||||
ValidationService.evaluateFhirpath(cliContext, validator);
|
||||
validationService.evaluateFhirpath(cliContext, validator);
|
||||
break;
|
||||
case VERSION:
|
||||
ValidationService.transformVersion(cliContext, validator);
|
||||
validationService.transformVersion(cliContext, validator);
|
||||
break;
|
||||
case VALIDATION:
|
||||
case SCAN:
|
||||
|
@ -232,7 +234,7 @@ public class ValidatorCli {
|
|||
Scanner validationScanner = new Scanner(validator.getContext(), validator.getValidator(), validator.getIgLoader(), validator.getFhirPathEngine());
|
||||
validationScanner.validateScan(cliContext.getOutput(), cliContext.getSources());
|
||||
} else {
|
||||
ValidationService.validateSources(cliContext, validator);
|
||||
validationService.validateSources(cliContext, validator);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -18,11 +18,19 @@ public class ValidationRequest {
|
|||
return cliContext;
|
||||
}
|
||||
|
||||
@JsonProperty("sessionId")
|
||||
public String sessionId;
|
||||
|
||||
public ValidationRequest() {}
|
||||
|
||||
public ValidationRequest(CliContext cliContext, List<FileInfo> filesToValidate) {
|
||||
this(cliContext, filesToValidate, null);
|
||||
}
|
||||
|
||||
public ValidationRequest(CliContext cliContext, List<FileInfo> filesToValidate, String sessionToken) {
|
||||
this.cliContext = cliContext;
|
||||
this.filesToValidate = filesToValidate;
|
||||
this.sessionId = sessionToken;
|
||||
}
|
||||
|
||||
@JsonProperty("cliContext")
|
||||
|
@ -42,6 +50,17 @@ public class ValidationRequest {
|
|||
return this;
|
||||
}
|
||||
|
||||
@JsonProperty("sessionId")
|
||||
public String getSessionId() {
|
||||
return sessionId;
|
||||
}
|
||||
|
||||
@JsonProperty("sessionId")
|
||||
public ValidationRequest setSessionId(String sessionId) {
|
||||
this.sessionId = sessionId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String listSourceFiles() {
|
||||
List<String> fileNames = new ArrayList<>();
|
||||
for (FileInfo fp : filesToValidate) {
|
||||
|
|
|
@ -10,10 +10,18 @@ public class ValidationResponse {
|
|||
@JsonProperty("outcomes")
|
||||
public List<ValidationOutcome> outcomes = new ArrayList<>();
|
||||
|
||||
@JsonProperty("sessionToken")
|
||||
public String sessionToken;
|
||||
|
||||
public ValidationResponse() {}
|
||||
|
||||
public ValidationResponse(List<ValidationOutcome> outcomes) {
|
||||
this(outcomes, null);
|
||||
}
|
||||
|
||||
public ValidationResponse(List<ValidationOutcome> outcomes, String sessionToken) {
|
||||
this.outcomes = outcomes;
|
||||
this.sessionToken = sessionToken;
|
||||
}
|
||||
|
||||
@JsonProperty("outcomes")
|
||||
|
@ -27,6 +35,17 @@ public class ValidationResponse {
|
|||
return this;
|
||||
}
|
||||
|
||||
@JsonProperty("sessionToken")
|
||||
public String getSessionToken() {
|
||||
return sessionToken;
|
||||
}
|
||||
|
||||
@JsonProperty("sessionToken")
|
||||
public ValidationResponse setSessionToken(String sessionToken) {
|
||||
this.sessionToken = sessionToken;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ValidationResponse addOutcome(ValidationOutcome outcome) {
|
||||
if (outcomes == null) {
|
||||
outcomes = new ArrayList<>();
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
package org.hl7.fhir.validation.cli.services;
|
||||
|
||||
import org.apache.commons.collections4.map.PassiveExpiringMap;
|
||||
import org.hl7.fhir.validation.ValidationEngine;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* SessionCache for storing and retrieving ValidationEngine instances, so callers do not have to re-instantiate a new
|
||||
* instance for each validation request.
|
||||
*/
|
||||
public class SessionCache {
|
||||
|
||||
protected static final long TIME_TO_LIVE = 60;
|
||||
protected static final TimeUnit TIME_UNIT = TimeUnit.MINUTES;
|
||||
|
||||
private final PassiveExpiringMap<String, ValidationEngine> cachedSessions;
|
||||
|
||||
public SessionCache() {
|
||||
cachedSessions = new PassiveExpiringMap<>(TIME_TO_LIVE, TIME_UNIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param sessionLength the constant amount of time an entry is available before it expires. A negative value results
|
||||
* in entries that NEVER expire. A zero value results in entries that ALWAYS expire.
|
||||
* @param sessionLengthUnit the unit of time for the timeToLive parameter, must not be null
|
||||
*/
|
||||
public SessionCache(long sessionLength, TimeUnit sessionLengthUnit) {
|
||||
cachedSessions = new PassiveExpiringMap<>(sessionLength, sessionLengthUnit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the initialized {@link ValidationEngine} in the cache. Returns the session id that will be associated with
|
||||
* this instance.
|
||||
* @param validationEngine {@link ValidationEngine}
|
||||
* @return The {@link String} id associated with the stored instance.
|
||||
*/
|
||||
public String cacheSession(ValidationEngine validationEngine) {
|
||||
String generatedId = generateID();
|
||||
cachedSessions.put(generatedId, validationEngine);
|
||||
return generatedId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the initialized {@link ValidationEngine} in the cache with the passed in id as the key. If a null key is
|
||||
* passed in, a new key is generated and returned.
|
||||
* @param sessionId The {@link String} key to associate with this stored {@link ValidationEngine}
|
||||
* @param validationEngine The {@link ValidationEngine} instance to cache.
|
||||
* @return The {@link String} id that will be associated with the stored {@link ValidationEngine}
|
||||
*/
|
||||
public String cacheSession(String sessionId, ValidationEngine validationEngine) {
|
||||
if(sessionId == null) {
|
||||
sessionId = cacheSession(validationEngine);
|
||||
} else {
|
||||
cachedSessions.put(sessionId, validationEngine);
|
||||
}
|
||||
return sessionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the passed in {@link String} id exists in the set of stored session id.
|
||||
* @param sessionId The {@link String} id to search for.
|
||||
* @return {@link Boolean#TRUE} if such id exists.
|
||||
*/
|
||||
public boolean sessionExists(String sessionId) {
|
||||
return cachedSessions.containsKey(sessionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the stored {@link ValidationEngine} associated with the passed in session id, if one such instance exists.
|
||||
* @param sessionId The {@link String} session id.
|
||||
* @return The {@link ValidationEngine} associated with the passed in id, or null if none exists.
|
||||
*/
|
||||
public ValidationEngine fetchSessionValidatorEngine(String sessionId) {
|
||||
return cachedSessions.get(sessionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of stored session ids.
|
||||
* @return {@link Set} of session ids.
|
||||
*/
|
||||
public Set<String> getSessionIds() {
|
||||
return cachedSessions.keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Session ids generated internally are UUID {@link String}.
|
||||
* @return A new {@link String} session id.
|
||||
*/
|
||||
private String generateID() {
|
||||
return UUID.randomUUID().toString();
|
||||
}
|
||||
}
|
|
@ -1,26 +1,20 @@
|
|||
package org.hl7.fhir.validation.cli.services;
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.r5.context.SimpleWorkerContext;
|
||||
import org.hl7.fhir.r5.context.TerminologyCache;
|
||||
import org.hl7.fhir.r5.elementmodel.Manager;
|
||||
import org.hl7.fhir.r5.formats.IParser;
|
||||
import org.hl7.fhir.r5.formats.JsonParser;
|
||||
import org.hl7.fhir.r5.formats.XmlParser;
|
||||
import org.hl7.fhir.r5.model.Bundle;
|
||||
import org.hl7.fhir.r5.model.DomainResource;
|
||||
import org.hl7.fhir.r5.model.FhirPublication;
|
||||
import org.hl7.fhir.r5.model.OperationOutcome;
|
||||
import org.hl7.fhir.r5.model.Resource;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
import org.hl7.fhir.r5.model.*;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind;
|
||||
import org.hl7.fhir.r5.utils.ToolingExtensions;
|
||||
import org.hl7.fhir.utilities.TextFile;
|
||||
import org.hl7.fhir.utilities.TimeTracker;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.VersionUtilities;
|
||||
import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager;
|
||||
import org.hl7.fhir.utilities.npm.ToolsVersion;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
import org.hl7.fhir.validation.IgLoader;
|
||||
import org.hl7.fhir.validation.ValidationEngine;
|
||||
|
@ -29,14 +23,32 @@ import org.hl7.fhir.validation.cli.model.*;
|
|||
import org.hl7.fhir.validation.cli.utils.EngineMode;
|
||||
import org.hl7.fhir.validation.cli.utils.VersionSourceInformation;
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ValidationService {
|
||||
|
||||
public static ValidationResponse validateSources(ValidationRequest request) throws Exception {
|
||||
private final SessionCache sessionCache;
|
||||
|
||||
public ValidationService() {
|
||||
sessionCache = new SessionCache();
|
||||
}
|
||||
|
||||
protected ValidationService(SessionCache cache) {
|
||||
this.sessionCache = cache;
|
||||
}
|
||||
|
||||
public ValidationResponse validateSources(ValidationRequest request) throws Exception {
|
||||
if (request.getCliContext().getSv() == null) {
|
||||
request.getCliContext().setSv(ValidationService.determineVersion(request.getCliContext()));
|
||||
String sv = determineVersion(request.getCliContext(), request.sessionId);
|
||||
request.getCliContext().setSv(sv);
|
||||
}
|
||||
|
||||
String definitions = VersionUtilities.packageForVersion(request.getCliContext().getSv()) + "#" + VersionUtilities.getCurrentVersion(request.getCliContext().getSv());
|
||||
ValidationEngine validator = ValidationService.getValidator(request.getCliContext(), definitions, new TimeTracker());
|
||||
|
||||
String sessionId = initializeValidator(request.getCliContext(), definitions, new TimeTracker(), request.sessionId);
|
||||
ValidationEngine validator = sessionCache.fetchSessionValidatorEngine(sessionId);
|
||||
|
||||
if (request.getCliContext().getProfiles().size() > 0) {
|
||||
System.out.println(" .. validate " + request.listSourceFiles() + " against " + request.getCliContext().getProfiles().toString());
|
||||
|
@ -56,23 +68,25 @@ public class ValidationService {
|
|||
return response;
|
||||
}
|
||||
|
||||
public static VersionSourceInformation scanForVersions(CliContext cliContext) throws Exception {
|
||||
public VersionSourceInformation scanForVersions(CliContext cliContext) throws Exception {
|
||||
VersionSourceInformation versions = new VersionSourceInformation();
|
||||
ValidationEngine ve = new ValidationEngine();
|
||||
IgLoader igLoader = new IgLoader(ve.getPcm(), ve.getContext(), ve.getVersion(), ve.isDebug());
|
||||
IgLoader igLoader = new IgLoader(
|
||||
new FilesystemPackageCacheManager(true, ToolsVersion.TOOLS_VERSION),
|
||||
SimpleWorkerContext.fromNothing(),
|
||||
null);
|
||||
for (String src : cliContext.getIgs()) {
|
||||
igLoader.scanForIgVersion(src, cliContext.isRecursive(), versions);
|
||||
}
|
||||
ve.scanForVersions(cliContext.getSources(), versions);
|
||||
igLoader.scanForVersions(cliContext.getSources(), versions);
|
||||
return versions;
|
||||
}
|
||||
|
||||
public static void validateSources(CliContext cliContext, ValidationEngine validator) throws Exception {
|
||||
|
||||
public void validateSources(CliContext cliContext, ValidationEngine validator) throws Exception {
|
||||
long start = System.currentTimeMillis();
|
||||
List<ValidationRecord> records = new ArrayList<>();
|
||||
Resource r = validator.validate(cliContext.getSources(), cliContext.getProfiles(), records);
|
||||
int ec = 0;
|
||||
System.out.println("Done. "+validator.getContext().clock().report());
|
||||
System.out.println("Done. " + validator.getContext().clock().report());
|
||||
System.out.println();
|
||||
|
||||
if (cliContext.getOutput() == null) {
|
||||
|
@ -98,24 +112,24 @@ public class ValidationService {
|
|||
s.close();
|
||||
}
|
||||
if (cliContext.getHtmlOutput() != null) {
|
||||
String html = new HTMLOutputGenerator(records).generate(System.currentTimeMillis()-start);
|
||||
String html = new HTMLOutputGenerator(records).generate(System.currentTimeMillis() - start);
|
||||
TextFile.stringToFile(html, cliContext.getHtmlOutput());
|
||||
System.out.println("HTML Summary in "+cliContext.getHtmlOutput());
|
||||
System.out.println("HTML Summary in " + cliContext.getHtmlOutput());
|
||||
}
|
||||
System.exit(ec > 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
public static void convertSources(CliContext cliContext, ValidationEngine validator) throws Exception {
|
||||
public void convertSources(CliContext cliContext, ValidationEngine validator) throws Exception {
|
||||
System.out.println(" ...convert");
|
||||
validator.convert(cliContext.getSources().get(0), cliContext.getOutput());
|
||||
}
|
||||
|
||||
public static void evaluateFhirpath(CliContext cliContext, ValidationEngine validator) throws Exception {
|
||||
public void evaluateFhirpath(CliContext cliContext, ValidationEngine validator) throws Exception {
|
||||
System.out.println(" ...evaluating " + cliContext.getFhirpath());
|
||||
System.out.println(validator.evaluateFhirPath(cliContext.getSources().get(0), cliContext.getFhirpath()));
|
||||
}
|
||||
|
||||
public static void generateSnapshot(CliContext cliContext, ValidationEngine validator) throws Exception {
|
||||
public void generateSnapshot(CliContext cliContext, ValidationEngine validator) throws Exception {
|
||||
StructureDefinition r = validator.snapshot(cliContext.getSources().get(0), cliContext.getSv());
|
||||
System.out.println(" ...generated snapshot successfully");
|
||||
if (cliContext.getOutput() != null) {
|
||||
|
@ -123,7 +137,7 @@ public class ValidationService {
|
|||
}
|
||||
}
|
||||
|
||||
public static void generateNarrative(CliContext cliContext, ValidationEngine validator) throws Exception {
|
||||
public void generateNarrative(CliContext cliContext, ValidationEngine validator) throws Exception {
|
||||
DomainResource r = validator.generate(cliContext.getSources().get(0), cliContext.getSv());
|
||||
System.out.println(" ...generated narrative successfully");
|
||||
if (cliContext.getOutput() != null) {
|
||||
|
@ -131,7 +145,7 @@ public class ValidationService {
|
|||
}
|
||||
}
|
||||
|
||||
public static void transform(CliContext cliContext, ValidationEngine validator) throws Exception {
|
||||
public void transform(CliContext cliContext, ValidationEngine validator) throws Exception {
|
||||
if (cliContext.getSources().size() > 1)
|
||||
throw new Exception("Can only have one source when doing a transform (found " + cliContext.getSources() + ")");
|
||||
if (cliContext.getTxServer() == null)
|
||||
|
@ -166,7 +180,7 @@ public class ValidationService {
|
|||
}
|
||||
}
|
||||
|
||||
public static void transformVersion(CliContext cliContext, ValidationEngine validator) throws Exception {
|
||||
public void transformVersion(CliContext cliContext, ValidationEngine validator) throws Exception {
|
||||
if (cliContext.getSources().size() > 1) {
|
||||
throw new Exception("Can only have one source when converting versions (found " + cliContext.getSources() + ")");
|
||||
}
|
||||
|
@ -189,44 +203,54 @@ public class ValidationService {
|
|||
}
|
||||
}
|
||||
|
||||
public static ValidationEngine getValidator(CliContext cliContext, String definitions, TimeTracker tt) throws Exception {
|
||||
tt.milestone();
|
||||
System.out.print(" Load FHIR v" + cliContext.getSv() + " from " + definitions);
|
||||
FhirPublication ver = FhirPublication.fromCode(cliContext.getSv());
|
||||
ValidationEngine validator = new ValidationEngine(definitions, ver, cliContext.getSv(), tt);
|
||||
IgLoader igLoader = new IgLoader(validator.getPcm(), validator.getContext(), validator.getVersion(), validator.isDebug());
|
||||
System.out.println(" - "+validator.getContext().countAllCaches()+" resources ("+tt.milestone()+")");
|
||||
igLoader.loadIg(validator.getIgs(), validator.getBinaries(), "hl7.terminology", false);
|
||||
System.out.print(" Terminology server " + cliContext.getTxServer());
|
||||
String txver = validator.setTerminologyServer(cliContext.getTxServer(), cliContext.getTxLog(), ver);
|
||||
System.out.println(" - Version "+txver+" ("+tt.milestone()+")");
|
||||
validator.setDebug(cliContext.isDoDebug());
|
||||
for (String src : cliContext.getIgs()) {
|
||||
igLoader.loadIg(validator.getIgs(), validator.getBinaries(), src, cliContext.isRecursive());
|
||||
}
|
||||
System.out.print(" Get set... ");
|
||||
validator.setQuestionnaireMode(cliContext.getQuestionnaireMode());
|
||||
validator.setDoNative(cliContext.isDoNative());
|
||||
validator.setHintAboutNonMustSupport(cliContext.isHintAboutNonMustSupport());
|
||||
validator.setAnyExtensionsAllowed(cliContext.isAnyExtensionsAllowed());
|
||||
validator.setLanguage(cliContext.getLang());
|
||||
validator.setLocale(cliContext.getLocale());
|
||||
validator.setSnomedExtension(cliContext.getSnomedCTCode());
|
||||
validator.setAssumeValidRestReferences(cliContext.isAssumeValidRestReferences());
|
||||
validator.setNoExtensibleBindingMessages(cliContext.isNoExtensibleBindingMessages());
|
||||
validator.setSecurityChecks(cliContext.isSecurityChecks());
|
||||
validator.setCrumbTrails(cliContext.isCrumbTrails());
|
||||
validator.setShowTimes(cliContext.isShowTimes());
|
||||
validator.setFetcher(new StandAloneValidatorFetcher(validator.getPcm(), validator.getContext(), validator));
|
||||
validator.getBundleValidationRules().addAll(cliContext.getBundleValidationRules());
|
||||
TerminologyCache.setNoCaching(cliContext.isNoInternalCaching());
|
||||
validator.prepare(); // generate any missing snapshots
|
||||
System.out.println(" go ("+tt.milestone()+")");
|
||||
|
||||
return validator;
|
||||
public ValidationEngine initializeValidator(CliContext cliContext, String definitions, TimeTracker tt) throws Exception {
|
||||
return sessionCache.fetchSessionValidatorEngine(initializeValidator(cliContext, definitions, tt, null));
|
||||
}
|
||||
|
||||
public static int displayOperationOutcome(OperationOutcome oo, boolean hasMultiples) {
|
||||
public String initializeValidator(CliContext cliContext, String definitions, TimeTracker tt, String sessionId) throws Exception {
|
||||
tt.milestone();
|
||||
if (!sessionCache.sessionExists(sessionId)) {
|
||||
System.out.println("No such cached session exists for session id " + sessionId + ", re-instantiating validator.");
|
||||
System.out.print(" Load FHIR v" + cliContext.getSv() + " from " + definitions);
|
||||
ValidationEngine validator = new ValidationEngine(definitions, cliContext.getSv(), tt);
|
||||
sessionId = sessionCache.cacheSession(validator);
|
||||
|
||||
FhirPublication ver = FhirPublication.fromCode(cliContext.getSv());
|
||||
IgLoader igLoader = new IgLoader(validator.getPcm(), validator.getContext(), validator.getVersion(), validator.isDebug());
|
||||
System.out.println(" - " + validator.getContext().countAllCaches() + " resources (" + tt.milestone() + ")");
|
||||
igLoader.loadIg(validator.getIgs(), validator.getBinaries(), "hl7.terminology", false);
|
||||
System.out.print(" Terminology server " + cliContext.getTxServer());
|
||||
String txver = validator.setTerminologyServer(cliContext.getTxServer(), cliContext.getTxLog(), ver);
|
||||
System.out.println(" - Version " + txver + " (" + tt.milestone() + ")");
|
||||
validator.setDebug(cliContext.isDoDebug());
|
||||
for (String src : cliContext.getIgs()) {
|
||||
igLoader.loadIg(validator.getIgs(), validator.getBinaries(), src, cliContext.isRecursive());
|
||||
}
|
||||
System.out.print(" Get set... ");
|
||||
validator.setQuestionnaireMode(cliContext.getQuestionnaireMode());
|
||||
validator.setDoNative(cliContext.isDoNative());
|
||||
validator.setHintAboutNonMustSupport(cliContext.isHintAboutNonMustSupport());
|
||||
validator.setAnyExtensionsAllowed(cliContext.isAnyExtensionsAllowed());
|
||||
validator.setLanguage(cliContext.getLang());
|
||||
validator.setLocale(cliContext.getLocale());
|
||||
validator.setSnomedExtension(cliContext.getSnomedCTCode());
|
||||
validator.setAssumeValidRestReferences(cliContext.isAssumeValidRestReferences());
|
||||
validator.setNoExtensibleBindingMessages(cliContext.isNoExtensibleBindingMessages());
|
||||
validator.setSecurityChecks(cliContext.isSecurityChecks());
|
||||
validator.setCrumbTrails(cliContext.isCrumbTrails());
|
||||
validator.setShowTimes(cliContext.isShowTimes());
|
||||
validator.setFetcher(new StandAloneValidatorFetcher(validator.getPcm(), validator.getContext(), validator));
|
||||
validator.getBundleValidationRules().addAll(cliContext.getBundleValidationRules());
|
||||
TerminologyCache.setNoCaching(cliContext.isNoInternalCaching());
|
||||
validator.prepare(); // generate any missing snapshots
|
||||
System.out.println(" go (" + tt.milestone() + ")");
|
||||
} else {
|
||||
System.out.println("Cached session exists for session id " + sessionId + ", returning stored validator session id.");
|
||||
}
|
||||
return sessionId;
|
||||
}
|
||||
|
||||
public int displayOperationOutcome(OperationOutcome oo, boolean hasMultiples) {
|
||||
int error = 0;
|
||||
int warn = 0;
|
||||
int info = 0;
|
||||
|
@ -240,29 +264,29 @@ public class ValidationService {
|
|||
else
|
||||
info++;
|
||||
}
|
||||
|
||||
|
||||
if (hasMultiples) {
|
||||
System.out.print("-- ");
|
||||
System.out.print(file);
|
||||
System.out.print(" --");
|
||||
System.out.println(Utilities.padLeft("", '-', Integer.max(38, file.length()+6)));
|
||||
System.out.println(Utilities.padLeft("", '-', Integer.max(38, file.length() + 6)));
|
||||
}
|
||||
System.out.println((error == 0 ? "Success" : "*FAILURE*") + ": " + Integer.toString(error) + " errors, " + Integer.toString(warn) + " warnings, " + Integer.toString(info)+" notes");
|
||||
System.out.println((error == 0 ? "Success" : "*FAILURE*") + ": " + Integer.toString(error) + " errors, " + Integer.toString(warn) + " warnings, " + Integer.toString(info) + " notes");
|
||||
for (OperationOutcome.OperationOutcomeIssueComponent issue : oo.getIssue()) {
|
||||
System.out.println(getIssueSummary(issue));
|
||||
}
|
||||
if (hasMultiples) {
|
||||
System.out.print("---");
|
||||
System.out.print(Utilities.padLeft("", '-', file.length()));
|
||||
System.out.print(Utilities.padLeft("", '-', file.length()));
|
||||
System.out.print("---");
|
||||
System.out.println(Utilities.padLeft("", '-', Integer.max(38, file.length()+6)));
|
||||
System.out.println(Utilities.padLeft("", '-', Integer.max(38, file.length() + 6)));
|
||||
System.out.println();
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
private static String getIssueSummary(OperationOutcome.OperationOutcomeIssueComponent issue) {
|
||||
String loc = null;
|
||||
private String getIssueSummary(OperationOutcome.OperationOutcomeIssueComponent issue) {
|
||||
String loc;
|
||||
if (issue.hasExpression()) {
|
||||
int line = ToolingExtensions.readIntegerExtension(issue, ToolingExtensions.EXT_ISSUE_LINE, -1);
|
||||
int col = ToolingExtensions.readIntegerExtension(issue, ToolingExtensions.EXT_ISSUE_COL, -1);
|
||||
|
@ -277,12 +301,16 @@ public class ValidationService {
|
|||
return " " + issue.getSeverity().getDisplay() + " @ " + loc + " : " + issue.getDetails().getText();
|
||||
}
|
||||
|
||||
public static String determineVersion(CliContext cliContext) throws Exception {
|
||||
public String determineVersion(CliContext cliContext) throws Exception {
|
||||
return determineVersion(cliContext, null);
|
||||
}
|
||||
|
||||
public String determineVersion(CliContext cliContext, String sessionId) throws Exception {
|
||||
if (cliContext.getMode() != EngineMode.VALIDATION) {
|
||||
return "current";
|
||||
}
|
||||
System.out.println("Scanning for versions (no -version parameter):");
|
||||
VersionSourceInformation versions = ValidationService.scanForVersions(cliContext);
|
||||
VersionSourceInformation versions = scanForVersions(cliContext);
|
||||
for (String s : versions.getReport()) {
|
||||
if (!s.equals("(nothing found)")) {
|
||||
System.out.println(" " + s);
|
||||
|
|
|
@ -87,7 +87,7 @@ public class Common {
|
|||
|
||||
public static ValidationEngine getValidationEngine(String version, String txServer, String definitions, String txLog, TimeTracker tt) throws Exception {
|
||||
System.out.println("Loading (v = " + version + ", tx server -> " + txServer + ")");
|
||||
ValidationEngine ve = new ValidationEngine(definitions, FhirPublication.fromCode(version), version, tt);
|
||||
ValidationEngine ve = new ValidationEngine(definitions, version, tt);
|
||||
ve.connectToTSServer(txServer, txLog, FhirPublication.fromCode(version));
|
||||
return ve;
|
||||
}
|
||||
|
|
|
@ -8,8 +8,8 @@ import java.util.List;
|
|||
|
||||
public class VersionSourceInformation {
|
||||
|
||||
private List<String> report = new ArrayList<>();
|
||||
private List<String> versions = new ArrayList<>();
|
||||
private final List<String> report = new ArrayList<>();
|
||||
private final List<String> versions = new ArrayList<>();
|
||||
|
||||
public void see(String version, String src) {
|
||||
version = VersionUtilities.getMajMin(version);
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
package org.hl7.fhir.validation.cli.services;
|
||||
|
||||
import org.hl7.fhir.validation.ValidationEngine;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
class SessionCacheTest {
|
||||
|
||||
@Test
|
||||
@DisplayName("test session expiration works")
|
||||
void expiredSession() throws IOException, InterruptedException {
|
||||
final long EXPIRE_TIME = 5L;
|
||||
SessionCache cache = new SessionCache(EXPIRE_TIME, TimeUnit.SECONDS);
|
||||
ValidationEngine testEngine = new ValidationEngine();
|
||||
String sessionId = cache.cacheSession(testEngine);
|
||||
TimeUnit.SECONDS.sleep(EXPIRE_TIME + 1L);
|
||||
Assertions.assertNull(cache.fetchSessionValidatorEngine(sessionId));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("test session caching works")
|
||||
void cachedSession() throws IOException {
|
||||
final long EXPIRE_TIME = 5L;
|
||||
SessionCache cache = new SessionCache(EXPIRE_TIME, TimeUnit.SECONDS);
|
||||
ValidationEngine testEngine = new ValidationEngine();
|
||||
String sessionId = cache.cacheSession(testEngine);
|
||||
Assertions.assertEquals(testEngine, cache.fetchSessionValidatorEngine(sessionId));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("test session exists")
|
||||
void sessionExists() throws IOException {
|
||||
SessionCache cache = new SessionCache();
|
||||
ValidationEngine testEngine = new ValidationEngine();
|
||||
String sessionId = cache.cacheSession(testEngine);
|
||||
Assertions.assertTrue(cache.sessionExists(sessionId));
|
||||
Assertions.assertFalse(cache.sessionExists(UUID.randomUUID().toString()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("test null session test id returns false")
|
||||
void testNullSessionExists() {
|
||||
SessionCache cache = new SessionCache();
|
||||
Assertions.assertFalse(cache.sessionExists(null));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
package org.hl7.fhir.validation.cli.services;
|
||||
|
||||
import org.apache.commons.io.Charsets;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.hl7.fhir.r5.elementmodel.Manager;
|
||||
import org.hl7.fhir.validation.ValidationEngine;
|
||||
import org.hl7.fhir.validation.cli.model.CliContext;
|
||||
import org.hl7.fhir.validation.cli.model.FileInfo;
|
||||
import org.hl7.fhir.validation.cli.model.ValidationRequest;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentMatchers;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class ValidationServiceTest {
|
||||
|
||||
@Test
|
||||
void validateSources() throws Exception {
|
||||
SessionCache sessionCache = Mockito.spy(new SessionCache());
|
||||
ValidationService myService = new ValidationService(sessionCache);
|
||||
|
||||
String resource = IOUtils.toString(getFileFromResourceAsStream("detected_issues.json"), StandardCharsets.UTF_8);
|
||||
List<FileInfo> filesToValidate = new ArrayList<>();
|
||||
filesToValidate.add(new FileInfo().setFileName("test_resource.json").setFileContent(resource).setFileType(Manager.FhirFormat.JSON.getExtension()));
|
||||
|
||||
ValidationRequest request = new ValidationRequest().setCliContext(new CliContext()).setFilesToValidate(filesToValidate);
|
||||
// Validation run 1...nothing cached yet
|
||||
myService.validateSources(request);
|
||||
Mockito.verify(sessionCache, Mockito.times(1)).cacheSession(ArgumentMatchers.any(ValidationEngine.class));
|
||||
|
||||
Set<String> sessionIds = sessionCache.getSessionIds();
|
||||
if (sessionIds.stream().findFirst().isPresent()) {
|
||||
// Verify that after 1 run there is only one entry within the cache
|
||||
Assertions.assertEquals(1, sessionIds.size());
|
||||
myService.validateSources(request);
|
||||
// Verify that the cache has been called on once with the id created in the first run
|
||||
Mockito.verify(sessionCache, Mockito.times(1)).fetchSessionValidatorEngine(sessionIds.stream().findFirst().get());
|
||||
} else {
|
||||
// If no sessions exist within the cache after a run, we auto-fail.
|
||||
fail();
|
||||
}
|
||||
}
|
||||
|
||||
private InputStream getFileFromResourceAsStream(String fileName) {
|
||||
// The class loader that loaded the class
|
||||
ClassLoader classLoader = getClass().getClassLoader();
|
||||
InputStream inputStream = classLoader.getResourceAsStream(fileName);
|
||||
|
||||
// the stream holding the file content
|
||||
if (inputStream == null) {
|
||||
throw new IllegalArgumentException("file not found! " + fileName);
|
||||
} else {
|
||||
return inputStream;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"resourceType": "DetectedIssue",
|
||||
"identifier": [ {
|
||||
"system": "http://covidcare.au/app/checkin",
|
||||
"value": "7"
|
||||
} ],
|
||||
"status": "final",
|
||||
"patient": "Patient/4912",
|
||||
"identifiedDateTime": "3020-10-27T13:33:15+11:00",
|
||||
"code": {
|
||||
"coding": [ {
|
||||
"system": "http://covidcare.au/app/alert",
|
||||
"code": "trendNegative",
|
||||
"display": "CovidCare: Vital signs trend negative alert: re-check recommended"
|
||||
} ],
|
||||
"text": "CovidCare alert"
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue