Refactor R4 infrastructure to use the new common

TerminologyServiceOptions, and tweak the validation of enableWhen to
handle a few edge cases correctly.
This commit is contained in:
James Agnew 2019-08-06 18:27:45 -04:00
parent 38a0877996
commit c1728a481d
15 changed files with 252 additions and 414 deletions

View File

@ -37,9 +37,9 @@ package org.hl7.fhir.dstu3.model;
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

View File

@ -84,7 +84,6 @@ import org.hl7.fhir.r4.model.UriType;
import org.hl7.fhir.r4.model.ValueSet;
import org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionComponent;
import org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionContainsComponent;
import org.hl7.fhir.r4.terminologies.TerminologyServiceOptions;
import org.hl7.fhir.r4.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
import org.hl7.fhir.r4.utils.NarrativeGenerator;
import org.hl7.fhir.r4.utils.ToolingExtensions;
@ -92,6 +91,7 @@ import org.hl7.fhir.r4.utils.TranslatingUtilities;
import org.hl7.fhir.r4.utils.formats.CSVWriter;
import org.hl7.fhir.r4.utils.formats.XLSXWriter;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
import org.hl7.fhir.utilities.TerminologyServiceOptions;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.utilities.validation.ValidationMessage.Source;

View File

@ -20,16 +20,7 @@ package org.hl7.fhir.r4.context;
* #L%
*/
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.google.gson.JsonObject;
import org.apache.commons.lang3.StringUtils;
import org.fhir.ucum.UcumService;
import org.hl7.fhir.exceptions.DefinitionException;
@ -37,51 +28,34 @@ import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.TerminologyServiceException;
import org.hl7.fhir.r4.conformance.ProfileUtilities;
import org.hl7.fhir.r4.context.TerminologyCache.CacheToken;
import org.hl7.fhir.r4.model.BooleanType;
import org.hl7.fhir.r4.model.CapabilityStatement;
import org.hl7.fhir.r4.model.CodeSystem;
import org.hl7.fhir.r4.model.*;
import org.hl7.fhir.r4.model.CodeSystem.CodeSystemContentMode;
import org.hl7.fhir.r4.model.CodeSystem.ConceptDefinitionComponent;
import org.hl7.fhir.r4.model.CodeableConcept;
import org.hl7.fhir.r4.model.Coding;
import org.hl7.fhir.r4.model.ConceptMap;
import org.hl7.fhir.r4.model.Constants;
import org.hl7.fhir.r4.model.ElementDefinition.ElementDefinitionBindingComponent;
import org.hl7.fhir.r4.model.ImplementationGuide;
import org.hl7.fhir.r4.model.MetadataResource;
import org.hl7.fhir.r4.model.NamingSystem;
import org.hl7.fhir.r4.model.NamingSystem.NamingSystemIdentifierType;
import org.hl7.fhir.r4.model.NamingSystem.NamingSystemUniqueIdComponent;
import org.hl7.fhir.r4.model.OperationDefinition;
import org.hl7.fhir.r4.model.Parameters;
import org.hl7.fhir.r4.model.Parameters.ParametersParameterComponent;
import org.hl7.fhir.r4.model.PlanDefinition;
import org.hl7.fhir.r4.model.Questionnaire;
import org.hl7.fhir.r4.model.Reference;
import org.hl7.fhir.r4.model.Resource;
import org.hl7.fhir.r4.model.SearchParameter;
import org.hl7.fhir.r4.model.StringType;
import org.hl7.fhir.r4.model.StructureDefinition;
import org.hl7.fhir.r4.model.StructureMap;
import org.hl7.fhir.r4.model.TerminologyCapabilities;
import org.hl7.fhir.r4.model.TerminologyCapabilities.TerminologyCapabilitiesCodeSystemComponent;
import org.hl7.fhir.r4.model.ValueSet;
import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent;
import org.hl7.fhir.r4.model.ValueSet.ValueSetComposeComponent;
import org.hl7.fhir.r4.terminologies.TerminologyClient;
import org.hl7.fhir.r4.terminologies.TerminologyServiceOptions;
import org.hl7.fhir.r4.terminologies.ValueSetCheckerSimple;
import org.hl7.fhir.r4.terminologies.ValueSetExpander.TerminologyServiceErrorClass;
import org.hl7.fhir.r4.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
import org.hl7.fhir.r4.terminologies.ValueSetExpanderSimple;
import org.hl7.fhir.r4.utils.ToolingExtensions;
import org.hl7.fhir.utilities.OIDUtils;
import org.hl7.fhir.utilities.TerminologyServiceOptions;
import org.hl7.fhir.utilities.TranslationServices;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
import com.google.gson.JsonObject;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.*;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
public abstract class BaseWorkerContext implements IWorkerContext {
@ -527,7 +501,7 @@ public abstract class BaseWorkerContext implements IWorkerContext {
if (implySystem)
pIn.addParameter().setName("implySystem").setValue(new BooleanType(true));
if (options != null)
options.updateParameters(pIn);
updateParameters(options, pIn);
res = validateOnServer(vs, pIn);
} catch (Exception e) {
res = new ValidationResult(IssueSeverity.ERROR, e.getMessage() == null ? e.getClass().getName() : e.getMessage()).setTxLink(txLog == null ? null : txLog.getLastId());
@ -537,6 +511,12 @@ public abstract class BaseWorkerContext implements IWorkerContext {
return res;
}
public void updateParameters(TerminologyServiceOptions options, Parameters pIn) {
if (isNotBlank(options.getLanguage())) {
pIn.addParameter("displayLanguage", options.getLanguage());
}
}
@Override
public ValidationResult validateCode(TerminologyServiceOptions options, CodeableConcept code, ValueSet vs) {
CacheToken cacheToken = txCache.generateValidationToken(options, code, vs);
@ -561,7 +541,7 @@ public abstract class BaseWorkerContext implements IWorkerContext {
Parameters pIn = new Parameters();
pIn.addParameter().setName("codeableConcept").setValue(code);
if (options != null)
options.updateParameters(pIn);
updateParameters(options, pIn);
res = validateOnServer(vs, pIn);
} catch (Exception e) {
res = new ValidationResult(IssueSeverity.ERROR, e.getMessage() == null ? e.getClass().getName() : e.getMessage()).setTxLink(txLog.getLastId());

View File

@ -44,11 +44,11 @@ import org.hl7.fhir.r4.model.StructureDefinition;
import org.hl7.fhir.r4.model.StructureMap;
import org.hl7.fhir.r4.model.ValueSet;
import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent;
import org.hl7.fhir.r4.terminologies.TerminologyServiceOptions;
import org.hl7.fhir.r4.terminologies.ValueSetExpander.TerminologyServiceErrorClass;
import org.hl7.fhir.r4.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
import org.hl7.fhir.r4.utils.INarrativeGenerator;
import org.hl7.fhir.r4.utils.IResourceValidator;
import org.hl7.fhir.utilities.TerminologyServiceOptions;
import org.hl7.fhir.utilities.TranslationServices;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
@ -160,11 +160,6 @@ public interface IWorkerContext {
* It's an error if the second form doesn't agree with class_. It's an
* error if class_ is null for the last form
*
* @param resource
* @param Reference
* @return
* @throws FHIRException
* @throws Exception
*/
public <T extends Resource> T fetchResource(Class<T> class_, String uri);
public <T extends Resource> T fetchResourceWithException(Class<T> class_, String uri) throws FHIRException;
@ -267,7 +262,6 @@ public interface IWorkerContext {
/**
* ValueSet Expansion - see $expand, but resolves the binding first
*
* @param source
* @return
* @throws FHIRException
*/

View File

@ -43,10 +43,10 @@ import org.hl7.fhir.r4.model.ValueSet;
import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent;
import org.hl7.fhir.r4.model.ValueSet.ConceptSetFilterComponent;
import org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionContainsComponent;
import org.hl7.fhir.r4.terminologies.TerminologyServiceOptions;
import org.hl7.fhir.r4.terminologies.ValueSetExpander.TerminologyServiceErrorClass;
import org.hl7.fhir.r4.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
import org.hl7.fhir.utilities.TerminologyServiceOptions;
import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;

View File

@ -1,57 +0,0 @@
package org.hl7.fhir.r4.terminologies;
/*-
* #%L
* org.hl7.fhir.r4
* %%
* Copyright (C) 2014 - 2019 Health Level 7
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import org.fhir.ucum.Utilities;
import org.hl7.fhir.r4.model.Parameters;
public class TerminologyServiceOptions {
private String language;
public TerminologyServiceOptions() {
super();
}
public TerminologyServiceOptions(String language) {
super();
this.language = language;
}
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
public String toJson() {
return "\"lang\":\""+language+"\"";
}
public void updateParameters(Parameters pIn) {
if (!Utilities.noString(language))
pIn.addParameter("displayLanguage", language);
}
}

View File

@ -21,31 +21,23 @@ package org.hl7.fhir.r4.terminologies;
*/
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r4.context.IWorkerContext;
import org.hl7.fhir.r4.context.IWorkerContext.ValidationResult;
import org.hl7.fhir.r4.model.*;
import org.hl7.fhir.r4.model.CodeSystem.CodeSystemContentMode;
import org.hl7.fhir.r4.model.CodeSystem.ConceptDefinitionComponent;
import org.hl7.fhir.r4.model.CodeSystem.ConceptDefinitionDesignationComponent;
import org.hl7.fhir.r4.model.ValueSet.*;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
import org.hl7.fhir.utilities.TerminologyServiceOptions;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r4.context.IWorkerContext;
import org.hl7.fhir.r4.context.IWorkerContext.ValidationResult;
import org.hl7.fhir.r4.model.CanonicalType;
import org.hl7.fhir.r4.model.CodeSystem;
import org.hl7.fhir.r4.model.CodeSystem.CodeSystemContentMode;
import org.hl7.fhir.r4.model.CodeSystem.ConceptDefinitionComponent;
import org.hl7.fhir.r4.model.CodeSystem.ConceptDefinitionDesignationComponent;
import org.hl7.fhir.r4.model.CodeableConcept;
import org.hl7.fhir.r4.model.Coding;
import org.hl7.fhir.r4.model.UriType;
import org.hl7.fhir.r4.model.ValueSet;
import org.hl7.fhir.r4.model.ValueSet.ConceptReferenceComponent;
import org.hl7.fhir.r4.model.ValueSet.ConceptReferenceDesignationComponent;
import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent;
import org.hl7.fhir.r4.model.ValueSet.ConceptSetFilterComponent;
import org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionContainsComponent;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
public class ValueSetCheckerSimple implements ValueSetChecker {
private ValueSet valueset;

View File

@ -17,9 +17,9 @@ import org.hl7.fhir.r4.model.ExpressionNode.*;
import org.hl7.fhir.r4.model.StructureDefinition.StructureDefinitionKind;
import org.hl7.fhir.r4.model.StructureDefinition.TypeDerivationRule;
import org.hl7.fhir.r4.model.TypeDetails.ProfiledType;
import org.hl7.fhir.r4.terminologies.TerminologyServiceOptions;
import org.hl7.fhir.r4.utils.FHIRLexer.FHIRLexerException;
import org.hl7.fhir.r4.utils.FHIRPathEngine.IEvaluationContext.FunctionDetails;
import org.hl7.fhir.utilities.TerminologyServiceOptions;
import org.hl7.fhir.utilities.Utilities;
import java.math.BigDecimal;

View File

@ -21,10 +21,65 @@ package org.hl7.fhir.r4.utils;
*/
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.commons.lang3.NotImplementedException;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.exceptions.TerminologyServiceException;
import org.hl7.fhir.r4.conformance.ProfileUtilities;
import org.hl7.fhir.r4.conformance.ProfileUtilities.ProfileKnowledgeProvider;
import org.hl7.fhir.r4.context.IWorkerContext;
import org.hl7.fhir.r4.context.IWorkerContext.ValidationResult;
import org.hl7.fhir.r4.formats.FormatUtilities;
import org.hl7.fhir.r4.formats.IParser.OutputStyle;
import org.hl7.fhir.r4.formats.XmlParser;
import org.hl7.fhir.r4.model.*;
import org.hl7.fhir.r4.model.Bundle.*;
import org.hl7.fhir.r4.model.CapabilityStatement.*;
import org.hl7.fhir.r4.model.CodeSystem.*;
import org.hl7.fhir.r4.model.CompartmentDefinition.CompartmentDefinitionResourceComponent;
import org.hl7.fhir.r4.model.Composition.SectionComponent;
import org.hl7.fhir.r4.model.ConceptMap.ConceptMapGroupComponent;
import org.hl7.fhir.r4.model.ConceptMap.OtherElementComponent;
import org.hl7.fhir.r4.model.ConceptMap.SourceElementComponent;
import org.hl7.fhir.r4.model.ConceptMap.TargetElementComponent;
import org.hl7.fhir.r4.model.Enumeration;
import org.hl7.fhir.r4.model.ContactPoint.ContactPointSystem;
import org.hl7.fhir.r4.model.Enumerations.ConceptMapEquivalence;
import org.hl7.fhir.r4.model.HumanName.NameUse;
import org.hl7.fhir.r4.model.Narrative.NarrativeStatus;
import org.hl7.fhir.r4.model.OperationDefinition.OperationDefinitionParameterComponent;
import org.hl7.fhir.r4.model.OperationOutcome.IssueSeverity;
import org.hl7.fhir.r4.model.OperationOutcome.OperationOutcomeIssueComponent;
import org.hl7.fhir.r4.model.StructureDefinition.StructureDefinitionKind;
import org.hl7.fhir.r4.model.Timing.EventTiming;
import org.hl7.fhir.r4.model.Timing.TimingRepeatComponent;
import org.hl7.fhir.r4.model.Timing.UnitsOfTime;
import org.hl7.fhir.r4.model.ValueSet.FilterOperator;
import org.hl7.fhir.r4.model.ValueSet.*;
import org.hl7.fhir.r4.terminologies.CodeSystemUtilities;
import org.hl7.fhir.r4.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
import org.hl7.fhir.r4.utils.FHIRPathEngine.IEvaluationContext;
import org.hl7.fhir.r4.utils.LiquidEngine.LiquidDocument;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
import org.hl7.fhir.utilities.MarkDownProcessor;
import org.hl7.fhir.utilities.MarkDownProcessor.Dialect;
import org.hl7.fhir.utilities.TerminologyServiceOptions;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.xhtml.NodeType;
import org.hl7.fhir.utilities.xhtml.XhtmlComposer;
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
import org.hl7.fhir.utilities.xhtml.XhtmlParser;
import org.hl7.fhir.utilities.xml.XMLUtil;
import org.hl7.fhir.utilities.xml.XmlGenerator;
import org.w3c.dom.Element;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
/*
Copyright (c) 2011+, HL7, Inc
@ -55,143 +110,6 @@ Copyright (c) 2011+, HL7, Inc
*/
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.LinkedTransferQueue;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.commons.lang3.NotImplementedException;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.exceptions.TerminologyServiceException;
import org.hl7.fhir.r4.conformance.ProfileUtilities;
import org.hl7.fhir.r4.conformance.ProfileUtilities.ProfileKnowledgeProvider;
import org.hl7.fhir.r4.context.IWorkerContext;
import org.hl7.fhir.r4.context.IWorkerContext.ValidationResult;
import org.hl7.fhir.r4.formats.FormatUtilities;
import org.hl7.fhir.r4.formats.IParser.OutputStyle;
import org.hl7.fhir.r4.formats.XmlParser;
import org.hl7.fhir.r4.model.Address;
import org.hl7.fhir.r4.model.Annotation;
import org.hl7.fhir.r4.model.Attachment;
import org.hl7.fhir.r4.model.Base;
import org.hl7.fhir.r4.model.Base64BinaryType;
import org.hl7.fhir.r4.model.BooleanType;
import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent;
import org.hl7.fhir.r4.model.Bundle.BundleEntryRequestComponent;
import org.hl7.fhir.r4.model.Bundle.BundleEntryResponseComponent;
import org.hl7.fhir.r4.model.Bundle.BundleEntrySearchComponent;
import org.hl7.fhir.r4.model.Bundle.BundleType;
import org.hl7.fhir.r4.model.CapabilityStatement;
import org.hl7.fhir.r4.model.CapabilityStatement.CapabilityStatementRestComponent;
import org.hl7.fhir.r4.model.CapabilityStatement.CapabilityStatementRestResourceComponent;
import org.hl7.fhir.r4.model.CapabilityStatement.ResourceInteractionComponent;
import org.hl7.fhir.r4.model.CapabilityStatement.SystemInteractionComponent;
import org.hl7.fhir.r4.model.CapabilityStatement.SystemRestfulInteraction;
import org.hl7.fhir.r4.model.CapabilityStatement.TypeRestfulInteraction;
import org.hl7.fhir.r4.model.CodeSystem;
import org.hl7.fhir.r4.model.CodeSystem.CodeSystemContentMode;
import org.hl7.fhir.r4.model.CodeSystem.CodeSystemFilterComponent;
import org.hl7.fhir.r4.model.CodeSystem.ConceptDefinitionComponent;
import org.hl7.fhir.r4.model.CodeSystem.ConceptDefinitionDesignationComponent;
import org.hl7.fhir.r4.model.CodeSystem.PropertyComponent;
import org.hl7.fhir.r4.model.CodeType;
import org.hl7.fhir.r4.model.CodeableConcept;
import org.hl7.fhir.r4.model.Coding;
import org.hl7.fhir.r4.model.CompartmentDefinition;
import org.hl7.fhir.r4.model.CompartmentDefinition.CompartmentDefinitionResourceComponent;
import org.hl7.fhir.r4.model.Composition;
import org.hl7.fhir.r4.model.Composition.SectionComponent;
import org.hl7.fhir.r4.model.ConceptMap;
import org.hl7.fhir.r4.model.ConceptMap.ConceptMapGroupComponent;
import org.hl7.fhir.r4.model.ConceptMap.OtherElementComponent;
import org.hl7.fhir.r4.model.ConceptMap.SourceElementComponent;
import org.hl7.fhir.r4.model.ConceptMap.TargetElementComponent;
import org.hl7.fhir.r4.model.ContactDetail;
import org.hl7.fhir.r4.model.ContactPoint;
import org.hl7.fhir.r4.model.ContactPoint.ContactPointSystem;
import org.hl7.fhir.r4.model.DateTimeType;
import org.hl7.fhir.r4.model.DiagnosticReport;
import org.hl7.fhir.r4.model.DomainResource;
import org.hl7.fhir.r4.model.Dosage;
import org.hl7.fhir.r4.model.ElementDefinition;
import org.hl7.fhir.r4.model.Enumeration;
import org.hl7.fhir.r4.model.Enumerations.ConceptMapEquivalence;
import org.hl7.fhir.r4.model.Extension;
import org.hl7.fhir.r4.model.ExtensionHelper;
import org.hl7.fhir.r4.model.HumanName;
import org.hl7.fhir.r4.model.HumanName.NameUse;
import org.hl7.fhir.r4.model.IdType;
import org.hl7.fhir.r4.model.Identifier;
import org.hl7.fhir.r4.model.ImplementationGuide;
import org.hl7.fhir.r4.model.InstantType;
import org.hl7.fhir.r4.model.Meta;
import org.hl7.fhir.r4.model.MetadataResource;
import org.hl7.fhir.r4.model.Narrative;
import org.hl7.fhir.r4.model.Narrative.NarrativeStatus;
import org.hl7.fhir.r4.model.OperationDefinition;
import org.hl7.fhir.r4.model.OperationDefinition.OperationDefinitionParameterComponent;
import org.hl7.fhir.r4.model.OperationOutcome;
import org.hl7.fhir.r4.model.OperationOutcome.IssueSeverity;
import org.hl7.fhir.r4.model.OperationOutcome.OperationOutcomeIssueComponent;
import org.hl7.fhir.r4.model.Period;
import org.hl7.fhir.r4.model.PrimitiveType;
import org.hl7.fhir.r4.model.Property;
import org.hl7.fhir.r4.model.Quantity;
import org.hl7.fhir.r4.model.Questionnaire;
import org.hl7.fhir.r4.model.Range;
import org.hl7.fhir.r4.model.Ratio;
import org.hl7.fhir.r4.model.Reference;
import org.hl7.fhir.r4.model.RelatedArtifact;
import org.hl7.fhir.r4.model.Resource;
import org.hl7.fhir.r4.model.SampledData;
import org.hl7.fhir.r4.model.Signature;
import org.hl7.fhir.r4.model.StringType;
import org.hl7.fhir.r4.model.StructureDefinition;
import org.hl7.fhir.r4.model.StructureDefinition.StructureDefinitionKind;
import org.hl7.fhir.r4.model.Timing;
import org.hl7.fhir.r4.model.Timing.EventTiming;
import org.hl7.fhir.r4.model.Timing.TimingRepeatComponent;
import org.hl7.fhir.r4.model.Timing.UnitsOfTime;
import org.hl7.fhir.r4.model.Type;
import org.hl7.fhir.r4.model.UriType;
import org.hl7.fhir.r4.model.UsageContext;
import org.hl7.fhir.r4.model.ValueSet;
import org.hl7.fhir.r4.model.ValueSet.ConceptReferenceComponent;
import org.hl7.fhir.r4.model.ValueSet.ConceptReferenceDesignationComponent;
import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent;
import org.hl7.fhir.r4.model.ValueSet.ConceptSetFilterComponent;
import org.hl7.fhir.r4.model.ValueSet.FilterOperator;
import org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionComponent;
import org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionContainsComponent;
import org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionParameterComponent;
import org.hl7.fhir.r4.terminologies.CodeSystemUtilities;
import org.hl7.fhir.r4.terminologies.TerminologyServiceOptions;
import org.hl7.fhir.r4.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
import org.hl7.fhir.r4.utils.FHIRPathEngine.IEvaluationContext;
import org.hl7.fhir.r4.utils.LiquidEngine.LiquidDocument;
import org.hl7.fhir.r4.utils.NarrativeGenerator.ILiquidTemplateProvider;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
import org.hl7.fhir.utilities.MarkDownProcessor;
import org.hl7.fhir.utilities.MarkDownProcessor.Dialect;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.xhtml.NodeType;
import org.hl7.fhir.utilities.xhtml.XhtmlComposer;
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
import org.hl7.fhir.utilities.xhtml.XhtmlParser;
import org.hl7.fhir.utilities.xml.XMLUtil;
import org.hl7.fhir.utilities.xml.XmlGenerator;
import org.w3c.dom.Element;
public class NarrativeGenerator implements INarrativeGenerator {
public interface ILiquidTemplateProvider {
@ -201,7 +119,7 @@ public class NarrativeGenerator implements INarrativeGenerator {
}
public interface ITypeParser {
Base parseType(String xml, String type) throws FHIRFormatError, IOException, FHIRException ;
Base parseType(String xml, String type) throws IOException, FHIRException ;
}
public class ConceptMapRenderInstructions {
@ -389,29 +307,29 @@ public class NarrativeGenerator implements INarrativeGenerator {
}
private interface PropertyWrapper {
public String getName();
public boolean hasValues();
public List<BaseWrapper> getValues();
public String getTypeCode();
public String getDefinition();
public int getMinCardinality();
public int getMaxCardinality();
public StructureDefinition getStructure();
public BaseWrapper value();
String getName();
boolean hasValues();
List<BaseWrapper> getValues();
String getTypeCode();
String getDefinition();
int getMinCardinality();
int getMaxCardinality();
StructureDefinition getStructure();
BaseWrapper value();
}
private interface ResourceWrapper {
public List<ResourceWrapper> getContained();
public String getId();
public XhtmlNode getNarrative() throws FHIRFormatError, IOException, FHIRException;
public String getName();
public List<PropertyWrapper> children();
List<ResourceWrapper> getContained();
String getId();
XhtmlNode getNarrative() throws IOException, FHIRException;
String getName();
List<PropertyWrapper> children();
}
private interface BaseWrapper {
public Base getBase() throws UnsupportedEncodingException, IOException, FHIRException;
public List<PropertyWrapper> children();
public PropertyWrapper getChildByName(String tail);
Base getBase() throws IOException, FHIRException;
List<PropertyWrapper> children();
PropertyWrapper getChildByName(String tail);
}
private class BaseWrapperElement implements BaseWrapper {
@ -430,7 +348,7 @@ public class NarrativeGenerator implements INarrativeGenerator {
}
@Override
public Base getBase() throws UnsupportedEncodingException, IOException, FHIRException {
public Base getBase() throws IOException, FHIRException {
if (type == null || type.equals("Resource") || type.equals("BackboneElement") || type.equals("Element"))
return null;
@ -578,7 +496,7 @@ public class NarrativeGenerator implements INarrativeGenerator {
}
@Override
public Base getBase() throws UnsupportedEncodingException, IOException, FHIRException {
public Base getBase() throws IOException, FHIRException {
if (type == null || type.equals("Resource") || type.equals("BackboneElement") || type.equals("Element"))
return null;
@ -648,7 +566,7 @@ public class NarrativeGenerator implements INarrativeGenerator {
}
@Override
public XhtmlNode getNarrative() throws FHIRFormatError, IOException, FHIRException {
public XhtmlNode getNarrative() throws IOException, FHIRException {
org.hl7.fhir.r4.elementmodel.Element txt = wrapped.getNamedChild("text");
if (txt == null)
return null;
@ -781,7 +699,7 @@ public class NarrativeGenerator implements INarrativeGenerator {
}
@Override
public XhtmlNode getNarrative() throws FHIRFormatError, IOException, FHIRException {
public XhtmlNode getNarrative() throws IOException, FHIRException {
Element txt = XMLUtil.getNamedChild(wrapped, "text");
if (txt == null)
return null;
@ -1140,7 +1058,7 @@ public class NarrativeGenerator implements INarrativeGenerator {
return b;
}
private void generateByProfile(Element eres, StructureDefinition profile, Element ee, List<ElementDefinition> allElements, ElementDefinition defn, List<ElementDefinition> children, XhtmlNode x, String path, boolean showCodeDetails) throws FHIRException, UnsupportedEncodingException, IOException {
private void generateByProfile(Element eres, StructureDefinition profile, Element ee, List<ElementDefinition> allElements, ElementDefinition defn, List<ElementDefinition> children, XhtmlNode x, String path, boolean showCodeDetails) throws FHIRException, IOException {
ResourceWrapperElement resw = new ResourceWrapperElement(eres, profile);
BaseWrapperElement base = new BaseWrapperElement(ee, null, profile, profile.getSnapshot().getElement().get(0));
@ -1148,11 +1066,11 @@ public class NarrativeGenerator implements INarrativeGenerator {
}
private void generateByProfile(Resource res, StructureDefinition profile, Base e, List<ElementDefinition> allElements, ElementDefinition defn, List<ElementDefinition> children, XhtmlNode x, String path, boolean showCodeDetails, ResourceContext rc) throws FHIRException, UnsupportedEncodingException, IOException {
private void generateByProfile(Resource res, StructureDefinition profile, Base e, List<ElementDefinition> allElements, ElementDefinition defn, List<ElementDefinition> children, XhtmlNode x, String path, boolean showCodeDetails, ResourceContext rc) throws FHIRException, IOException {
generateByProfile(new ResourceWrapperDirect(res), profile, new BaseWrapperDirect(e), allElements, defn, children, x, path, showCodeDetails, 0, rc);
}
private void generateByProfile(ResourceWrapper res, StructureDefinition profile, BaseWrapper e, List<ElementDefinition> allElements, ElementDefinition defn, List<ElementDefinition> children, XhtmlNode x, String path, boolean showCodeDetails, int indent, ResourceContext rc) throws FHIRException, UnsupportedEncodingException, IOException {
private void generateByProfile(ResourceWrapper res, StructureDefinition profile, BaseWrapper e, List<ElementDefinition> allElements, ElementDefinition defn, List<ElementDefinition> children, XhtmlNode x, String path, boolean showCodeDetails, int indent, ResourceContext rc) throws FHIRException, IOException {
if (children.isEmpty()) {
renderLeaf(res, e, defn, x, false, showCodeDetails, readDisplayHints(defn), path, indent, rc);
} else {
@ -1224,7 +1142,7 @@ public class NarrativeGenerator implements INarrativeGenerator {
i++;
if (i > 6)
i = 6;
return "h"+Integer.toString(i);
return "h"+ i;
}
private void filterGrandChildren(List<ElementDefinition> grandChildren, String string, PropertyWrapper prop) {
@ -1242,7 +1160,7 @@ public class NarrativeGenerator implements INarrativeGenerator {
grandChildren.removeAll(toRemove);
}
private List<PropertyWrapper> splitExtensions(StructureDefinition profile, List<PropertyWrapper> children) throws UnsupportedEncodingException, IOException, FHIRException {
private List<PropertyWrapper> splitExtensions(StructureDefinition profile, List<PropertyWrapper> children) throws IOException, FHIRException {
List<PropertyWrapper> results = new ArrayList<PropertyWrapper>();
Map<String, PropertyWrapper> map = new HashMap<String, PropertyWrapper>();
for (PropertyWrapper p : children)
@ -1278,7 +1196,7 @@ public class NarrativeGenerator implements INarrativeGenerator {
}
@SuppressWarnings("rawtypes")
private boolean isDefaultValue(Map<String, String> displayHints, List<BaseWrapper> list) throws UnsupportedEncodingException, IOException, FHIRException {
private boolean isDefaultValue(Map<String, String> displayHints, List<BaseWrapper> list) throws IOException, FHIRException {
if (list.size() != 1)
return false;
if (list.get(0).getBase() instanceof PrimitiveType)
@ -1289,9 +1207,7 @@ public class NarrativeGenerator implements INarrativeGenerator {
private boolean isDefault(Map<String, String> displayHints, PrimitiveType primitiveType) {
String v = primitiveType.asStringValue();
if (!Utilities.noString(v) && displayHints.containsKey("default") && v.equals(displayHints.get("default")))
return true;
return false;
return !Utilities.noString(v) && displayHints.containsKey("default") && v.equals(displayHints.get("default"));
}
private boolean exemptFromRendering(ElementDefinition child) {
@ -1299,16 +1215,13 @@ public class NarrativeGenerator implements INarrativeGenerator {
return false;
if ("Composition.subject".equals(child.getPath()))
return true;
if ("Composition.section".equals(child.getPath()))
return true;
return false;
return "Composition.section".equals(child.getPath());
}
private boolean renderAsList(ElementDefinition child) {
if (child.getType().size() == 1) {
String t = child.getType().get(0).getCode();
if (t.equals("Address") || t.equals("Reference"))
return true;
return t.equals("Address") || t.equals("Reference");
}
return false;
}
@ -1318,7 +1231,7 @@ public class NarrativeGenerator implements INarrativeGenerator {
tr.td().b().addText(Utilities.capitalize(tail(e.getPath())));
}
private void addColumnValues(ResourceWrapper res, XhtmlNode tr, List<ElementDefinition> grandChildren, BaseWrapper v, boolean showCodeDetails, Map<String, String> displayHints, String path, int indent, ResourceContext rc) throws FHIRException, UnsupportedEncodingException, IOException {
private void addColumnValues(ResourceWrapper res, XhtmlNode tr, List<ElementDefinition> grandChildren, BaseWrapper v, boolean showCodeDetails, Map<String, String> displayHints, String path, int indent, ResourceContext rc) throws FHIRException, IOException {
for (ElementDefinition e : grandChildren) {
PropertyWrapper p = v.getChildByName(e.getPath().substring(e.getPath().lastIndexOf(".")+1));
if (p == null || p.getValues().size() == 0 || p.getValues().get(0) == null)
@ -1361,9 +1274,7 @@ public class NarrativeGenerator implements INarrativeGenerator {
//we can tell if e is a primitive because it has types
if (e.getType().isEmpty())
return false;
if (e.getType().size() == 1 && isBase(e.getType().get(0).getCode()))
return false;
return true;
return e.getType().size() != 1 || !isBase(e.getType().get(0).getCode());
// return !e.getType().isEmpty()
}
@ -1380,7 +1291,7 @@ public class NarrativeGenerator implements INarrativeGenerator {
return null;
}
private void renderLeaf(ResourceWrapper res, BaseWrapper ew, ElementDefinition defn, XhtmlNode x, boolean title, boolean showCodeDetails, Map<String, String> displayHints, String path, int indent, ResourceContext rc) throws FHIRException, UnsupportedEncodingException, IOException {
private void renderLeaf(ResourceWrapper res, BaseWrapper ew, ElementDefinition defn, XhtmlNode x, boolean title, boolean showCodeDetails, Map<String, String> displayHints, String path, int indent, ResourceContext rc) throws FHIRException, IOException {
if (ew == null)
return;
@ -1486,7 +1397,7 @@ public class NarrativeGenerator implements INarrativeGenerator {
}
}
private boolean displayLeaf(ResourceWrapper res, BaseWrapper ew, ElementDefinition defn, XhtmlNode x, String name, boolean showCodeDetails, ResourceContext rc) throws FHIRException, UnsupportedEncodingException, IOException {
private boolean displayLeaf(ResourceWrapper res, BaseWrapper ew, ElementDefinition defn, XhtmlNode x, String name, boolean showCodeDetails, ResourceContext rc) throws FHIRException, IOException {
if (ew == null)
return false;
Base e = ew.getBase();
@ -1640,7 +1551,7 @@ public class NarrativeGenerator implements INarrativeGenerator {
return s + (!p.hasEnd() ? "(ongoing)" : p.getEndElement().toHumanDisplay());
}
private void generateResourceSummary(XhtmlNode x, ResourceWrapper res, boolean textAlready, boolean showCodeDetails, ResourceContext rc) throws FHIRException, UnsupportedEncodingException, IOException {
private void generateResourceSummary(XhtmlNode x, ResourceWrapper res, boolean textAlready, boolean showCodeDetails, ResourceContext rc) throws FHIRException, IOException {
if (!textAlready) {
XhtmlNode div = res.getNarrative();
if (div != null) {
@ -1687,8 +1598,7 @@ public class NarrativeGenerator implements INarrativeGenerator {
return true;
if (child.getType().size() == 1) {
String t = child.getType().get(0).getCode();
if (t.equals("Address") || t.equals("Contact") || t.equals("Reference") || t.equals("Uri") || t.equals("Url") || t.equals("Canonical"))
return false;
return !t.equals("Address") && !t.equals("Contact") && !t.equals("Reference") && !t.equals("Uri") && !t.equals("Url") && !t.equals("Canonical");
}
return true;
}
@ -2048,14 +1958,14 @@ public class NarrativeGenerator implements INarrativeGenerator {
if (rep.hasBoundsPeriod() && rep.getBoundsPeriod().hasStart())
b.append("Starting "+rep.getBoundsPeriod().getStartElement().toHumanDisplay());
if (rep.hasCount())
b.append("Count "+Integer.toString(rep.getCount())+" times");
b.append("Count "+ rep.getCount() +" times");
if (rep.hasDuration())
b.append("Duration "+rep.getDuration().toPlainString()+displayTimeUnits(rep.getPeriodUnit()));
if (rep.hasWhen()) {
String st = "";
if (rep.hasOffset()) {
st = Integer.toString(rep.getOffset())+"min ";
st = rep.getOffset() +"min ";
}
b.append("Do "+st);
for (Enumeration<EventTiming> wh : rep.getWhen())
@ -2067,7 +1977,7 @@ public class NarrativeGenerator implements INarrativeGenerator {
else {
st = Integer.toString(rep.getFrequency());
if (rep.hasFrequencyMax())
st = st + "-"+Integer.toString(rep.getFrequency());
st = st + "-"+ rep.getFrequency();
}
if (rep.hasPeriod()) {
st = st + " per "+rep.getPeriod().toPlainString();
@ -3046,7 +2956,7 @@ public class NarrativeGenerator implements INarrativeGenerator {
if (ToolingExtensions.EXT_TRANSLATION.equals(ext.getUrl())) {
String l = ToolingExtensions.readStringExtension(ext, "lang");
if (lang.equals(l))
d = ToolingExtensions.readStringExtension(ext, "content");;
d = ToolingExtensions.readStringExtension(ext, "content");
}
}
tr.td().addText(d == null ? "" : d);
@ -3130,9 +3040,7 @@ public class NarrativeGenerator implements INarrativeGenerator {
private boolean checkDoSystem(ValueSet vs, ValueSet src) {
if (src != null)
vs = src;
if (vs.hasCompose())
return true;
return false;
return vs.hasCompose();
}
private boolean IsNotFixedExpansion(ValueSet vs) {
@ -4118,7 +4026,7 @@ public class NarrativeGenerator implements INarrativeGenerator {
tr = tbl.tr();
tr.td().addText(p.getUse().toString());
tr.td().addText(path+p.getName());
tr.td().addText(Integer.toString(p.getMin())+".."+p.getMax());
tr.td().addText(p.getMin() +".."+p.getMax());
XhtmlNode td = tr.td();
StructureDefinition sd = context.fetchTypeDefinition(p.getType());
if (sd != null)
@ -4342,7 +4250,7 @@ public class NarrativeGenerator implements INarrativeGenerator {
for (SectionComponent section : sections) {
node.hr();
if (section.hasTitleElement())
node.addTag("h"+Integer.toString(level)).addText(section.getTitle());
node.addTag("h"+ level).addText(section.getTitle());
// else if (section.hasCode())
// node.addTag("h"+Integer.toString(level)).addText(displayCodeableConcept(section.getCode()));
@ -4611,7 +4519,7 @@ public class NarrativeGenerator implements INarrativeGenerator {
if (be.hasResource() && be.getResource().hasId())
root.an(be.getResource().getResourceType().name().toLowerCase() + "_" + be.getResource().getId());
root.hr();
root.para().addText("Entry "+Integer.toString(i)+(be.hasFullUrl() ? " - Full URL = " + be.getFullUrl() : ""));
root.para().addText("Entry "+ i +(be.hasFullUrl() ? " - Full URL = " + be.getFullUrl() : ""));
if (be.hasRequest())
renderRequest(root, be.getRequest());
if (be.hasSearch())

View File

@ -102,11 +102,11 @@ import org.hl7.fhir.r4.model.TypeDetails.ProfiledType;
import org.hl7.fhir.r4.model.UriType;
import org.hl7.fhir.r4.model.ValueSet;
import org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionContainsComponent;
import org.hl7.fhir.r4.terminologies.TerminologyServiceOptions;
import org.hl7.fhir.r4.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
import org.hl7.fhir.r4.utils.FHIRLexer.FHIRLexerException;
import org.hl7.fhir.r4.utils.FHIRPathEngine.IEvaluationContext;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
import org.hl7.fhir.utilities.TerminologyServiceOptions;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.utilities.xhtml.NodeType;
@ -120,7 +120,7 @@ import org.hl7.fhir.utilities.xhtml.XhtmlNode;
* getTargetType(map) - return the definition for the type to create to hand in
* transform(appInfo, source, map, target) - transform from source to target following the map
* analyse(appInfo, map) - generate profiles and other analysis artifacts for the targets of the transform
* map generateMapFromMappings(StructureDefinition) - build a mapping from a structure definition with loigcal mappings
* map generateMapFromMappings(StructureDefinition) - build a mapping from a structure definition with logical mappings
*
* @author Grahame Grieve
*
@ -223,7 +223,7 @@ public class StructureMapUtilities {
private ITransformerServices services;
private ProfileKnowledgeProvider pkp;
private Map<String, Integer> ids = new HashMap<String, Integer>();
private TerminologyServiceOptions terminologyServiceOptions = new TerminologyServiceOptions();
private TerminologyServiceOptions terminologyServiceOptions = new TerminologyServiceOptions();
public StructureMapUtilities(IWorkerContext worker, ITransformerServices services, ProfileKnowledgeProvider pkp) {
super();

View File

@ -48,7 +48,7 @@ public abstract class BaseResource extends Base implements IAnyResource, IElemen
@Override
public FhirVersionEnum getStructureFhirVersionEnum() {
return FhirVersionEnum.R4; // to: change to R5
return FhirVersionEnum.R5; // to: change to R5
}
@Override

View File

@ -2,7 +2,7 @@ package org.hl7.fhir.utilities;
/*-
* #%L
* org.hl7.fhir.r5
* org.hl7.fhir.utilities
* %%
* Copyright (C) 2014 - 2019 Health Level 7
* %%

View File

@ -120,8 +120,8 @@ import org.hl7.fhir.r4.utils.IResourceValidator;
import org.hl7.fhir.r4.utils.ToolingExtensions;
import org.hl7.fhir.r4.utils.ValidationProfileSet;
import org.hl7.fhir.r4.utils.ValidationProfileSet.ProfileRegistration;
import org.hl7.fhir.r4.terminologies.TerminologyServiceOptions;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
import org.hl7.fhir.utilities.TerminologyServiceOptions;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
@ -809,7 +809,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
if (ss) {
t = System.nanoTime();
ValidationResult s = context.validateCode(new TerminologyServiceOptions("en"), system, code, display);
txTime = txTime + (System.nanoTime() - t);
txTime += (System.nanoTime() - t);
if (s == null)
return true;
if (s.isOk()) {

View File

@ -296,6 +296,16 @@ public class EnableWhenEvaluator {
}
retVal.addAll(findOnItem(item, question));
}
// In case the question with the enableWhen is a direct child of the question with
// the answer that it depends on. There is an example of this in the
// "BO_ConsDrop" question in this test case:
// https://github.com/jamesagnew/hapi-fhir/blob/master/hapi-fhir-validation/src/test/resources/dstu3/fmc03-questionnaire.json
if (hasLinkId(focus, question)) {
List<Element> answers = extractAnswer(focus);
retVal.addAll(answers);
}
return retVal;
}

View File

@ -33,13 +33,11 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import java.util.UUID;
import org.apache.commons.lang3.NotImplementedException;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.r5.model.Reference;
import org.hl7.fhir.exceptions.*;
import org.hl7.fhir.convertors.VersionConvertorConstants;
import org.hl7.fhir.convertors.VersionConvertor_10_50;
import org.hl7.fhir.convertors.VersionConvertor_14_50;
@ -107,7 +105,6 @@ import org.hl7.fhir.r5.model.Questionnaire.QuestionnaireItemComponent;
import org.hl7.fhir.r5.model.Questionnaire.QuestionnaireItemType;
import org.hl7.fhir.r5.model.Range;
import org.hl7.fhir.r5.model.Ratio;
import org.hl7.fhir.r5.model.Reference;
import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.model.SampledData;
import org.hl7.fhir.r5.model.StringType;
@ -122,7 +119,6 @@ import org.hl7.fhir.r5.model.TypeDetails;
import org.hl7.fhir.r5.model.UriType;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent;
import org.hl7.fhir.r5.test.utils.TestingUtilities;
import org.hl7.fhir.r5.utils.FHIRLexer.FHIRLexerException;
import org.hl7.fhir.r5.utils.FHIRPathEngine;
import org.hl7.fhir.r5.utils.FHIRPathEngine.IEvaluationContext;
@ -130,7 +126,6 @@ import org.hl7.fhir.r5.utils.IResourceValidator;
import org.hl7.fhir.r5.utils.ToolingExtensions;
import org.hl7.fhir.r5.utils.ValidationProfileSet;
import org.hl7.fhir.r5.utils.ValidationProfileSet.ProfileRegistration;
import org.hl7.fhir.r5.utils.Version;
import org.hl7.fhir.r5.validation.EnableWhenEvaluator.QStack;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
import org.hl7.fhir.utilities.TerminologyServiceOptions;
@ -3170,7 +3165,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
return null;
}
private void validateQuestionannaireResponseItem(Questionnaire qsrc, QuestionnaireItemComponent qItem, List<ValidationMessage> errors, Element element, NodeStack stack, boolean inProgress, Element questionnaireResponseRoot, QStack qstack) {
private void validateQuestionnaireResponseItem(Questionnaire qsrc, QuestionnaireItemComponent qItem, List<ValidationMessage> errors, Element element, NodeStack stack, boolean inProgress, Element questionnaireResponseRoot, QStack qstack) {
String text = element.getNamedChildValue("text");
rule(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), Utilities.noString(text) || text.equals(qItem.getText()), "If text exists, it must match the questionnaire definition for linkId "+qItem.getLinkId());
@ -3191,74 +3186,76 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
for (Element answer : answers) {
NodeStack ns = stack.push(answer, -1, null, null);
switch (qItem.getType()) {
case GROUP:
rule(errors, IssueType.STRUCTURE, answer.line(), answer.col(), stack.getLiteralPath(), false, "Items of type group should not have answers");
break;
case DISPLAY: // nothing
break;
case BOOLEAN:
validateQuestionnaireResponseItemType(errors, answer, ns, "boolean");
break;
case DECIMAL:
validateQuestionnaireResponseItemType(errors, answer, ns, "decimal");
break;
case INTEGER:
validateQuestionnaireResponseItemType(errors, answer, ns, "integer");
break;
case DATE:
validateQuestionnaireResponseItemType(errors, answer, ns, "date");
break;
case DATETIME:
validateQuestionnaireResponseItemType(errors, answer, ns, "dateTime");
break;
case TIME:
validateQuestionnaireResponseItemType(errors, answer, ns, "time");
break;
case STRING:
validateQuestionnaireResponseItemType(errors, answer, ns, "string");
break;
case TEXT:
validateQuestionnaireResponseItemType(errors, answer, ns, "text");
break;
case URL:
validateQuestionnaireResponseItemType(errors, answer, ns, "uri");
break;
case ATTACHMENT:
validateQuestionnaireResponseItemType(errors, answer, ns, "Attachment");
break;
case REFERENCE:
validateQuestionnaireResponseItemType(errors, answer, ns, "Reference");
break;
case QUANTITY:
if ("Quantity".equals(validateQuestionnaireResponseItemType(errors, answer, ns, "Quantity")))
if (qItem.hasExtension("???"))
validateQuestionnaireResponseItemQuantity(errors, answer, ns);
break;
case CHOICE:
String itemType=validateQuestionnaireResponseItemType(errors, answer, ns, "Coding", "date", "time", "integer", "string");
if (itemType != null) {
if (itemType.equals("Coding")) validateAnswerCode(errors, answer, ns, qsrc, qItem, false);
else if (itemType.equals("date")) checkOption(errors, answer, ns, qsrc, qItem, "date");
else if (itemType.equals("time")) checkOption(errors, answer, ns, qsrc, qItem, "time");
else if (itemType.equals("integer")) checkOption(errors, answer, ns, qsrc, qItem, "integer");
else if (itemType.equals("string")) checkOption(errors, answer, ns, qsrc, qItem, "string");
}
break;
case OPENCHOICE:
itemType=validateQuestionnaireResponseItemType(errors, answer, ns, "Coding", "date", "time", "integer", "string");
if (itemType != null) {
if (itemType.equals("Coding")) validateAnswerCode(errors, answer, ns, qsrc, qItem, true);
else if (itemType.equals("date")) checkOption(errors, answer, ns, qsrc, qItem, "date");
else if (itemType.equals("time")) checkOption(errors, answer, ns, qsrc, qItem, "time");
else if (itemType.equals("integer")) checkOption(errors, answer, ns, qsrc, qItem, "integer");
else if (itemType.equals("string")) checkOption(errors, answer, ns, qsrc, qItem, "string", true);
}
break;
case QUESTION:
case NULL:
// no validation
break;
if (qItem.getType() != null) {
switch (qItem.getType()) {
case GROUP:
rule(errors, IssueType.STRUCTURE, answer.line(), answer.col(), stack.getLiteralPath(), false, "Items of type group should not have answers");
break;
case DISPLAY: // nothing
break;
case BOOLEAN:
validateQuestionnaireResponseItemType(errors, answer, ns, "boolean");
break;
case DECIMAL:
validateQuestionnaireResponseItemType(errors, answer, ns, "decimal");
break;
case INTEGER:
validateQuestionnaireResponseItemType(errors, answer, ns, "integer");
break;
case DATE:
validateQuestionnaireResponseItemType(errors, answer, ns, "date");
break;
case DATETIME:
validateQuestionnaireResponseItemType(errors, answer, ns, "dateTime");
break;
case TIME:
validateQuestionnaireResponseItemType(errors, answer, ns, "time");
break;
case STRING:
validateQuestionnaireResponseItemType(errors, answer, ns, "string");
break;
case TEXT:
validateQuestionnaireResponseItemType(errors, answer, ns, "text");
break;
case URL:
validateQuestionnaireResponseItemType(errors, answer, ns, "uri");
break;
case ATTACHMENT:
validateQuestionnaireResponseItemType(errors, answer, ns, "Attachment");
break;
case REFERENCE:
validateQuestionnaireResponseItemType(errors, answer, ns, "Reference");
break;
case QUANTITY:
if ("Quantity".equals(validateQuestionnaireResponseItemType(errors, answer, ns, "Quantity")))
if (qItem.hasExtension("???"))
validateQuestionnaireResponseItemQuantity(errors, answer, ns);
break;
case CHOICE:
String itemType = validateQuestionnaireResponseItemType(errors, answer, ns, "Coding", "date", "time", "integer", "string");
if (itemType != null) {
if (itemType.equals("Coding")) validateAnswerCode(errors, answer, ns, qsrc, qItem, false);
else if (itemType.equals("date")) checkOption(errors, answer, ns, qsrc, qItem, "date");
else if (itemType.equals("time")) checkOption(errors, answer, ns, qsrc, qItem, "time");
else if (itemType.equals("integer")) checkOption(errors, answer, ns, qsrc, qItem, "integer");
else if (itemType.equals("string")) checkOption(errors, answer, ns, qsrc, qItem, "string");
}
break;
case OPENCHOICE:
itemType = validateQuestionnaireResponseItemType(errors, answer, ns, "Coding", "date", "time", "integer", "string");
if (itemType != null) {
if (itemType.equals("Coding")) validateAnswerCode(errors, answer, ns, qsrc, qItem, true);
else if (itemType.equals("date")) checkOption(errors, answer, ns, qsrc, qItem, "date");
else if (itemType.equals("time")) checkOption(errors, answer, ns, qsrc, qItem, "time");
else if (itemType.equals("integer")) checkOption(errors, answer, ns, qsrc, qItem, "integer");
else if (itemType.equals("string")) checkOption(errors, answer, ns, qsrc, qItem, "string", true);
}
break;
case QUESTION:
case NULL:
// no validation
break;
}
}
validateQuestionannaireResponseItems(qsrc, qItem.getItem(), errors, answer, stack, inProgress, questionnaireResponseRoot, qstack);
}
@ -3277,13 +3274,13 @@ private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, L
return !answers.isEmpty() || !qItem.getRequired() || qItem.getType() == QuestionnaireItemType.GROUP;
}
private void validateQuestionannaireResponseItem(Questionnaire qsrc, QuestionnaireItemComponent qItem, List<ValidationMessage> errors, List<Element> elements, NodeStack stack, boolean inProgress, Element questionnaireResponseRoot, QStack qstack) {
private void validateQuestionnaireResponseItem(Questionnaire qsrc, QuestionnaireItemComponent qItem, List<ValidationMessage> errors, List<Element> elements, NodeStack stack, boolean inProgress, Element questionnaireResponseRoot, QStack qstack) {
if (elements.size() > 1)
rule(errors, IssueType.INVALID, elements.get(1).line(), elements.get(1).col(), stack.getLiteralPath(), qItem.getRepeats(), "Only one response item with this linkId allowed - " + qItem.getLinkId());
int i = 0;
for (Element element : elements) {
NodeStack ns = stack.push(element, i, null, null);
validateQuestionannaireResponseItem(qsrc, qItem, errors, element, ns, inProgress, questionnaireResponseRoot, qstack.push(qItem, element));
validateQuestionnaireResponseItem(qsrc, qItem, errors, element, ns, inProgress, questionnaireResponseRoot, qstack.push(qItem, element));
i++;
}
}
@ -3311,7 +3308,7 @@ private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, L
if (qItem != null) {
rule(errors, IssueType.STRUCTURE, item.line(), item.col(), stack.getLiteralPath(), index > -1, misplacedItemError(qItem));
NodeStack ns = stack.push(item, -1, null, null);
validateQuestionannaireResponseItem(qsrc, qItem, errors, item, ns, inProgress, questionnaireResponseRoot, qstack.push(qItem, item));
validateQuestionnaireResponseItem(qsrc, qItem, errors, item, ns, inProgress, questionnaireResponseRoot, qstack.push(qItem, item));
}
else
rule(errors, IssueType.NOTFOUND, item.line(), item.col(), stack.getLiteralPath(), index > -1, "LinkId \""+linkId+"\" not found in questionnaire");
@ -3320,22 +3317,25 @@ private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, L
{
rule(errors, IssueType.STRUCTURE, item.line(), item.col(), stack.getLiteralPath(), index >= lastIndex, "Structural Error: items are out of order");
lastIndex = index;
List<Element> mapItem = map.computeIfAbsent(linkId, key -> new ArrayList<>());
mapItem.add(item);
// If an item has a child called "linkId" but no child called "answer",
// we'll treat it as not existing for the purposes of enableWhen validation
if (item.hasChildren("answer") || item.hasChildren("item")) {
List<Element> mapItem = map.computeIfAbsent(linkId, key -> new ArrayList<>());
mapItem.add(item);
}
}
}
}
// ok, now we have a list of known items, grouped by linkId. We"ve made an error for anything out of order
// ok, now we have a list of known items, grouped by linkId. We've made an error for anything out of order
for (QuestionnaireItemComponent qItem : qItems) {
List<Element> mapItem = map.get(qItem.getLinkId());
validateQuestionannaireResponseItem(qsrc, errors, element, stack, inProgress, questionnaireResponseRoot, qItem, mapItem, qstack);
validateQuestionnaireResponseItem(qsrc, errors, element, stack, inProgress, questionnaireResponseRoot, qItem, mapItem, qstack);
}
}
public void validateQuestionannaireResponseItem(Questionnaire qsrc, List<ValidationMessage> errors, Element element, NodeStack stack, boolean inProgress, Element questionnaireResponseRoot, QuestionnaireItemComponent qItem, List<Element> mapItem, QStack qstack) {
public void validateQuestionnaireResponseItem(Questionnaire qsrc, List<ValidationMessage> errors, Element element, NodeStack stack, boolean inProgress, Element questionnaireResponseRoot, QuestionnaireItemComponent qItem, List<Element> mapItem, QStack qstack) {
boolean enabled = myEnableWhenEvaluator.isQuestionEnabled(qItem, qstack);
if (mapItem != null){
if (!enabled) {
@ -3346,13 +3346,24 @@ private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, L
i++;
}
}
validateQuestionannaireResponseItem(qsrc, qItem, errors, mapItem, stack, inProgress, questionnaireResponseRoot, qstack);
} else {
//item is missing, is the question enabled?
if (enabled && qItem.getRequired()) {
rule(errors, IssueType.REQUIRED, element.line(), element.col(), stack.getLiteralPath(), false, "No response found for required item with id = '"+qItem.getLinkId()+"'");
// Recursively validate child items
validateQuestionnaireResponseItem(qsrc, qItem, errors, mapItem, stack, inProgress, questionnaireResponseRoot, qstack);
} else {
// item is missing, is the question enabled?
if (enabled && qItem.getRequired()) {
String message = "No response found for required item with id = '" + qItem.getLinkId() + "'";
if (inProgress) {
warning(errors, IssueType.REQUIRED, element.line(), element.col(), stack.getLiteralPath(), false, message);
} else {
rule(errors, IssueType.REQUIRED, element.line(), element.col(), stack.getLiteralPath(), false, message);
}
}
}
}
private String misplacedItemError(QuestionnaireItemComponent qItem) {