Add -watch-scan-delay and -watch-settle-time

This commit is contained in:
Grahame Grieve 2023-06-24 09:07:07 +10:00
parent 40380ff0f3
commit d35eba6b23
10 changed files with 98 additions and 30 deletions

View File

@ -174,9 +174,12 @@ public class IgLoader implements IValidationEngineLoader {
* * @see IgLoader#loadIgSource(String, boolean, boolean) loadIgSource for detailed description of the src parameter
*/
public Content loadContent(String source, String opName, boolean asIg) throws FHIRException, IOException {
public Content loadContent(String source, String opName, boolean asIg, boolean mustLoad) throws FHIRException, IOException {
Map<String, byte[]> s = loadIgSource(source, false, asIg);
Content res = new Content();
if (!mustLoad && s.size() == 0) {
return null;
}
if (s.size() != 1)
throw new FHIRException("Unable to find resource " + source + " to " + opName);
for (Map.Entry<String, byte[]> t : s.entrySet()) {
@ -306,7 +309,7 @@ public class IgLoader implements IValidationEngineLoader {
List<SourceFile> refs = new ArrayList<>();
ValidatorUtils.parseSources(sources, refs, context);
for (SourceFile ref : refs) {
Content cnt = loadContent(ref.getRef(), "validate", false);
Content cnt = loadContent(ref.getRef(), "validate", false, true);
scanForFhirVersion(versions, ref.getRef(), cnt.getFocus());
}
}

View File

@ -82,7 +82,7 @@ public class Scanner {
List<ScanOutputItem> res = new ArrayList<>();
for (SourceFile ref : refs) {
Content cnt = getIgLoader().loadContent(ref.getRef(), "validate", false);
Content cnt = getIgLoader().loadContent(ref.getRef(), "validate", false, true);
List<ValidationMessage> messages = new ArrayList<>();
Element e = null;
try {

View File

@ -555,14 +555,14 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
return list;
}
public OperationOutcome validate(String source, List<String> profiles, IValidationEngineLoader loader, boolean all) throws FHIRException, IOException {
public OperationOutcome validate(String source, List<String> profiles, IValidationEngineLoader loader, boolean all) throws FHIRException, IOException, InterruptedException {
List<String> l = new ArrayList<String>();
List<SourceFile> refs = new ArrayList<>();
l.add(source);
return (OperationOutcome) validate(l, profiles, refs, null, loader, all);
return (OperationOutcome) validate(l, profiles, refs, null, loader, all, 0, true);
}
public Resource validate(List<String> sources, List<String> profiles, List<SourceFile> refs, List<ValidationRecord> record, IValidationEngineLoader loader, boolean all) throws FHIRException, IOException {
public Resource validate(List<String> sources, List<String> profiles, List<SourceFile> refs, List<ValidationRecord> record, IValidationEngineLoader loader, boolean all, int delay, boolean first) throws FHIRException, IOException, InterruptedException {
boolean asBundle = ValidatorUtils.parseSources(sources, refs, context);
Bundle results = new Bundle();
results.setType(Bundle.BundleType.COLLECTION);
@ -575,6 +575,8 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
}
if (!found) {
return null;
} else if (!first) {
Thread.sleep(delay);
}
// round one: try to read them all natively
@ -583,8 +585,8 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
// something that should've been loaded
for (SourceFile ref : refs) {
if (ref.isProcess() || all) {
ref.setCnt(igLoader.loadContent(ref.getRef(), "validate", false));
if (loader != null) {
ref.setCnt(igLoader.loadContent(ref.getRef(), "validate", false, first));
if (loader != null && ref.getCnt() != null) {
try {
loader.load(ref.getCnt());
} catch (Throwable t) {
@ -595,7 +597,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
}
for (SourceFile ref : refs) {
if (ref.isProcess() || all) {
if ((ref.isProcess() || all) && ref.getCnt() != null) {
TimeTracker.Session tts = context.clock().start("validation");
context.clock().milestone();
System.out.println(" Validate " + ref);
@ -666,7 +668,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
}
public org.hl7.fhir.r5.elementmodel.Element transform(String source, String map) throws FHIRException, IOException {
Content cnt = igLoader.loadContent(source, "validate", false);
Content cnt = igLoader.loadContent(source, "validate", false, true);
return transform(cnt.getFocus(), cnt.getCntType(), map);
}
@ -750,7 +752,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
public Resource generate(String source, String version) throws FHIRException, IOException, EOperationOutcome {
Content cnt = igLoader.loadContent(source, "validate", false);
Content cnt = igLoader.loadContent(source, "validate", false, true);
Resource res = igLoader.loadResourceByVersion(version, cnt.getFocus(), source);
RenderingContext rc = new RenderingContext(context, null, null, "http://hl7.org/fhir", "", null, ResourceRendererMode.END_USER, GenerationRules.VALID_RESOURCE);
genResource(res, rc);
@ -771,13 +773,13 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
}
public void convert(String source, String output) throws FHIRException, IOException {
Content cnt = igLoader.loadContent(source, "validate", false);
Content cnt = igLoader.loadContent(source, "validate", false, true);
Element e = Manager.parseSingle(context, new ByteArrayInputStream(cnt.getFocus()), cnt.getCntType());
Manager.compose(context, e, new FileOutputStream(output), (output.endsWith(".json") ? FhirFormat.JSON : FhirFormat.XML), OutputStyle.PRETTY, null);
}
public String evaluateFhirPath(String source, String expression) throws FHIRException, IOException {
Content cnt = igLoader.loadContent(source, "validate", false);
Content cnt = igLoader.loadContent(source, "validate", false, true);
FHIRPathEngine fpe = this.getValidator(null).getFHIRPathEngine();
Element e = Manager.parseSingle(context, new ByteArrayInputStream(cnt.getFocus()), cnt.getCntType());
ExpressionNode exp = fpe.parse(expression);
@ -785,7 +787,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
}
public StructureDefinition snapshot(String source, String version) throws FHIRException, IOException {
Content cnt = igLoader.loadContent(source, "validate", false);
Content cnt = igLoader.loadContent(source, "validate", false, true);
Resource res = igLoader.loadResourceByVersion(version, cnt.getFocus(), Utilities.getFileNameForName(source));
if (!(res instanceof StructureDefinition))
@ -798,7 +800,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
}
public CanonicalResource loadCanonicalResource(String source, String version) throws FHIRException, IOException {
Content cnt = igLoader.loadContent(source, "validate", false);
Content cnt = igLoader.loadContent(source, "validate", false, true);
Resource res = igLoader.loadResourceByVersion(version, cnt.getFocus(), Utilities.getFileNameForName(source));
if (!(res instanceof CanonicalResource))
@ -944,7 +946,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
}
public byte[] transformVersion(String source, String targetVer, FhirFormat format, Boolean canDoNative) throws FHIRException, IOException, Exception {
Content cnt = igLoader.loadContent(source, "validate", false);
Content cnt = igLoader.loadContent(source, "validate", false, true);
org.hl7.fhir.r5.elementmodel.Element src = Manager.parseSingle(context, new ByteArrayInputStream(cnt.getFocus()), cnt.getCntType());
// if the src has a url, we try to use the java code

View File

@ -143,6 +143,13 @@ public class CliContext {
@JsonProperty("watchMode")
private ValidatorWatchMode watchMode = ValidatorWatchMode.NONE;
@JsonProperty("watchScanDelay")
private int watchScanDelay = 1000;
@JsonProperty("watchSettleTime")
private int watchSettleTime = 100;
@JsonProperty("map")
public String getMap() {
@ -751,14 +758,16 @@ public class CliContext {
Objects.equals(outputStyle, that.outputStyle) &&
Objects.equals(jurisdiction, that.jurisdiction) &&
Objects.equals(locations, that.locations) &&
Objects.equals(watchMode, that.watchMode) ;
Objects.equals(watchMode, that.watchMode) &&
Objects.equals(watchScanDelay, that.watchScanDelay) &&
Objects.equals(watchSettleTime, that.watchSettleTime) ;
}
@Override
public int hashCode() {
return Objects.hash(doNative, extensions, hintAboutNonMustSupport, recursive, doDebug, assumeValidRestReferences, canDoNative, noInternalCaching,
noExtensibleBindingMessages, noInvariants, displayWarnings, wantInvariantsInMessages, map, output, outputSuffix, htmlOutput, txServer, sv, txLog, txCache, mapLog, lang, srcLang, tgtLang, fhirpath, snomedCT,
targetVer, igs, questionnaireMode, level, profiles, sources, inputs, mode, locale, locations, crumbTrails, forPublication, showTimes, allowExampleUrls, outputStyle, jurisdiction, noUnicodeBiDiControlChars, watchMode,
targetVer, igs, questionnaireMode, level, profiles, sources, inputs, mode, locale, locations, crumbTrails, forPublication, showTimes, allowExampleUrls, outputStyle, jurisdiction, noUnicodeBiDiControlChars, watchMode, watchScanDelay, watchSettleTime,
htmlInMarkdownCheck, allowDoubleQuotesInFHIRPath);
}
@ -813,6 +822,8 @@ public class CliContext {
", htmlInMarkdownCheck=" + htmlInMarkdownCheck +
", allowDoubleQuotesInFHIRPath=" + allowDoubleQuotesInFHIRPath +
", watchMode=" + watchMode +
", watchSettleTime=" + watchSettleTime +
", watchScanDelay=" + watchScanDelay +
'}';
}
@ -837,6 +848,26 @@ public class CliContext {
this.watchMode = watchMode;
return this;
}
@JsonProperty("watchScanDelay")
public int getWatchScanDelay() {
return watchScanDelay;
}
@JsonProperty("watchScanDelay")
public void setWatchScanDelay(int watchScanDelay) {
this.watchScanDelay = watchScanDelay;
}
@JsonProperty("watchSettleTime")
public int getWatchSettleTime() {
return watchSettleTime;
}
@JsonProperty("watchSettleTime")
public void setWatchSettleTime(int watchSettleTime) {
this.watchSettleTime = watchSettleTime;
}
}

View File

@ -143,7 +143,7 @@ public class ValidationService {
return versions;
}
public void validateSources(CliContext cliContext, ValidationEngine validator, ValidatorWatchMode watch) throws Exception {
public void validateSources(CliContext cliContext, ValidationEngine validator, ValidatorWatchMode watch, int watchScanDelay, int watchSettleTime) throws Exception {
if (cliContext.getProfiles().size() > 0) {
System.out.println(" Profiles: " + cliContext.getProfiles());
}
@ -153,10 +153,12 @@ public class ValidationService {
List<SourceFile> refs = new ArrayList<>();
int ec = 0;
boolean first = true;
do {
long start = System.currentTimeMillis();
Resource r = validator.validate(cliContext.getSources(), cliContext.getProfiles(), refs, records, igLoader, watch == ValidatorWatchMode.ALL);
Resource r = validator.validate(cliContext.getSources(), cliContext.getProfiles(), refs, records, igLoader, watch == ValidatorWatchMode.ALL, watchSettleTime, first);
first = false;
boolean statusNeeded = false;
if (r != null) {
statusNeeded = true;
@ -218,9 +220,9 @@ public class ValidationService {
}
if (watch != ValidatorWatchMode.NONE) {
if (statusNeeded) {
System.out.println("Watching for changes");
System.out.println("Watching for changes ("+Integer.toString(watchScanDelay)+"ms cycle)");
}
Thread.sleep(1000);
Thread.sleep(watchScanDelay);
}
} while (watch != ValidatorWatchMode.NONE);
System.exit(ec > 0 ? 1 : 0);
@ -578,7 +580,7 @@ public class ValidationService {
ValidatorUtils.parseSources(cliContext.getSources(), refs, validator.getContext());
for (SourceFile ref : refs) {
System.out.println(" Extract Translations from " + ref);
org.hl7.fhir.validation.Content cnt = validator.getIgLoader().loadContent(ref.getRef(), "translate", false);
org.hl7.fhir.validation.Content cnt = validator.getIgLoader().loadContent(ref.getRef(), "translate", false, true);
Element e = Manager.parseSingle(validator.getContext(), new ByteArrayInputStream(cnt.getFocus()), cnt.getCntType());
LanguageProducerSession ps = po.startSession(e.fhirType()+"-"+e.getIdBase(), cliContext.getSrcLang());
LanguageProducerLanguageSession psl = ps.forLang(cliContext.getTgtLang());
@ -613,7 +615,7 @@ public class ValidationService {
int t = 0;
for (SourceFile ref : refs) {
System.out.println(" Inject Translations into " + ref);
org.hl7.fhir.validation.Content cnt = validator.getIgLoader().loadContent(ref.getRef(), "translate", false);
org.hl7.fhir.validation.Content cnt = validator.getIgLoader().loadContent(ref.getRef(), "translate", false, true);
Element e = Manager.parseSingle(validator.getContext(), new ByteArrayInputStream(cnt.getFocus()), cnt.getCntType());
t = t + new LanguageUtils(validator.getContext()).importFromTranslations(e, translations);
Manager.compose(validator.getContext(), e, new FileOutputStream(Utilities.path(dst, new File(ref.getRef()).getName())), cnt.getCntType(),

View File

@ -55,7 +55,7 @@ public class ValidateTask extends ValidationEngineTask {
}
System.out.println("Validating");
validationService.validateSources(cliContext, validationEngine, cliContext.getWatchMode());
validationService.validateSources(cliContext, validationEngine, cliContext.getWatchMode(), cliContext.getWatchScanDelay(), cliContext.getWatchSettleTime());
}
}

View File

@ -7,6 +7,7 @@ import java.util.Locale;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r5.terminologies.JurisdictionUtilities;
import org.hl7.fhir.r5.utils.validation.BundleValidationRule;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.validation.cli.model.CliContext;
import org.hl7.fhir.validation.cli.model.HtmlInMarkdownCheck;
@ -99,6 +100,8 @@ public class Params {
public static final String FILTER = "-filter";
private static final String FHIR_SETTINGS_PARAM = "-fhir-settings";
private static final String WATCH_MODE_PARAM = "-watch-mode";
private static final String WATCH_SCAN_DELAY = "-watch-scan-delay";
private static final String WATCH_SETTLE_TIME = "-watch-settle-time";
/**
* Checks the list of passed in params to see if it contains the passed in param.
@ -392,7 +395,18 @@ public class Params {
} else {
cliContext.setWatchMode(readWatchMode(args[++i]));
}
} else if (args[i].startsWith(X)) {
} else if (args[i].equals(WATCH_SCAN_DELAY)) {
if (i + 1 == args.length) {
throw new Error("Specified -watch-scan-delay without indicating mode value");
} else {
cliContext.setWatchScanDelay(readInteger(WATCH_SCAN_DELAY, args[++i]));
}
} else if (args[i].equals(WATCH_SETTLE_TIME)) {
if (i + 1 == args.length) {
throw new Error("Specified -watch-mode without indicating mode value");
} else {
cliContext.setWatchSettleTime(readInteger(WATCH_SETTLE_TIME, args[++i]));
} } else if (args[i].startsWith(X)) {
i++;
} else if (args[i].equals(CONVERT)) {
cliContext.setMode(EngineMode.CONVERT);
@ -413,6 +427,13 @@ public class Params {
return cliContext;
}
private static int readInteger(String n, String v) {
if (!Utilities.isInteger(v)) {
throw new Error("Unable to read "+v+" provided for '"+n+"' - must be an integer");
}
return Integer.parseInt(n);
}
private static ValidatorWatchMode readWatchMode(String s) {
if (s == null) {
return ValidatorWatchMode.NONE;

View File

@ -81,7 +81,14 @@ The following parameters are supported:
* single: when any of the validated files changes, re-validate it
* all: when any of the validated files changes, re-validate all of them
All is useful when the content includes internal dependencies e.g.
a profile and it's value sets.
a profile and it's value sets. Watch Mode has two additional parameters:
-watch-scan-delay (ms)
Control how often the validator looks at the content to decide to run again
Default 1000
-watch-settle-time (ms)
Control how long the validator waits before seeing a change, and revalidating
Default 100
-debug
Produce additional information about the loading/validation process
-recurse

View File

@ -48,8 +48,8 @@ public class ExternalTerminologyServiceTests implements ITxTesterLoader {
private JsonObject test;
}
private static final String SERVER = FhirSettings.getTxFhirDevelopment();
// private static final String SERVER = FhirSettings.getTxFhirLocal();
// private static final String SERVER = FhirSettings.getTxFhirDevelopment();
private static final String SERVER = FhirSettings.getTxFhirLocal();
// private static final String SERVER = "https://r4.ontoserver.csiro.au/fhir";

View File

@ -247,9 +247,11 @@ public class ValidatorCliTests {
CliContext cliContext = Params.loadCliContext(args);
ValidatorCli cli = mockValidatorCliWithService(cliContext);
ValidatorWatchMode watchMode = ValidatorWatchMode.NONE;
int watchScanDelay = 1000;
int watchSettleTime = 100;
cli.readParamsAndExecuteTask(cliContext, args);
Mockito.verify(validationService).determineVersion(same(cliContext));
Mockito.verify(validationService).validateSources(same(cliContext), same(validationEngine), same(watchMode));
Mockito.verify(validationService).validateSources(same(cliContext), same(validationEngine), same(watchMode), same(watchScanDelay), same(watchSettleTime));
}
@Test