Reverted out QuestionnaireScript changes

This commit is contained in:
Lloyd McKenzie 2024-09-22 11:10:46 -04:00
parent 4810ed3e0e
commit eba23cba20
18 changed files with 69 additions and 858 deletions

View File

@ -352,9 +352,9 @@ public class CapabilityStatementUtilities {
* Selects whichever code exists if only one exists, otherwise checks that the two codes match and merges conformance expectations
*/
private Enumeration merge(Enumeration targetCode, Enumeration importedCode, String maxConformance, String context) throws FHIRException {
if (targetCode == null)
if (targetCode == null || targetCode.getCode() == null)
return (Enumeration)fixMax(importedCode, maxConformance);
else if (importedCode == null)
else if (importedCode == null || importedCode.getCode() == null)
return targetCode;
else if (targetCode.getValue().equals(importedCode.getValue())) {
mergeExpectations(targetCode, importedCode, maxConformance);

View File

@ -279,7 +279,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
private int expandCodesLimit = 1000;
protected org.hl7.fhir.r5.context.ILoggingService logger = new SystemOutLoggingService();
protected Parameters expParameters;
protected Map<String, PackageInformation> packages = new HashMap<>();
private Map<String, PackageInformation> packages = new HashMap<>();
@Getter
protected TerminologyCache txCache = new TerminologyCache(this, null);

View File

@ -536,7 +536,7 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
for (PackageResourceInformation pri : pi.listIndexedResources(types)) {
if (!pri.getFilename().contains("ig-r4") && (loader == null || loader.wantLoad(pi, pri))) {
try {
if (!pri.hasId() || pri.getResourceType().equals("Basic")) {
if (!pri.hasId()) {
loadDefinitionItem(pri.getFilename(), ManagedFileAccess.inStream(pri.getFilename()), loader, null, pii);
} else {
registerResourceFromPackage(new PackageResourceLoader(pri, loader, pii), pii);
@ -830,7 +830,7 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
@Override
public PackageInformation getPackage(String id, String ver) {
return packages.get(id + "#" + ver);
return null;
}
public boolean isAllowLazyLoading() {

View File

@ -3,34 +3,34 @@ package org.hl7.fhir.r5.utils;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
/*
Copyright (c) 2011+, HL7, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of HL7 nor the names of its contributors may be used to
endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
/*
Copyright (c) 2011+, HL7, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of HL7 nor the names of its contributors may be used to
endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
@ -212,9 +212,8 @@ public class ToolingExtensions {
public static final String EXT_OLD_CONCEPTMAP_EQUIVALENCE = "http://hl7.org/fhir/1.0/StructureDefinition/extension-ConceptMap.element.target.equivalence";
public static final String EXT_Q_IS_SUBJ = "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-isSubject";
public static final String EXT_Q_HIDDEN = "http://hl7.org/fhir/StructureDefinition/questionnaire-hidden";
public static final String EXT_Q_OTP_DISP = "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-optionalDisplay";
public static final String EXT_O_LINK_PERIOD = "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationLinkPeriod";
public static final String EXT_O_EXTRACTION_RESOURCE = "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-extractionResource";
public static final String EXT_Q_OTP_DISP = "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-optionalDisplay";
public static final String EXT_O_LINK_PERIOD = "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationLinkPeriod";
public static final String EXT_Q_CHOICE_ORIENT = "http://hl7.org/fhir/StructureDefinition/questionnaire-choiceOrientation";
public static final String EXT_Q_DISPLAY_CAT = "http://hl7.org/fhir/StructureDefinition/questionnaire-displayCategory";
public static final String EXT_REND_MD = "http://hl7.org/fhir/StructureDefinition/rendering-markdown";

View File

@ -768,14 +768,11 @@ public class NpmPackage {
public List<PackageResourceInformation> listIndexedResources(List<String> types) throws IOException {
List<PackageResourceInformation> res = new ArrayList<PackageResourceInformation>();
List<String> basicTypes = new ArrayList<String>();
List<String> effectiveTypes = effectiveTypes(types);
for (NpmPackageFolder folder : folders.values()) {
JsonObject index = folder.index();
if (index != null) {
for (JsonObject fi : index.getJsonObjects("files")) {
String resourceType = fi.asString("resourceType");
if (Utilities.existsInList(resourceType, effectiveTypes) || types.isEmpty()) {
if (Utilities.existsInList(fi.asString("resourceType"), types) || types.isEmpty()) {
res.add(new PackageResourceInformation(folder.folder == null ? "@"+folder.getFolderName() : folder.folder.getAbsolutePath(), fi));
}
}
@ -785,17 +782,6 @@ public class NpmPackage {
return res;
}
private List<String> effectiveTypes(List<String> types) {
List<String> effective = new ArrayList<String>();
for (String type: types) {
if (type.startsWith("Basic-"))
effective.add("Basic");
else
effective.add(type);
}
return effective;
}
/**
* use the name from listResources()
*

View File

@ -9,7 +9,6 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.URISyntaxException;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
@ -23,8 +22,6 @@ import java.util.Set;
import java.util.UUID;
import org.fhir.ucum.UcumEssenceService;
import org.hl7.fhir.QuestionnaireItem;
import org.hl7.fhir.convertors.conv43_50.datatypes43_50.special43_50.Reference43_50;
import org.hl7.fhir.convertors.factory.VersionConvertorFactory_10_50;
import org.hl7.fhir.convertors.factory.VersionConvertorFactory_14_50;
import org.hl7.fhir.convertors.factory.VersionConvertorFactory_30_50;
@ -39,7 +36,6 @@ import org.hl7.fhir.r5.context.IWorkerContextManager;
import org.hl7.fhir.r5.context.SimpleWorkerContext;
import org.hl7.fhir.r5.context.SystemOutLoggingService;
import org.hl7.fhir.r5.elementmodel.*;
import org.hl7.fhir.r5.elementmodel.Element;
import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat;
import org.hl7.fhir.r5.fhirpath.ExpressionNode;
import org.hl7.fhir.r5.fhirpath.FHIRPathEngine;
@ -47,9 +43,22 @@ import org.hl7.fhir.r5.formats.FormatUtilities;
import org.hl7.fhir.r5.formats.IParser.OutputStyle;
import org.hl7.fhir.r5.formats.JsonParser;
import org.hl7.fhir.r5.formats.XmlParser;
import org.hl7.fhir.r5.model.*;
import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.Bundle;
import org.hl7.fhir.r5.model.Bundle.BundleEntryComponent;
import org.hl7.fhir.r5.renderers.ObligationsRenderer;
import org.hl7.fhir.r5.model.CanonicalResource;
import org.hl7.fhir.r5.model.CanonicalType;
import org.hl7.fhir.r5.model.Coding;
import org.hl7.fhir.r5.model.DomainResource;
import org.hl7.fhir.r5.model.ElementDefinition;
import org.hl7.fhir.r5.model.ImplementationGuide;
import org.hl7.fhir.r5.model.OperationOutcome;
import org.hl7.fhir.r5.model.PackageInformation;
import org.hl7.fhir.r5.model.Parameters;
import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.model.StructureMap;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.renderers.RendererFactory;
import org.hl7.fhir.r5.renderers.utils.RenderingContext;
import org.hl7.fhir.r5.renderers.utils.ResourceWrapper;
@ -85,7 +94,6 @@ import org.hl7.fhir.utilities.http.ManagedWebAccess;
import org.hl7.fhir.utilities.npm.CommonPackages;
import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager;
import org.hl7.fhir.utilities.npm.NpmPackage;
import org.hl7.fhir.utilities.npm.PackageInfo;
import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.utilities.xhtml.XhtmlComposer;
import org.hl7.fhir.validation.BaseValidator.ValidationControl;
@ -1033,557 +1041,6 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
return bs.toByteArray();
}
public Questionnaire genScriptQuestionnaire(String igPackageId, String canonical) throws FHIRException, IOException, Exception {
String[] packageParts = igPackageId.split("#");
PackageInformation p = context.getPackage(packageParts[0], packageParts[1]);
String igCanonical = p.getCanonical();
ImplementationGuide ig = (ImplementationGuide)context.fetchResource(ImplementationGuide.class, igCanonical + "/ImplementationGuide/" + packageParts[0]);
if (ig == null)
throw new FHIRException("Unable to load/find implementation guide " + igPackageId);
Questionnaire q = new Questionnaire();
q.setUrl(canonical);
q.setName(ig.getName() + "TestScriptQuestionnaire");
q.setTitle("Test Script Generation Questionnaire for " + ig.getTitle() + " IG");
q.setStatus(Enumerations.PublicationStatus.ACTIVE);
q.setDescription("A Questionnaire intended to gather information about the functionality a specific system has implemented from the '" +
ig.getTitle() + " implementation guide. QuestionnaireResponses can then go through an 'extraction' process to produce a " +
"TestScript designed to test only the implemented functionality");
q.addSubjectType("Endpoint");
q.addSubjectType("Device");
q.setDate(Date.from(Instant.now()));
TestScript script = new TestScript();
q.addContained(script);
q.addExtension(ToolingExtensions.EXT_O_EXTRACTION_RESOURCE, new Reference("#script"));
script.setId("script");
script.setUrl(canonical.replace("Questionnaire","TestScript"));
// Todo: Make name and description generate
script.setStatus(Enumerations.PublicationStatus.ACTIVE);
StringType title = new StringType("test");
Expression titleExp = new Expression().setLanguage("text/fhirpath").setExpression("%qr.item.where(linkId='title').answer & ' Test Script for '" +
ig.getTitle() + " Implementation Guide'");
title.addExtension(ToolingExtensions.EXT_CQF_EXP, titleExp);
script.setTitleElement(title);
MarkdownType descMd = new MarkdownType("test");
Expression descExp = new Expression().setLanguage("text/fhirpath").setExpression("'A Test script verifying that the ' & %qr.item.where(linkId='title').answer & ' system complies with the " +
ig.getTitle() + " implementation guide'");
descMd.addExtension(ToolingExtensions.EXT_CQF_EXP, descExp);
script.setDescriptionElement(descMd);
Map<String, CapabilityStatement> capabilities = new HashMap<String,CapabilityStatement>();
List<CapabilityStatement> usedCapabilities = new ArrayList<CapabilityStatement>();
List<ActorDefinition> actors = new ArrayList<ActorDefinition>();
for (ImplementationGuide.ImplementationGuideDefinitionResourceComponent r: ig.getDefinition().getResource()) {
if (r.getReference().hasReference()) {
if (r.getReference().getReference().startsWith("CapabilityStatement")) {
CapabilityStatement cap = (CapabilityStatement) context.fetchResource(CapabilityStatement.class, igCanonical + "/" + r.getReference().getReference());
if (cap == null)
throw new FHIRException("Unable to find CapabilityStatement " + r.getReference().getReference() + " in IG " + igPackageId);
capabilities.put(cap.getUrl(), cap);
} else if (r.getReference().getReference().startsWith("ActorDefinition")) {
ActorDefinition ad = (ActorDefinition) context.fetchResource(ActorDefinition.class, igCanonical + "/" + r.getReference().getReference());
if (ad == null)
throw new FHIRException("Unable to find ActorDefinition " + r.getReference().getReference() + " in IG " + igPackageId);
actors.add(ad);
}
}
}
if (actors.isEmpty())
throw new FHIRException("No ActorDefinitions found in IG " + igPackageId + ". TestScript generation depends on the presence of actor-specific obligations.");
if (capabilities.isEmpty())
throw new FHIRException("No CapabilityStatements found in IG " + igPackageId + ". TestScript generation depends on the presence of system-specific capabilities.");
Map<String, ActorDefinition> capabilityActors = new HashMap<String, ActorDefinition>();
List<String> actorUrls = new ArrayList<String>();
for (ActorDefinition actor: actors) {
if (actor.hasCapabilities()) {
if (capabilities.containsKey(actor.getCapabilities())) {
CapabilityStatement cap = capabilities.get(actor.getCapabilities());
usedCapabilities.add(cap);
capabilityActors.put(cap.getUrl(), actor);
actorUrls.add(actor.getUrl());
} else
throw new FHIRException("ActorDefinition " + actor.getUrl() + " refers to CapabilityStatement that is not defined in the same guide - " + actor.getCapabilities());
} else
System.out.println("ActorDefinition " + actor.getUrl() + " ignored because it is not associated with capabilities");
}
Questionnaire.QuestionnaireItemComponent sysItem = q.addItem().setLinkId("title").setType(Questionnaire.QuestionnaireItemType.STRING).setRequired(true).setRepeats(true);
sysItem.setText("Enter the name of the system for which the test script is being generated");
Questionnaire.QuestionnaireItemComponent capItem = q.addItem().setLinkId("capabilities").setType(Questionnaire.QuestionnaireItemType.CODING).setRequired(true).setRepeats(true);
capItem.setText("Which of the the following CapabilityStatements does your system implement?");
for (CapabilityStatement cap: usedCapabilities) {
capItem.addAnswerOption().setValue(new Coding("urn:ietf:rfc:3986", cap.getUrl(), cap.getTitle()));
}
Questionnaire.QuestionnaireItemComponent actorItem = q.addItem().setLinkId("actors").setType(Questionnaire.QuestionnaireItemType.CODING).setRequired(true).setRepeats(true);
actorItem.setText("Which of the the following ActorDefinitions does your system implement?");
actorItem.setReadOnly(true);
for (ActorDefinition actor: actors) {
Coding actorCoding = new Coding("urn:ietf:rfc:3986", actor.getUrl(), actor.getTitle());
actorItem.addAnswerOption().setValue(actorCoding);
actorItem.addInitial().setValue(actorCoding);
}
int capNum = 1;
for (CapabilityStatement cap: usedCapabilities) {
Questionnaire.QuestionnaireItemComponent capGroup = q.addItem().setLinkId("capabilities" + capNum).setType(Questionnaire.QuestionnaireItemType.GROUP).setRequired(true).setRepeats(false);
capGroup.setText("Implementation Details for " + cap.getTitle() + " Capabilities");
Questionnaire.QuestionnaireItemEnableWhenComponent ew = capGroup.addEnableWhen();
ew.setQuestion("capabilities").setOperator(Questionnaire.QuestionnaireItemOperator.EQUAL).setAnswer(new Coding("urn:ietf:rfc:3986", cap.getUrl(), cap.getTitle()));
processQuestionnaireCapabilities(capGroup, cap, capabilityActors.get(cap.getUrl()), actorUrls);
capNum++;
}
/*
If all of the capabilities require something, fix it to required/read-only. If some of the capabilities require something, make it conditionally required/read-only
If any of the capabilities require something, it's required. Otherwise, if something is optional for any of the capabilities, then it's optional
Look for min and max examples for each profile
*/
return q;
}
private void processQuestionnaireCapabilities(Questionnaire.QuestionnaireItemComponent capGroup, CapabilityStatement cap, ActorDefinition actor, List<String> actorUrls) {
if (!cap.hasRest()) {
System.out.println("Capability Statement " + cap.getUrl() + " is ignored as it has no REST features. Testing of messages, documents, and other exchanges is not yet supported.");
return;
}
for (CapabilityStatement.CapabilityStatementRestComponent rest: cap.getRest()) {
List<String> resources = new ArrayList<String>();
Map<String, CapabilityStatement.CapabilityStatementRestResourceComponent> resourceComponents = new HashMap<String, CapabilityStatement.CapabilityStatementRestResourceComponent>();
Map<String, List<StructureDefinition>> resourceProfiles = new HashMap<String, List<StructureDefinition>>();
Questionnaire.QuestionnaireItemComponent inst = capGroup.addItem().setLinkId(capGroup.getLinkId()+ "inst" + rest.getMode()).setType(Questionnaire.QuestionnaireItemType.DISPLAY);
inst.setText("Indicate which resources are supported, and for each supported, resource, which interaction types are supported");
inst.addExtension(ToolingExtensions.EXT_Q_DISPLAY_CAT, Factory.newCodeableConcept("instructions", "http://hl7.org/fhir/questionnaire-item-control", "Instructions"));
Questionnaire.QuestionnaireItemComponent restItem = capGroup.addItem().setLinkId(capGroup.getLinkId()+rest.getMode()).setType(Questionnaire.QuestionnaireItemType.GROUP).setRequired(true).setRepeats(false);
restItem.setText(rest.getMode().getDisplay() + " Capabilities");
restItem.addExtension(ToolingExtensions.EXT_CONTROL, Factory.newCodeableConcept("grid", "http://hl7.org/fhir/questionnaire-item-control", "Grid"));
for (CapabilityStatement.CapabilityStatementRestResourceComponent r: rest.getResource()) {
if (!r.hasExtension(ToolingExtensions.EXT_CAP_STMT_EXPECT)) {
System.out.println("Ignoring resource " + r.getType() + " for CapabilityStatement " + cap.getUrl() + " because it does not declare SHALL/SHOULD/MAY - and that is required for testing purposes.");
} else if (!r.hasSupportedProfile()) {
System.out.println("Ignoring resource " + r.getType() + " for CapabilityStatement " + cap.getUrl() + " because it does not declare a profile - and that is required for testing purposes.");
} else {
if (!resources.contains(r.getType())) {
resources.add(r.getType());
resourceComponents.put(r.getType(), r);
List<StructureDefinition> profiles = new ArrayList<StructureDefinition>();
for (CanonicalType canonical: r.getSupportedProfile()) {
StructureDefinition profile = context.fetchResource(StructureDefinition.class, canonical.getValue());
if (profile==null)
throw new FHIRException("Unable to find profile " + canonical.getValue() + " referenced in CapabilityStatement " + cap.getUrl());
profiles.add(profile);
}
resourceProfiles.put(r.getType(), profiles);
}
Questionnaire.QuestionnaireItemComponent resourceGrp = restItem.addItem().setLinkId(restItem.getLinkId() + r.getType()).setType(Questionnaire.QuestionnaireItemType.GROUP).setRequired(true).setRepeats(false);
resourceGrp.setText(r.getType());
Questionnaire.QuestionnaireItemComponent resourceItem = resourceGrp.addItem().setLinkId(resourceGrp.getLinkId() + "-supported").setType(Questionnaire.QuestionnaireItemType.BOOLEAN).setRequired(true).setRepeats(false);
// resourceItem.addExtension(ToolingExtensions.EXT_CONTROL, Factory.newCodeableConcept("check-box", "http://hl7.org/fhir/questionnaire-item-control", "Check-box"));
resourceItem.setText("Supported?");
CodeType conformance = r.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT).getValueCodeType();
if (conformance.getCode().equals("SHALL")) {
resourceItem.setReadOnly(true);
resourceItem.addInitial().setValue(new BooleanType(true));
}
/* In theory, all of these can be tested, but going to start with simpler tests for now */
questionnaireResourceInteraction(resourceGrp, resourceItem, r, "read");
questionnaireResourceInteraction(resourceGrp, resourceItem, r, "vread");
questionnaireResourceInteraction(resourceGrp, resourceItem, r, "update");
/* questionnaireResourceInteraction(resourceGrp, resourceItem, r, "update-conditional");
questionnaireResourceInteraction(resourceGrp, resourceItem, r, "patch");
questionnaireResourceInteraction(resourceGrp, resourceItem, r, "patch-conditional");
questionnaireResourceInteraction(resourceGrp, resourceItem, r, "delete");
questionnaireResourceInteraction(resourceGrp, resourceItem, r, "delete-conditional-single");
questionnaireResourceInteraction(resourceGrp, resourceItem, r, "delete-conditional-multiple");
questionnaireResourceInteraction(resourceGrp, resourceItem, r, "delete-history");
questionnaireResourceInteraction(resourceGrp, resourceItem, r, "delete-history-version");
questionnaireResourceInteraction(resourceGrp, resourceItem, r, "history-instance");
questionnaireResourceInteraction(resourceGrp, resourceItem, r, "history-type");*/
questionnaireResourceInteraction(resourceGrp, resourceItem, r, "create");
// questionnaireResourceInteraction(resourceGrp, resourceItem, r, "create-conditional");
questionnaireResourceInteraction(resourceGrp, resourceItem, r, "search-type");
}
}
Questionnaire.QuestionnaireItemComponent inst2 = capGroup.addItem().setLinkId(capGroup.getLinkId()+ "inst" + rest.getMode()).setType(Questionnaire.QuestionnaireItemType.DISPLAY);
inst2.setText("For each of the following resource profiles, for each element indicate which optional obligations are supported.");
inst2.addExtension(ToolingExtensions.EXT_Q_DISPLAY_CAT, Factory.newCodeableConcept("instructions", "http://hl7.org/fhir/questionnaire-item-control", "Instructions"));
Questionnaire.QuestionnaireItemComponent profilesGrp = capGroup.addItem().setLinkId(restItem.getLinkId() + "profiles").setType(Questionnaire.QuestionnaireItemType.GROUP).setRequired(true).setRepeats(false);
profilesGrp.setText("Profiles support");
resources.sort(new Utilities.CaseInsensitiveSorter());
for (String resourceName: resources) {
List<String> obligationElementPaths = new ArrayList<String>();
Map<String, TestingObligations> obligations = new HashMap<String, TestingObligations>();
List<StructureDefinition> profiles = resourceProfiles.get(resourceName);
for (StructureDefinition profile: profiles) {
// Get list of obligations declared on the resource rather than on particular elements.
List<Extension> globals = profile.getExtensionsByUrl(ToolingExtensions.EXT_OBLIGATION_CORE);
Map<String, List<Extension>> globalsById = new HashMap<String, List<Extension>>();
for (Extension ext: globals) {
for (Extension element: ext.getExtensionsByUrl("elementId")) {
String elementId = element.getValueStringType().toString();
List<Extension> obligationList = globalsById.get(elementId);
if (obligationList==null) {
obligationList = new ArrayList<Extension>();
globalsById.put(elementId, obligationList);
}
obligationList.add(ext);
}
}
boolean foundObligations = false;
// NOTE: This process presumes that if the path is the same, the element is equivalent. In theory it's possible for slice
// names to be the same in multiple profiles defined in a single IG to actually correspond to different discriminators and/or different discriminator values.
// However, doing that is a super confusing thing for implementers and this code presumes IG authors won't be that foolish/sadistic.
for (ElementDefinition e: profile.getSnapshot().getElement()) {
TestingObligations testingObligations;
if (obligationElementPaths.contains(e.getPath())) {
testingObligations = obligations.get(e.getPath());
} else
testingObligations = new TestingObligations(actorUrls);
boolean foundElementObligations = testingObligations.processObligations(e);
boolean foundGlobalObligations = testingObligations.processObligations(globalsById.get(e.getPath()));
foundObligations = foundObligations || foundElementObligations || foundGlobalObligations;
if (!testingObligations.isEmpty() && !obligationElementPaths.contains(e.getPath())) {
obligationElementPaths.add(e.getPath());
obligations.put(e.getPath(), testingObligations);
}
}
if (!foundObligations) {
System.out.println("Not exposing profile " + profile.getTitle() + " because there are no obligations defined in the profile and obligations are required for testing");
} else if (obligations.isEmpty()) {
System.out.println("Not exposing resource " + profile.getTitle() + " because none of the found obligations were applicable for testing for the in-scope ActorDefinitions");
}
}
Questionnaire.QuestionnaireItemComponent profileGrp = profilesGrp.addItem().setLinkId(restItem.getLinkId() + "profiles").setType(Questionnaire.QuestionnaireItemType.GROUP).setRequired(true).setRepeats(false);
profileGrp.setText(resourceName + "(Amalgamated across " + profiles.size() + " profiles + ) Elements");
profileGrp.addExtension(ToolingExtensions.EXT_CONTROL, Factory.newCodeableConcept("grid", "http://hl7.org/fhir/questionnaire-item-control", "Grid"));
Questionnaire.QuestionnaireItemEnableWhenComponent ew = profileGrp.addEnableWhen();
ew.setQuestion(restItem.getLinkId() + resourceName + "-supported").setOperator(Questionnaire.QuestionnaireItemOperator.EQUAL).setAnswer(new BooleanType(true));
// While alphabetic sorting kind of sucks, because we're grabbing elements from multiple profiles, each of which may have their own slicing hierarchy, there isn't really a better way.
obligationElementPaths.sort(new Utilities.CaseInsensitiveSorter());
Questionnaire.QuestionnaireItemComponent setAllGrp = null;
List<String> allCodes = new ArrayList<String>();
if (obligationElementPaths.size() > 2) {
setAllGrp = profileGrp.addItem().setLinkId(profileGrp.getLinkId() + "SETALL").setType(Questionnaire.QuestionnaireItemType.GROUP).setRequired(true).setRepeats(false);
setAllGrp.setText("Set/Clear all");
}
for (String path: obligationElementPaths) {
Questionnaire.QuestionnaireItemComponent elementGrp = profileGrp.addItem().setLinkId(profileGrp.getLinkId() + path).setType(Questionnaire.QuestionnaireItemType.GROUP).setRequired(true).setRepeats(false);
elementGrp.setText(path);
TestingObligations testingObligations = obligations.get(path);
allCodes.addAll(testingObligations.getCodes());
for (String oCode: testingObligations.getCodes()) {
Questionnaire.QuestionnaireItemComponent obligationItem = elementGrp.addItem().setLinkId(elementGrp.getLinkId() + "-" + oCode).setType(Questionnaire.QuestionnaireItemType.BOOLEAN).setRequired(true).setRepeats(false);
// Todo: Use displayname instead
obligationItem.setText(oCode);
if (testingObligations.isAlwaysRequired(oCode)) {
obligationItem.addInitial().setValue(new BooleanType(true));
obligationItem.setReadOnly(true);
} else if (testingObligations.isConditionallyRequired(oCode)) {
// todo
String expression = "%resource.item.where(linkId='actors').answer.value.where(";
boolean first = true;
for (String actorUrl: testingObligations.requiredActors(oCode)) {
expression += "code='" + actorUrl + "'";
if (first)
first = false;
else
expression += " or ";
}
expression += ").exists()";
Expression expr = new Expression().setLanguage("text/fhirpath").setExpression(expression);
BooleanType b = new BooleanType();
b.addExtension(new Extension(ToolingExtensions.EXT_CQF_EXP, expr));
obligationItem.addInitial().setValue(b);
obligationItem.setReadOnlyElement(b);
} else if (setAllGrp != null) {
// todo handle descendants
Expression expr = new Expression().setLanguage("text/fhirpath").setExpression("%resource.item.where(linkId='" + setAllGrp.getLinkId() + oCode + "').answer.value");
obligationItem.addInitial().addExtension(ToolingExtensions.EXT_CQF_EXP, expr);
}
}
}
// if ()
profileGrp = profilesGrp.addItem().setLinkId(restItem.getLinkId() + "profiles").setType(Questionnaire.QuestionnaireItemType.GROUP).setRequired(true).setRepeats(false);
profileGrp.setText(resourceName + "(Amalgamated across " + profiles.size() + " profiles + ) Elements");
}
/* for (CapabilityStatement.CapabilityStatementRestResourceComponent r: rest.getResource()) {
if (r.hasExtension(ToolingExtensions.EXT_CAP_STMT_EXPECT)) {
Questionnaire.QuestionnaireItemComponent resourceGrp = restItem.addItem().setLinkId(restItem.getLinkId() + r.getType()).setType(Questionnaire.QuestionnaireItemType.GROUP).setRequired(true).setRepeats(false);
}
}*/
if (!restItem.hasItem()) {
// No questions about this rest mode, so drop it
capGroup.getItem().remove(restItem);
}
}
}
/*
* Takes the set of obligations associated with an element and exposes information about the specific testable
* obligation codes that apply, as well as to which actors and whether those obligations are optional or mandatory
*/
class TestingObligations {
private List<String> actorUrls;
private boolean hadObligations = false;
private List<String> codes = new ArrayList<String>();
private boolean sorted = false;
private Map<String, Map<String,ActorObligation>> details = new HashMap<>();
/*
* Class for capturing the details about a specific testable obligation code for a specific actor
*/
private class ActorObligation {
String actorUrl;
String code;
boolean optional;
ActorObligation(String originalCode, String filteredCode, String actorUrl) {
this.actorUrl = actorUrl;
this.code = filteredCode;
optional = checkOptional(originalCode);
}
/*
* In cases where the same code is declared for the same actor more than once, the stricter optionality applies
*/
public void updateOptionality(String originalCode) {
optional = optional && checkOptional(originalCode);
}
/*
* Obligatins are optional if they are SHOULD or MAY or if the obligation code is itself intrinsically optional
*/
private boolean checkOptional(String originalCode) {
return originalCode.startsWith("SHOULD:") || originalCode.startsWith("MAY:") || originalCode.endsWith(":able-to-populate");
}
public boolean isOptional() {
return optional;
}
}
/*
* We take in the list of actor ids that are relevant for this particular element
*/
TestingObligations(List<String> actorUrls) {
this.actorUrls = actorUrls;
}
/*
* Captures the computable obligation codes for the obligations on the specified element as well as the actors they apply to and whether
* the obligations are optional or not
*/
boolean processObligations(ElementDefinition e) {
return processObligations(e.getExtensionsByUrl(ToolingExtensions.EXT_OBLIGATION_CORE));
}
/*
* Captures the computable obligation codes for the specified obligations as well as the actors they apply to and whether
* the obligations are optional or not
*/
boolean processObligations(List<Extension> obligations) {
if (obligations==null || obligations.isEmpty())
return false;
hadObligations = true;
for (Extension obligation: obligations) {
processObligation(obligation);
}
return true;
}
/*
* Captures the computable obligation codes for the specified obligation as well as the actors they apply to and whether
* the obligations are optional or not
*/
protected void processObligation(Extension ext) {
ObligationsRenderer.ObligationDetail obligation = new ObligationsRenderer.ObligationDetail(ext);
if (obligation.hasFilter()) {
context.getLogger().logDebugMessage(ILoggingService.LogCategory.CONTEXT, "Obligations with filters are ignored");
return;
}
if (obligation.hasUsage()) {
context.getLogger().logDebugMessage(ILoggingService.LogCategory.CONTEXT, "Obligations with usage constraints are ignored");
return;
}
if (!inActors(obligation))
return;
for (String originalCode: obligation.getCodeList()) {
String filteredCode = filter(originalCode);
Map<String, ActorObligation> actorObs;
if (filteredCode==null) {
continue;
} else if (codes.contains(filteredCode)) {
actorObs = details.get(filteredCode);
} else {
actorObs = new HashMap<String, ActorObligation>();
details.put(filteredCode, actorObs);
codes.add(filteredCode);
sorted = false;
}
processDetail(obligation, actorObs, originalCode, filteredCode);
}
}
/*
* Updates the list of associated actor expectations for the specified code
*/
private void processDetail(ObligationsRenderer.ObligationDetail obligation, Map<String, ActorObligation> actorObs, String originalCode, String filteredCode) {
for (String actorUrl: actorUrls) {
if (obligation.hasActor(actorUrl)) {
if (actorObs.containsKey(actorUrl)) {
ActorObligation actorOb = actorObs.get(actorUrl);
actorOb.updateOptionality(originalCode);
} else {
ActorObligation actorOb = new ActorObligation(originalCode, filteredCode, actorUrl);
actorObs.put(actorUrl, actorOb);
}
}
}
}
/*
* Returns true if the specified obligation applies to any of the in-scope actors for the associated element
*/
private boolean inActors(ObligationsRenderer.ObligationDetail obligation) {
for (String actorUrl: actorUrls) {
if (obligation.hasActor(actorUrl))
return true;
}
return false;
}
/*
* Returns a code without the 'conformance' prefix and turns intrinsically 'optional' obligation codes into their
* equivalent non-optional code
*/
private String filter(String code) {
String baseCode = code.substring(code.indexOf(":")+1);
switch (baseCode) {
case "able-to-populate":
case "alter":
case "process":
return null;
case "populate-if-known":
return "populate";
}
return baseCode;
}
/*
* Returns true if obligations were present on the associated element, even if none were in scope
*/
public boolean hadObligations() {
return this.hadObligations;
}
/*
* Returns true if there were no in-scope obligations
*/
public boolean isEmpty() {
return codes.isEmpty();
}
/*
* Returns the 'simple' testable obligation codes that hold for the element with this element
*/
public List<String> getCodes() {
if (!sorted)
codes.sort(new Utilities.CaseInsensitiveSorter());
sorted = true;
return codes;
}
public boolean isAlwaysRequired(String code) {
Map<String, ActorObligation> actorObs = details.get(code);
boolean alwaysRequired = true;
for (ActorObligation actorOb: actorObs.values()) {
if (actorOb.isOptional())
return false;
}
return alwaysRequired;
}
public boolean isConditionallyRequired(String code) {
Map<String, ActorObligation> actorObs = details.get(code);
boolean usesRequired = false;
boolean usesOptional = false;
for (ActorObligation actorOb: actorObs.values()) {
if (actorOb.isOptional())
usesOptional = true;
else
usesRequired = true;
}
return (usesOptional==usesRequired);
}
public List<String> requiredActors(String code) {
List<String> list = new ArrayList<String>();
Map<String, ActorObligation> actorObs = details.get(code);
for (ActorObligation actorOb: actorObs.values()) {
if (!actorOb.isOptional())
list.add(actorOb.actorUrl);
}
return list;
}
}
/*
* todo
*/
public void questionnaireResourceInteraction(Questionnaire.QuestionnaireItemComponent resourceGrp, Questionnaire.QuestionnaireItemComponent resourceItem, CapabilityStatement.CapabilityStatementRestResourceComponent r, String interactionCode) {
for (CapabilityStatement.ResourceInteractionComponent interaction: r.getInteraction()) {
if (interaction.getCode().toCode().equals(interactionCode)) {
Questionnaire.QuestionnaireItemComponent interactionItem = resourceGrp.addItem().setLinkId(resourceGrp.getLinkId() + interactionCode).setType(Questionnaire.QuestionnaireItemType.BOOLEAN).setRequired(true).setRepeats(false);
// interactionItem.addExtension(ToolingExtensions.EXT_CONTROL, Factory.newCodeableConcept("check-box", "http://hl7.org/fhir/questionnaire-item-control", "Check-box"));
interactionItem.setText(interaction.getCode().toCode());
Questionnaire.QuestionnaireItemEnableWhenComponent ew = interactionItem.addEnableWhen();
ew.setQuestion(resourceItem.getLinkId()).setOperator(Questionnaire.QuestionnaireItemOperator.EQUAL).setAnswer(new BooleanType(true));
CodeType conformance = interaction.getExtensionByUrl(ToolingExtensions.EXT_CAP_STMT_EXPECT).getValueCodeType();
if (conformance.getCode().equals("SHALL")) {
interactionItem.setReadOnly(true);
interactionItem.addInitial().setValue(new BooleanType(true));
}
}
}
}
/*
* todo
*/
public void questionnaireExtract(String source, String outputDir, FhirFormat format) throws FHIRException, IOException, Exception {
Content cnt = igLoader.loadContent(source, "questionnaireExtract", false, true);
org.hl7.fhir.r5.elementmodel.Element src = Manager.parseSingle(context, new ByteArrayInputStream(cnt.getFocus().getBytes()), cnt.getCntType());
}
private String getMapId(String type, String targetVer) {
if (VersionUtilities.isR2Ver(version)) {
if (VersionUtilities.isR3Ver(targetVer)) {

View File

@ -135,8 +135,6 @@ public class ValidatorCli {
new TxTestsTask(),
new TransformTask(),
new VersionTask(),
new QuestionnaireExtractTask(),
new TestScriptQuestionnaireTask(),
defaultCliTask);
}
@ -340,10 +338,6 @@ public class ValidatorCli {
res.add("5.0");
res.add("-ig");
res.add("hl7.fhir.uv.sql-on-fhir#current");
} else if (a.equals("-questionnaire-extract") || a.equals("-script-questionnaire")) {
res.add(a);
res.add("-tx");
res.add("n/a");
} else {
res.add(a);
}

View File

@ -91,25 +91,25 @@ public class ValidatorUtils {
return null;
}
if (VersionUtilities.isR2Ver(version)) {
return new R2ToR5Loader(Utilities.strings("Conformance", "StructureDefinition", "ValueSet", "ActorDefinition", "ImplementationGuide", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem"), loader);
return new R2ToR5Loader(Utilities.strings("Conformance", "StructureDefinition", "ValueSet", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem"), loader);
}
if (VersionUtilities.isR2BVer(version)) {
return new R2016MayToR5Loader(Utilities.strings("Conformance", "StructureDefinition", "ValueSet", "Basic-ActorDefinition", "ActorDefinition", "ImplementationGuide", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem"), loader); // special case
return new R2016MayToR5Loader(Utilities.strings("Conformance", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem"), loader); // special case
}
if (VersionUtilities.isR3Ver(version)) {
return new R3ToR5Loader(Utilities.strings("CapabilityStatement", "StructureDefinition", "ValueSet", "Basic-ActorDefinition", "ActorDefinition", "ImplementationGuide", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem"), loader);
return new R3ToR5Loader(Utilities.strings("CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem"), loader);
}
if (VersionUtilities.isR4Ver(version)) {
return new R4ToR5Loader(Utilities.strings("CapabilityStatement", "StructureDefinition", "ValueSet", "Basic-ActorDefinition", "ImplementationGuide", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem"), loader, version);
return new R4ToR5Loader(Utilities.strings("CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem"), loader, version);
}
if (VersionUtilities.isR4BVer(version)) {
return new R4BToR5Loader(Utilities.strings("CapabilityStatement", "StructureDefinition", "ValueSet", "Basic-ActorDefinition", "ImplementationGuide", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem"), loader, version);
return new R4BToR5Loader(Utilities.strings("CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem"), loader, version);
}
if (VersionUtilities.isR5Ver(version)) {
return new R5ToR5Loader(Utilities.strings("CapabilityStatement", "StructureDefinition", "ValueSet", "ActorDefinition", "ImplementationGuide", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem"), loader);
return new R5ToR5Loader(Utilities.strings("CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem"), loader);
}
if (VersionUtilities.isR6Ver(version)) {
return new R6ToR5Loader(Utilities.strings("CapabilityStatement", "StructureDefinition", "ValueSet", "ActorDefinition", "ImplementationGuide", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem"), loader);
return new R6ToR5Loader(Utilities.strings("CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem"), loader);
}
return null;
}

View File

@ -68,8 +68,6 @@ public class CliContext {
private String map = null;
@JsonProperty("output")
private String output = null;
@JsonProperty("outputCanonical")
private String outputCanonical = null;
@JsonProperty("outputSuffix")
private String outputSuffix;
@JsonProperty("htmlOutput")
@ -164,7 +162,7 @@ public class CliContext {
@JsonProperty("bestPracticeLevel")
private BestPracticeWarningLevel bestPracticeLevel = BestPracticeWarningLevel.Warning;
@JsonProperty("baseEngine")
public String getBaseEngine() {
return baseEngine;
@ -441,17 +439,6 @@ public class CliContext {
return this;
}
@JsonProperty("outputCanonical")
public String getOutputCanonical() {
return outputCanonical;
}
@JsonProperty("outputCanonical")
public CliContext setOutputCanonical(String outputCanonical) {
this.outputCanonical = outputCanonical;
return this;
}
@JsonProperty("outputSuffix")
public String getOutputSuffix() {
return outputSuffix;

View File

@ -26,7 +26,15 @@ import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat;
import org.hl7.fhir.r5.elementmodel.ValidatedFragment;
import org.hl7.fhir.r5.formats.IParser;
import org.hl7.fhir.r5.formats.IParser.OutputStyle;
import org.hl7.fhir.r5.model.*;
import org.hl7.fhir.r5.model.Bundle;
import org.hl7.fhir.r5.model.CanonicalResource;
import org.hl7.fhir.r5.model.CodeSystem;
import org.hl7.fhir.r5.model.ConceptMap;
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.StructureMap;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.renderers.spreadsheets.CodeSystemSpreadsheetGenerator;
import org.hl7.fhir.r5.renderers.spreadsheets.ConceptMapSpreadsheetGenerator;
import org.hl7.fhir.r5.renderers.spreadsheets.StructureDefinitionSpreadsheetGenerator;
@ -475,49 +483,6 @@ public class ValidationService {
}
}
public void genScriptQuestionnaire(CliContext cliContext, ValidationEngine validator) throws Exception {
if (cliContext.getIgs().size() != 1) {
throw new Exception("Must have exactly one IG when generating TestScript questionnaires (found " + cliContext.getIgs().size() + ")");
}
if (cliContext.getOutput() == null) {
throw new Exception("Must nominate an output when generating TestScript questionnaires");
}
if (cliContext.getOutputCanonical() == null) {
throw new Exception("Must specify an outputCanonical URL for the generated Questionnaire");
}
try {
/* if (cliContext.getMapLog() != null) {
validator.setMapLog(cliContext.getMapLog());
}*/
Questionnaire q = validator.genScriptQuestionnaire(cliContext.getIgs().get(0), cliContext.getOutputCanonical());
System.out.println(" ...success");
validator.handleOutput(q, cliContext.getOutput(), cliContext.getSv());
} catch (Exception e) {
System.out.println(" ...Failure: " + e.getMessage());
e.printStackTrace();
}
}
public void questionnaireExtract(CliContext cliContext, ValidationEngine validator) throws Exception {
if (cliContext.getSources().size() != 1) {
throw new Exception("Must have exactly one source QuestionnaireResponse when performing a Questionnaire extract");
}
if (cliContext.getOutput() == null) {
throw new Exception("Must nominate an output folder when extracting from a QuestionnaireResponse");
}
try {
/* if (cliContext.getMapLog() != null) {
validator.setMapLog(cliContext.getMapLog());
}*/
validator.questionnaireExtract(cliContext.getSources().get(0), cliContext.getOutput(), cliContext.getOutputSuffix().equals("json") ? Manager.FhirFormat.JSON : Manager.FhirFormat.XML);
System.out.println(" ...success");
} catch (Exception e) {
System.out.println(" ...Failure: " + e.getMessage());
e.printStackTrace();
}
}
public ValidationEngine initializeValidator(CliContext cliContext, String definitions, TimeTracker tt) throws Exception {
return sessionCache.fetchSessionValidatorEngine(initializeValidator(cliContext, definitions, tt, null));
}

View File

@ -1,44 +0,0 @@
package org.hl7.fhir.validation.cli.tasks;
import org.hl7.fhir.utilities.TimeTracker;
import org.hl7.fhir.validation.ValidationEngine;
import org.hl7.fhir.validation.cli.model.CliContext;
import org.hl7.fhir.validation.cli.services.ValidationService;
import org.hl7.fhir.validation.cli.utils.Display;
import org.hl7.fhir.validation.cli.utils.EngineMode;
import java.io.PrintStream;
public class QuestionnaireExtractTask extends ValidationEngineTask {
@Override
public String getName() {
return "questionnaire-extract";
}
@Override
public String getDisplayName() {
return "Questionnaire Extraction";
}
@Override
public boolean isHidden() {
return false;
}
@Override
public boolean shouldExecuteTask(CliContext cliContext, String[] args) {
return cliContext.getMode() == EngineMode.QUESTIONNAIRE_EXTRACT;
}
@Override
public void printHelp(PrintStream out) {
Display.displayHelpDetails(out,"help/questionnaire-extract.txt");
}
@Override
public void executeTask(ValidationService validationService, ValidationEngine validationEngine, CliContext cliContext, String[] args, TimeTracker tt, TimeTracker.Session tts) throws Exception {
validationService.questionnaireExtract(cliContext, validationEngine);
}
}

View File

@ -1,44 +0,0 @@
package org.hl7.fhir.validation.cli.tasks;
import org.hl7.fhir.utilities.TimeTracker;
import org.hl7.fhir.validation.ValidationEngine;
import org.hl7.fhir.validation.cli.model.CliContext;
import org.hl7.fhir.validation.cli.services.ValidationService;
import org.hl7.fhir.validation.cli.utils.Display;
import org.hl7.fhir.validation.cli.utils.EngineMode;
import java.io.PrintStream;
public class TestScriptQuestionnaireTask extends ValidationEngineTask {
@Override
public String getName() {
return "script-questionnaire";
}
@Override
public String getDisplayName() {
return "Generate Test Script Questionnaire";
}
@Override
public boolean isHidden() {
return false;
}
@Override
public boolean shouldExecuteTask(CliContext cliContext, String[] args) {
return cliContext.getMode() == EngineMode.SCRIPT_QUESTIONNAIRE;
}
@Override
public void printHelp(PrintStream out) {
Display.displayHelpDetails(out,"help/script-questionnaire.txt");
}
@Override
public void executeTask(ValidationService validationService, ValidationEngine validationEngine, CliContext cliContext, String[] args, TimeTracker tt, TimeTracker.Session tts) throws Exception {
validationService.genScriptQuestionnaire(cliContext, validationEngine);
}
}

View File

@ -13,7 +13,5 @@ public enum EngineMode {
FHIRPATH,
VERSION,
RUN_TESTS,
INSTALL,
SCRIPT_QUESTIONNAIRE,
QUESTIONNAIRE_EXTRACT
INSTALL
}

View File

@ -23,7 +23,6 @@ public class Params {
public static final String OUTPUT = "-output";
public static final String OUTPUT_SUFFIX = "-outputSuffix";
public static final String OUTPUT_CANONICAL = "-outputCanonical";
public static final String LEVEL = "-level";
public static final String HTML_OUTPUT = "-html-output";
public static final String PROXY = "-proxy";
@ -68,8 +67,6 @@ public class Params {
public static final String HELP = "help";
public static final String COMPARE = "-compare";
public static final String SPREADSHEET = "-spreadsheet";
public static final String SCRIPT_QUESTIONNAIRE = "-script-questionnaire";
public static final String QUESTIONNAIRE_EXTRACT = "-questionnaire-extract";
public static final String DESTINATION = "-dest";
public static final String LEFT = "-left";
public static final String RIGHT = "-right";
@ -168,11 +165,6 @@ public class Params {
throw new Error("Specified -outputSuffix without indicating output suffix");
else
cliContext.setOutputSuffix(args[++i]);
} else if (args[i].equals(OUTPUT_CANONICAL)) {
if (i + 1 == args.length)
throw new Error("Specified -outputCanonical without indicating output canonical");
else
cliContext.setOutputCanonical(args[++i]);
}
else if (args[i].equals(HTML_OUTPUT)) {
if (i + 1 == args.length)
@ -458,10 +450,6 @@ public class Params {
cliContext.setFhirpath(args[++i]);
else
throw new Exception("Can only nominate a single -fhirpath parameter");
} else if (args[i].equals(SCRIPT_QUESTIONNAIRE)) {
cliContext.setMode(EngineMode.SCRIPT_QUESTIONNAIRE);
} else if (args[i].equals(QUESTIONNAIRE_EXTRACT)) {
cliContext.setMode(EngineMode.SCRIPT_QUESTIONNAIRE);
} else {
cliContext.addSource(args[i]);
}

View File

@ -1,11 +0,0 @@
You can use the validator to take a QuestionnaireResponse and a Questionnaire (or IG containing the Questionnaire) and perform an extraction process
to generate resources based on the information found in the QuestionnaireResponse.
NOTE: At present, this feature only supports the 'contained resource' extraction approach. (Refer to the Structured Data Capture IG.)
For parameters, you must specify:
-ig to identify the IG containing the CapabilityStatements, and ActorDefinitions to generate test scripts for
-output to identify the filename of the Questionnaire to create
Example: `-questionnaire-extract -questionnaire questionnaire.json -questionnaire-response response.json -output c:\someFolder\`
This will put the generated resources in the someFolder location

View File

@ -1,9 +0,0 @@
You can use the validator to generate a Questionnaire which, when completed, can produce a TestScript (using questionnaire-extract) that
can test a specific system against a guide. The Questionnaire will prompt a user to answer questions about which optional capabilities
defined by an IG a given system supports - allowing creation of a system-specific test script focused on exactly what the system does.
For parameters, you must specify:
-ig to identify the IG containing the CapabilityStatements, and ActorDefinitions to generate test scripts for
-questionnaire to identify the filename of the Questionnaire to create
Example: `-ig hl7.fhir.us.physical-activity#1.0.0 -script-questionnaire -output outputQuestionnaire.json`

View File

@ -58,12 +58,6 @@ public class ValidatorCliTests {
@Spy
SpreadsheetTask spreadsheetTask;
@Spy
TestScriptQuestionnaireTask testScriptQuestionnaireTask;
@Spy
QuestionnaireExtractTask questionnaireExtractTask;
@Spy
PreloadCacheTask preloadCacheTask = new PreloadCacheTask() {
@Override
@ -124,8 +118,6 @@ public class ValidatorCliTests {
txTestsTask,
transformTask,
versionTask,
questionnaireExtractTask,
testScriptQuestionnaireTask,
//validate is the default
validateTask
);
@ -260,26 +252,6 @@ public class ValidatorCliTests {
Mockito.verify(validationService).transformLang(same(cliContext), same(validationEngine));
}
@Test
public void testScriptQuestionnaireTest() throws Exception {
final String[] args = new String[]{"-ig", "hl7.fhir.us.physical-activity#dev", "-script-questionnaire", "-output", "outputQuestionnaire.json"};
CliContext cliContext = Params.loadCliContext(args);
ValidatorCli cli = mockValidatorCliWithService(cliContext);
cli.readParamsAndExecuteTask(cliContext, args);
Mockito.verify(validationService).determineVersion(same(cliContext));
Mockito.verify(validationService).genScriptQuestionnaire(same(cliContext), same(validationEngine));
}
@Test
public void questionnaireExtractTest() throws Exception {
final String[] args = new String[]{"questionnaireResponse.json", "-questionnaire-extract", "-output", "testScripts"};
CliContext cliContext = Params.loadCliContext(args);
ValidatorCli cli = mockValidatorCliWithService(cliContext);
cli.readParamsAndExecuteTask(cliContext, args);
Mockito.verify(validationService).determineVersion(same(cliContext));
Mockito.verify(validationService).questionnaireExtract(same(cliContext), same(validationEngine));
}
@Test
public void defaultTest() throws Exception {
final String[] args = new String[]{"dummyFile.json"};

View File

@ -1,27 +0,0 @@
package org.hl7.fhir.validation.tests;
import org.hl7.fhir.r4.context.SimpleWorkerContext;
import org.hl7.fhir.r5.test.utils.TestingUtilities;
import org.hl7.fhir.utilities.SystemExitManager;
import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.filesystem.ManagedFileAccess;
import org.hl7.fhir.utilities.settings.FhirSettings;
import org.hl7.fhir.validation.ValidatorCli;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@Disabled
public class TestScriptQuestionnaireTests {
private SimpleWorkerContext context;
@Test
public void test() throws Exception {
String fn = TestingUtilities.tempFile("testScriptQuestionnaire", "questionnaire.json");
SystemExitManager.setNoExit(true);
ValidatorCli.main(new String[] {"-ig", "hl7.fhir.us.physical-activity#dev", "-script-questionnaire", "-outputCanonical",
"http://hl7.org/fhir/uv/physical-activity/Questionnaire/script-generation", "-version", "4.0", "-output", fn});
// Todo: Compare against known good file
fn = fn;
}
}