Merge branch 'master' of https://github.com/hapifhir/org.hl7.fhir.core into ExampleScenarioRendering

This commit is contained in:
Lloyd McKenzie 2023-08-07 09:27:29 -06:00
commit 820a945807
62 changed files with 1755 additions and 243 deletions

View File

@ -0,0 +1,49 @@
#!/bin/bash
IFS=$'\n'
readarray -t whitelist < ./.github/workflows/license-check/license-whitelist.txt
readarray -t specialcases < <( grep -vE "^#" ./.github/workflows/license-check/license-special-cases.txt )
exitStatus=0
for specialcase in "${specialcases[@]}"
do
echo "Special case: " "$specialcase"
done
readarray -t thirdparty < <( tail -n +3 ./target/generated-sources/license/THIRD-PARTY.txt )
for thirdpartyentry in "${thirdparty[@]}"
do
allLicensesValid=true
# Remove leading spaces
thirdpartyentry="${thirdpartyentry#"${thirdpartyentry%%[![:space:]]*}"}"
echo "Evaluating Dependency: " "$thirdpartyentry"
if [[ $(echo "${specialcases[@]}" | fgrep -w $thirdpartyentry) ]]
then
echo " Ignoring: " "$thirdpartyentry"
else
licenses=($(echo $thirdpartyentry | awk -vRS=")" -vFS="(" '{print $2}'))
for (( i=0; i < ${#licenses[@]} - 1 ; i++ ))
do
#echo ${licenses[i]}
licenseToCheck=${licenses[i]}
if [[ $(echo "${whitelist[@]}" | fgrep -w $licenseToCheck) ]]
then
#do nothing bsh no-op
:
else
echo " Unknown license found: " $licenseToCheck
allLicensesValid=false
exitStatus=1
fi
done
fi
if $allLicensesValid
then
echo " All licenses OK"
else
echo " Possible license incompatibilities found"
fi
done
exit $exitStatus

View File

@ -0,0 +1,3 @@
(Unknown license) javaparser (com.google.code.javaparser:javaparser:1.0.11 - http://code.google.com/p/javaparser/)
# IGNORE ME
(Apache Software License 2.0) HAPI FHIR - Validation Resources (FHIR R4) (ca.uhn.hapi.fhir:hapi-fhir-validation-resources-r4:6.4.1 - https://hapifhir.io/hapi-deployable-pom/hapi-fhir-validation-resources-r4)

View File

@ -0,0 +1,25 @@
The Apache Software License, Version 2.0
Apache Software License, version 1.1
Apache Software License 2.0
The Apache License, Version 2.0
The Apache Software License, Version 2.0
MIT License
The MIT License
Apache Software License, version 1.1
Apache 2
Apache 2.0
Apache License 2.0
Eclipse Public License v2.0
BSD licence
The BSD License
BSD-Style License
BSD License 3
New BSD License
BSD 3 Clause
The JSON License
Eclipse Public License - v 1.0
Eclipse Public License v. 2.0
Eclipse Distribution License v. 1.0
Eclipse Distribution License - v 1.0
Unicode/ICU License
BSD 2-Clause License

30
.github/workflows/manual.yml vendored Normal file
View File

@ -0,0 +1,30 @@
# This is a basic workflow that is manually triggered
name: License Check
on:
workflow_dispatch:
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "greet"
check:
# The type of runner that the job will run on
runs-on: ubuntu-latest
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Collect module licenses
run: mvn clean install -DskipTests
- name: Collect module licenses
run: mvn license:add-third-party
- name: Aggregate licenses
run: mvn license:aggregate-add-third-party
- name: Set script permissions
run: chmod u+x .github/workflows/license-check/license-check.sh
- name: Run script
run: .github/workflows/license-check/license-check.sh
continue-on-error: true

View File

@ -1,9 +1,7 @@
## Validator Changes
* Fix invalid integer detection
* Improved invariant checking
* no changes
## Other code changes
* Update obligation handling code for split definitions
* Update ICF importer to handle grouping levels
* no changes

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>6.0.24-SNAPSHOT</version>
<version>6.0.26-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -0,0 +1,309 @@
package org.hl7.fhir.convertors.misc;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Date;
import java.util.Scanner;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r5.formats.IParser.OutputStyle;
import org.hl7.fhir.r5.formats.JsonParser;
import org.hl7.fhir.r5.model.CodeSystem;
import org.hl7.fhir.r5.model.BooleanType;
import org.hl7.fhir.r5.model.StringType;
import org.hl7.fhir.r5.model.CodeType;
import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent;
import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionDesignationComponent;
import org.hl7.fhir.r5.model.CodeSystem.ConceptPropertyComponent;
import org.hl7.fhir.r5.model.CodeSystem.PropertyType;
import org.hl7.fhir.r5.model.Coding;
import org.hl7.fhir.r5.model.Enumerations.CodeSystemContentMode;
import org.hl7.fhir.r5.model.Enumerations.PublicationStatus;
import org.hl7.fhir.r5.terminologies.CodeSystemUtilities;
import org.hl7.fhir.utilities.CSVReader;
import org.hl7.fhir.utilities.Utilities;
public class CPTImporter {
public static void main(String[] args) throws FHIRException, FileNotFoundException, IOException, ClassNotFoundException, SQLException {
new CPTImporter().doImport(args[0], args[1], args[2]);
}
private Connection con;
private void doImport(String src, String version, String dst) throws FHIRException, FileNotFoundException, IOException, ClassNotFoundException, SQLException {
CodeSystem cs = new CodeSystem();
cs.setId("cpt");
cs.setUrl("http://www.ama-assn.org/go/cpt");
cs.setVersion(version);
cs.setName("AmaCPT");
cs.setTitle("AMA CPT");
cs.setStatus(PublicationStatus.ACTIVE);
cs.setDate(new Date());
cs.setContent(CodeSystemContentMode.COMPLETE);
cs.setCompositional(true);
cs.setPublisher("AMA");
cs.setValueSet("http://hl7.org/fhir/ValueSet/cpt-all");
cs.setCopyright("CPT © Copyright 2019 American Medical Association. All rights reserved. AMA and CPT are registered trademarks of the American Medical Association.");
cs.addProperty().setCode("modifier").setDescription("Whether code is a modifier code").setType(PropertyType.BOOLEAN);
cs.addProperty().setCode("modified").setDescription("Whether code has been modified (all base codes are not modified)").setType(PropertyType.BOOLEAN);
cs.addProperty().setCode("kind").setDescription("Kind of Code (see metadata)").setType(PropertyType.CODE);
defineMetadata(cs);
System.out.println(readCodes(cs, Utilities.path(src, "LONGULT.txt"), false, null, null));
System.out.println(readCodes(cs, Utilities.path(src, "LONGUT.txt"), false, "upper", null));
System.out.println(readCodes(cs, Utilities.path(src, "MEDU.txt"), false, "med", null));
System.out.println(readCodes(cs, Utilities.path(src, "SHORTU.txt"), false, "short", null));
System.out.println(readCodes(cs, Utilities.path(src, "ConsumerDescriptor.txt"), true, "consumer", null));
System.out.println(readCodes(cs, Utilities.path(src, "ClinicianDescriptor.txt"), true, "clinician", null));
System.out.println(readCodes(cs, Utilities.path(src, "OrthopoxvirusCodes.txt"), false, null, "orthopod"));
System.out.println(processModifiers(cs, Utilities.path(src, "modifiers.csv")));
System.out.println("-------------------");
System.out.println(cs.getConcept().size());
int c = 0;
int k = 0;
for (ConceptDefinitionComponent cc: cs.getConcept()) {
c = Integer.max(c, cc.getProperty().size());
if (cc.getProperty().size() > 3) {
k++;
}
}
System.out.println(c);
System.out.println(k);
new JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(dst), cs);
connect(Utilities.changeFileExt(dst, ".db"));
Statement stmt = con.createStatement();
stmt.execute("insert into Information (name, value) values ('version', "+cs.getVersion()+")");
for (ConceptDefinitionComponent cc: cs.getConcept()) {
if (!cc.getCode().startsWith("metadata")) {
stmt.execute("insert into Concepts (code, modifier) values ('"+cc.getCode()+"', "+isModifier(cc)+")");
int i = 0;
if (cc.hasDisplay()) {
stmt.execute("insert into Designations (code, type, sequence, value) values ('"+cc.getCode()+"', 0, 0, '"+Utilities.escapeSql(cc.getDisplay())+"')");
i++;
}
for (ConceptDefinitionDesignationComponent d : cc.getDesignation()) {
stmt.execute("insert into Designations (code, type, sequence, value) values ('"+cc.getCode()+"', '"+d.getUse().getCode()+"', "+i+", '"+Utilities.escapeSql(d.getValue())+"')");
i++;
}
i = 0;
for (ConceptPropertyComponent p : cc.getProperty()) {
if (!Utilities.existsInList(p.getCode(), "modified", "modifier")) {
stmt.execute("insert into Properties (code, name, sequence, value) values ('"+cc.getCode()+"', '"+p.getCode()+"', "+i+", '"+p.getValue().primitiveValue()+"')");
i++;
}
}
}
}
cs.getConcept().removeIf(cc -> !Utilities.existsInList(cc.getCode(), "metadata-kinds", "metadata-designations", "99202", "25"));
new JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(dst+"-fragment"), cs);
}
private String isModifier(ConceptDefinitionComponent cc) {
for (ConceptPropertyComponent p : cc.getProperty()) {
if (p.getCode().equals("modifier")) {
return p.getValue().primitiveValue().equals("true") ? "1" : "0";
}
}
return "0";
}
private void connect(String dest) throws SQLException, ClassNotFoundException {
// Class.forName("com.mysql.jdbc.Driver");
// con = DriverManager.getConnection("jdbc:mysql://localhost:3306/omop?useSSL=false","root",{pwd});
new File(dest).delete();
con = DriverManager.getConnection("jdbc:sqlite:"+dest);
makeMetadataTable();
makeConceptsTable();
makeDesignationsTable();
makePropertiesTable();
}
private void makeDesignationsTable() throws SQLException {
Statement stmt = con.createStatement();
stmt.execute("CREATE TABLE Designations (\r\n"+
"`code` varchar(15) NOT NULL,\r\n"+
"`type` varchar(15) NOT NULL,\r\n"+
"`sequence` int NOT NULL,\r\n"+
"`value` text NOT NULL,\r\n"+
"PRIMARY KEY (`code`, `type`, `sequence`))\r\n");
}
private void makePropertiesTable() throws SQLException {
Statement stmt = con.createStatement();
stmt.execute("CREATE TABLE Properties (\r\n"+
"`code` varchar(15) NOT NULL,\r\n"+
"`name` varchar(15) NOT NULL,\r\n"+
"`sequence` int NOT NULL,\r\n"+
"`value` varchar(15) NOT NULL,\r\n"+
"PRIMARY KEY (`code`, `name`, `sequence`))\r\n");
}
private void makeConceptsTable() throws SQLException {
Statement stmt = con.createStatement();
stmt.execute("CREATE TABLE Concepts (\r\n"+
"`code` varchar(15) NOT NULL,\r\n"+
"`modifier` int DEFAULT NULL,\r\n"+
"PRIMARY KEY (`code`))\r\n");
}
private void makeMetadataTable() throws SQLException {
Statement stmt = con.createStatement();
stmt.execute("CREATE TABLE Information (\r\n"+
"`name` varchar(64) NOT NULL,\r\n"+
"`value` varchar(64) DEFAULT NULL,\r\n"+
"PRIMARY KEY (`name`))\r\n");
}
private void defineMetadata(CodeSystem cs) {
ConceptDefinitionComponent pc = mm(cs.addConcept().setCode("metadata-kinds"));
mm(pc.addConcept()).setCode("code").setDisplay("A normal CPT code");
mm(pc.addConcept()).setCode("cat-1").setDisplay("CPT Level I Modifiers");
mm(pc.addConcept()).setCode("cat-2").setDisplay("A Category II code or modifier");
mm(pc.addConcept()).setCode("physical-status").setDisplay("Anesthesia Physical Status Modifiers");
mm(pc.addConcept()).setCode("general").setDisplay("A general modifier");
mm(pc.addConcept()).setCode("hcpcs").setDisplay("Level II (HCPCS/National) Modifiers");
mm(pc.addConcept()).setCode("orthopox").setDisplay("");
mm(pc.addConcept()).setCode("metadata").setDisplay("A kind of code or designation");
ConceptDefinitionComponent dc = mm(cs.addConcept().setCode("metadata-designations"));
mm(dc.addConcept()).setCode("upper").setDisplay("Uppercase variant of the display");
mm(dc.addConcept()).setCode("med").setDisplay("Medium length variant of the display (all uppercase)");
mm(dc.addConcept()).setCode("short").setDisplay("Short length variant of the display (all uppercase)");
mm(dc.addConcept()).setCode("consumer").setDisplay("Consumer Friendly representation for the concept");
mm(dc.addConcept()).setCode("clinician").setDisplay("Clinician Friendly representation for the concept (can be more than one per concept)");
}
private ConceptDefinitionComponent mm(ConceptDefinitionComponent cc) {
cc.addProperty().setCode("kind").setValue(new CodeType("metadata"));
return cc;
}
private int processModifiers(CodeSystem cs, String path) throws FHIRException, FileNotFoundException, IOException {
CSVReader csv = new CSVReader(new FileInputStream(path));
csv.readHeaders();
int res = 0;
while (csv.line()) {
String code = csv.cell("Code");
String general = csv.cell("General");
String physicalStatus = csv.cell("PhysicalStatus");
String levelOne = csv.cell("LevelOne");
String levelTwo = csv.cell("LevelTwo");
String hcpcs = csv.cell("HCPCS");
String defn = csv.cell("Definition");
res = Integer.max(res, defn.length());
ConceptDefinitionComponent cc = cs.addConcept().setCode(code);
cc.setDisplay(defn);
cc.addProperty().setCode("modified").setValue(new BooleanType(false));
cc.addProperty().setCode("modifier").setValue(new BooleanType(true));
if ("1".equals(general)) {
cc.addProperty().setCode("kind").setValue(new CodeType("general"));
}
if ("1".equals(physicalStatus)) {
cc.addProperty().setCode("kind").setValue(new CodeType("physical-status"));
}
if ("1".equals(levelOne)) {
cc.addProperty().setCode("kind").setValue(new CodeType("cat-1"));
}
if ("1".equals(levelTwo)) {
cc.addProperty().setCode("kind").setValue(new CodeType("cat-2"));
}
if ("1".equals(hcpcs)) {
cc.addProperty().setCode("kind").setValue(new CodeType("hcpcs"));
}
}
return res;
}
private int readCodes(CodeSystem cs, String path, boolean hasConceptId, String use, String type) throws IOException {
int res = 0;
FileInputStream inputStream = null;
Scanner sc = null;
try {
inputStream = new FileInputStream(path);
sc = new Scanner(inputStream, "UTF-8");
while (sc.hasNextLine()) {
String line = sc.nextLine();
if (hasConceptId) {
line = line.substring(7).trim();
}
String code = line.substring(0, 5);
String desc = line.substring(6);
if (desc.contains("\t")) {
desc = desc.substring(desc.indexOf("\t")+1);
}
res = Integer.max(res, desc.length());
ConceptDefinitionComponent cc = CodeSystemUtilities.getCode(cs, code);
if (cc == null) {
cc = cs.addConcept().setCode(code);
cc.addProperty().setCode("modifier").setValue(new BooleanType(false));
cc.addProperty().setCode("modified").setValue(new BooleanType(false));
if (type == null) {
if (Utilities.isInteger(code)) {
cc.addProperty().setCode("kind").setValue(new CodeType("code"));
} else {
cc.addProperty().setCode("kind").setValue(new CodeType("cat-2"));
}
} else {
cc.addProperty().setCode("kind").setValue(new CodeType(type));
}
} else if (type != null) {
cc.addProperty().setCode("kind").setValue(new CodeType(type));
}
if (use == null) {
if (cc.hasDisplay()) {
System.err.println("?");
}
cc.setDisplay(desc);
} else {
cc.addDesignation().setUse(new Coding("http://www.ama-assn.org/go/cpt", use, null)).setValue(desc);
}
}
// note that Scanner suppresses exceptions
if (sc.ioException() != null) {
throw sc.ioException();
}
} finally {
if (inputStream != null) {
inputStream.close();
}
if (sc != null) {
sc.close();
}
}
return res;
}
}

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>6.0.24-SNAPSHOT</version>
<version>6.0.26-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>6.0.24-SNAPSHOT</version>
<version>6.0.26-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>6.0.24-SNAPSHOT</version>
<version>6.0.26-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>6.0.24-SNAPSHOT</version>
<version>6.0.26-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>6.0.24-SNAPSHOT</version>
<version>6.0.26-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>6.0.24-SNAPSHOT</version>
<version>6.0.26-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -192,13 +192,17 @@ public class R5ExtensionsLoader {
for (CanonicalType t : inc.getValueSet()) {
loadValueSet(t.asStringValue(), context, valueSets, codeSystems);
}
if (inc.hasSystem() && !inc.hasVersion()) {
if (codeSystems.containsKey(inc.getSystem())) {
CodeSystem cs = codeSystems.get(inc.getSystem()).getResource();
inc.setVersion(cs.getVersion());
context.cacheResourceFromPackage(cs, cs.getSourcePackage());
} else if (!context.hasResource(CodeSystem.class, inc.getSystem()) && codeSystems.containsKey(inc.getSystem())) {
CodeSystem cs1 = codeSystems.get(inc.getSystem()).getResource();
if (inc.hasSystem()) {
if (!inc.hasVersion()) {
if (codeSystems.containsKey(inc.getSystem())) {
CodeSystem cs = codeSystems.get(inc.getSystem()).getResource();
CodeSystem csAlready = context.fetchCodeSystem(inc.getSystem());
if (csAlready == null) {
context.cacheResourceFromPackage(cs, cs.getSourcePackage());
}
}
} else if (context.fetchResource(CodeSystem.class, inc.getSystem(), inc.getVersion()) == null && codeSystems.containsKey(inc.getSystem()+"|"+inc.getVersion())) {
CodeSystem cs1 = codeSystems.get(inc.getSystem()+"|"+inc.getVersion()).getResource();
context.cacheResourceFromPackage(cs1, cs1.getSourcePackage());
}
}

View File

@ -11,7 +11,9 @@ import org.hl7.fhir.r5.conformance.ElementRedirection;
import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.CanonicalType;
import org.hl7.fhir.r5.model.ElementDefinition;
import org.hl7.fhir.r5.model.ElementDefinition.DiscriminatorType;
import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionSlicingComponent;
import org.hl7.fhir.r5.model.ElementDefinition.SlicingRules;
import org.hl7.fhir.r5.model.OperationOutcome.IssueType;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionSnapshotComponent;
@ -193,9 +195,16 @@ public class ProfilePathProcessor {
private void debugProcessPathsIteration(ProfilePathProcessorState cursors, String currentBasePath) {
if (profileUtilities.isDebug()) {
System.out.println(getDebugIndent() + " - " + currentBasePath + ": base = " + cursors.baseCursor + " (" + profileUtilities.descED(cursors.base.getElement(), cursors.baseCursor) + ") to " + getBaseLimit() + " (" + profileUtilities.descED(cursors.base.getElement(), getBaseLimit()) + "), diff = " + cursors.diffCursor + " (" + profileUtilities.descED(getDifferential().getElement(), cursors.diffCursor) + ") to " + getDiffLimit() + " (" + profileUtilities.descED(getDifferential().getElement(), getDiffLimit()) + ") " +
System.out.println(getDebugIndent() + " - " + currentBasePath + ": "+
"base = " + cursors.baseCursor + " (" + profileUtilities.descED(cursors.base.getElement(), cursors.baseCursor) + ") to " + getBaseLimit() +" (" + profileUtilities.descED(cursors.base.getElement(), getBaseLimit()) + "), "+
"diff = " + cursors.diffCursor + " (" + profileUtilities.descED(getDifferential().getElement(), cursors.diffCursor) + ") to " + getDiffLimit() + " (" + profileUtilities.descED(getDifferential().getElement(), getDiffLimit()) + ") " +
"(slicingDone = " + getSlicing().isDone() + ") (diffpath= " + (getDifferential().getElement().size() > cursors.diffCursor ? getDifferential().getElement().get(cursors.diffCursor).getPath() : "n/a") + ")");
String path = cursors.diffCursor >=0 && cursors.diffCursor < getDifferential().getElement().size() ? getDifferential().getElement().get(cursors.diffCursor).present() : null;
// if (path != null && path.contains(":populationBasis")) {
// System.out.println("!");
// }
}
}
private void debugProcessPathsEntry(ProfilePathProcessorState cursors) {
@ -294,7 +303,7 @@ public class ProfilePathProcessor {
// differential - if the first one in the list has a name, we'll process it. Else we'll treat it as the base definition of the slice.
if (!diffMatches.get(0).hasSliceName()) {
profileUtilities.updateFromDefinition(outcome, diffMatches.get(0), getProfileName(), isTrimDifferential(), getUrl(),getSourceStructureDefinition(), getDerived());
profileUtilities.updateFromDefinition(outcome, diffMatches.get(0), getProfileName(), isTrimDifferential(), getUrl(),getSourceStructureDefinition(), getDerived(), diffPath(diffMatches.get(0)));
profileUtilities.removeStatusExtensions(outcome);
if (!outcome.hasContentReference() && !outcome.hasType() && outcome.getPath().contains(".")) {
throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.NOT_DONE_YET));
@ -354,6 +363,10 @@ public class ProfilePathProcessor {
cursors.diffCursor = newDiffLimit + 1;
}
private String diffPath(ElementDefinition ed) {
return "StructureDefinition.differential.element["+differential.getElement().indexOf(ed)+"]";
}
private String slicingSummary(ElementDefinitionSlicingComponent s) {
return s.toString();
}
@ -635,6 +648,11 @@ public class ProfilePathProcessor {
res = outcome;
profileUtilities.updateFromBase(outcome, currentBase, getSourceStructureDefinition().getUrl());
if (diffMatches.get(0).hasSliceName()) {
template = currentBase.copy();
template = profileUtilities.updateURLs(getUrl(), getWebUrl(), template);
template.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), template.getPath(), getRedirector(), getContextPathSource()));
checkToSeeIfSlicingExists(diffMatches.get(0), template);
outcome.setSliceName(diffMatches.get(0).getSliceName());
if (!diffMatches.get(0).hasMin() && (diffMatches.size() > 1 || getSlicing().getElementDefinition()== null || getSlicing().getElementDefinition().getSlicing().getRules() != ElementDefinition.SlicingRules.CLOSED) && !currentBase.hasSliceName()) {
if (!currentBasePath.endsWith("xtension.value[x]")) { // hack work around for problems with snapshots in official releases
@ -642,7 +660,7 @@ public class ProfilePathProcessor {
}
}
}
profileUtilities.updateFromDefinition(outcome, diffMatches.get(0), getProfileName(), isTrimDifferential(), getUrl(), getSourceStructureDefinition(), getDerived());
profileUtilities.updateFromDefinition(outcome, diffMatches.get(0), getProfileName(), isTrimDifferential(), getUrl(), getSourceStructureDefinition(), getDerived(), diffPath(diffMatches.get(0)));
profileUtilities.removeStatusExtensions(outcome);
// if (outcome.getPath().endsWith("[x]") && outcome.getType().size() == 1 && !outcome.getType().get(0).getCode().equals("*") && !diffMatches.get(0).hasSlicing()) // if the base profile allows multiple types, but the profile only allows one, rename it
// outcome.setPath(outcome.getPath().substring(0, outcome.getPath().length()-3)+Utilities.capitalize(outcome.getType().get(0).getCode()));
@ -743,6 +761,63 @@ public class ProfilePathProcessor {
return res;
}
private void checkToSeeIfSlicingExists(ElementDefinition ed, ElementDefinition template) {
List<ElementDefinition> ss = result.getElement();
int i = ss.size() -1;
ElementDefinition m = null;
while (i >= 0) {
ElementDefinition t = ss.get(i);
if (pathsMatch(t.getPath(), ed.getPath())) {
if (t.hasSlicing() || t.hasSliceName() || t.getPath().endsWith("[x]")) {
m = t;
break;
}
}
if (t.getPath().length() < ed.getPath().length()) {
break;
}
i--;
}
if (m == null) {
if (template.getPath().endsWith(".extension")) {
template.getSlicing().setRules(SlicingRules.OPEN);
template.getSlicing().setOrdered(false);
template.getSlicing().addDiscriminator().setType(DiscriminatorType.VALUE).setPath("url");
result.getElement().add(template);
} else {
System.err.println("checkToSeeIfSlicingExists: "+ed.getPath()+":"+ed.getSliceName()+" is not sliced");
}
}
}
private boolean pathsMatch(String path1, String path2) {
String[] p1 = path1.split("\\.");
String[] p2 = path2.split("\\.");
if (p1.length != p2.length) {
return false;
}
for (int i = 0; i < p1.length; i++) {
String pp1 = p1[i];
String pp2 = p2[i];
if (!pp1.equals(pp2)) {
if (pp1.endsWith("[x]")) {
if (!pp2.startsWith(pp1.substring(0, pp1.length()-3))) {
return false;
}
} else if (pp2.endsWith("[x]")) {
if (!pp1.startsWith(pp2.substring(0, pp2.length()-3))) {
return false;
}
} else {
return false;
}
}
}
return true;
}
private int indexOfFirstNonChild(StructureDefinitionSnapshotComponent base, ElementDefinition currentBase, int i, int baseLimit) {
return baseLimit+1;
}
@ -937,7 +1012,7 @@ public class ProfilePathProcessor {
profileUtilities.updateFromBase(outcome, currentBase, getSourceStructureDefinition().getUrl());
if (diffMatches.get(0).hasSlicing() || !diffMatches.get(0).hasSliceName()) {
profileUtilities.updateFromSlicing(outcome.getSlicing(), diffMatches.get(0).getSlicing());
profileUtilities.updateFromDefinition(outcome, diffMatches.get(0), getProfileName(), closed, getUrl(), getSourceStructureDefinition(), getDerived()); // if there's no slice, we don't want to update the unsliced description
profileUtilities.updateFromDefinition(outcome, diffMatches.get(0), getProfileName(), closed, getUrl(), getSourceStructureDefinition(), getDerived(), diffPath(diffMatches.get(0))); // if there's no slice, we don't want to update the unsliced description
profileUtilities.removeStatusExtensions(outcome);
} else if (!diffMatches.get(0).hasSliceName()) {
diffMatches.get(0).setUserData(profileUtilities.UD_GENERATED_IN_SNAPSHOT, outcome); // because of updateFromDefinition isn't called
@ -1075,7 +1150,7 @@ public class ProfilePathProcessor {
throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH));
debugCheck(outcome);
getResult().getElement().add(outcome);
profileUtilities.updateFromDefinition(outcome, diffItem, getProfileName(), isTrimDifferential(), getUrl(), getSourceStructureDefinition(), getDerived());
profileUtilities.updateFromDefinition(outcome, diffItem, getProfileName(), isTrimDifferential(), getUrl(), getSourceStructureDefinition(), getDerived(), diffPath(diffItem));
profileUtilities.removeStatusExtensions(outcome);
// --- LM Added this
cursors.diffCursor = getDifferential().getElement().indexOf(diffItem) + 1;

View File

@ -139,11 +139,13 @@ public class ProfileUtilities extends TranslatingUtilities {
public class ElementDefinitionCounter {
int countMin = 0;
int countMax = 0;
int index = 0;
ElementDefinition focus;
Set<String> names = new HashSet<>();
public ElementDefinitionCounter(ElementDefinition ed) {
public ElementDefinitionCounter(ElementDefinition ed, int i) {
focus = ed;
index = i;
}
public int checkMin() {
@ -192,6 +194,11 @@ public class ProfileUtilities extends TranslatingUtilities {
public boolean checkMinMax() {
return countMin <= countMax;
}
public int getIndex() {
return index;
}
}
public enum MappingMergeModeOption {
@ -683,11 +690,12 @@ public class ProfileUtilities extends TranslatingUtilities {
checkGroupConstraints(derived);
if (derived.getDerivation() == TypeDerivationRule.SPECIALIZATION) {
int i = 0;
for (ElementDefinition e : diff.getElement()) {
if (!e.hasUserData(UD_GENERATED_IN_SNAPSHOT) && e.getPath().contains(".")) {
ElementDefinition existing = getElementInCurrentContext(e.getPath(), derived.getSnapshot().getElement());
if (existing != null) {
updateFromDefinition(existing, e, profileName, false, url, base, derived);
updateFromDefinition(existing, e, profileName, false, url, base, derived, "StructureDefinition.differential.element["+i+"]");
} else {
ElementDefinition outcome = updateURLs(url, webUrl, e.copy());
e.setUserData(UD_GENERATED_IN_SNAPSHOT, outcome);
@ -701,6 +709,7 @@ public class ProfileUtilities extends TranslatingUtilities {
}
}
}
i++;
}
}
@ -723,6 +732,7 @@ public class ProfileUtilities extends TranslatingUtilities {
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder();
//Check that all differential elements have a corresponding snapshot element
int ce = 0;
int i = 0;
for (ElementDefinition e : diff.getElement()) {
if (!e.hasUserData("diff-source"))
throw new Error(context.formatMessage(I18nConstants.UNXPECTED_INTERNAL_CONDITION__NO_SOURCE_ON_DIFF_ELEMENT));
@ -736,15 +746,16 @@ public class ProfileUtilities extends TranslatingUtilities {
b.append(e.hasId() ? "id: "+e.getId() : "path: "+e.getPath());
ce++;
if (e.hasId()) {
String msg = "No match found in the generated snapshot: check that the path and definitions are legal in the differential (including order)";
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, url+"#"+e.getId(), msg, ValidationMessage.IssueSeverity.ERROR));
String msg = "No match found for "+e.getId()+" in the generated snapshot: check that the path and definitions are legal in the differential (including order)";
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, "StructureDefinition.differential.element["+i+"]", msg, ValidationMessage.IssueSeverity.ERROR));
}
}
i++;
}
if (!Utilities.noString(b.toString())) {
String msg = "The profile "+derived.getUrl()+" has "+ce+" "+Utilities.pluralize("element", ce)+" in the differential ("+b.toString()+") that don't have a matching element in the snapshot: check that the path and definitions are legal in the differential (including order)";
if (debug) {
System.out.println("Error in snapshot generation: "+msg);
System.err.println("Error in snapshot generation: "+msg);
if (!debug) {
System.out.println("Differential: ");
for (ElementDefinition ed : derived.getDifferential().getElement())
@ -789,10 +800,10 @@ public class ProfileUtilities extends TranslatingUtilities {
tn = tn.substring(tn.lastIndexOf("/")+1);
}
Map<String, ElementDefinitionCounter> slices = new HashMap<>();
int i = 0;
i = 0;
for (ElementDefinition ed : derived.getSnapshot().getElement()) {
if (ed.hasSlicing()) {
slices.put(ed.getPath(), new ElementDefinitionCounter(ed));
slices.put(ed.getPath(), new ElementDefinitionCounter(ed, i));
} else {
Set<String> toRemove = new HashSet<>();
for (String s : slices.keySet()) {
@ -809,50 +820,57 @@ public class ProfileUtilities extends TranslatingUtilities {
slice.getFocus().setMin(count);
} else {
String msg = "The slice definition for "+slice.getFocus().getId()+" has a minimum of "+slice.getFocus().getMin()+" but the slices add up to a minimum of "+count;
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, url+"#"+slice.getFocus().getId(), msg, forPublication ? ValidationMessage.IssueSeverity.ERROR : ValidationMessage.IssueSeverity.INFORMATION).setIgnorableError(true));
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE,
"StructureDefinition.snapshot.element["+slice.getIndex()+"]", msg, forPublication ? ValidationMessage.IssueSeverity.ERROR : ValidationMessage.IssueSeverity.INFORMATION).setIgnorableError(true));
}
}
count = slice.checkMax();
if (count > -1 && repeats) {
String msg = "The slice definition for "+slice.getFocus().getId()+" has a maximum of "+slice.getFocus().getMax()+" but the slices add up to a maximum of "+count+". Check that this is what is intended";
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, url+"#"+slice.getFocus().getId(), msg, ValidationMessage.IssueSeverity.INFORMATION));
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE,
"StructureDefinition.snapshot.element["+slice.getIndex()+"]", msg, ValidationMessage.IssueSeverity.INFORMATION));
}
if (!slice.checkMinMax()) {
String msg = "The slice definition for "+slice.getFocus().getId()+" has a maximum of "+slice.getFocus().getMax()+" which is less than the minimum of "+slice.getFocus().getMin();
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, url+"#"+"#"+slice.getFocus().getId(), msg, ValidationMessage.IssueSeverity.WARNING));
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE,
"StructureDefinition.snapshot.element["+slice.getIndex()+"]", msg, ValidationMessage.IssueSeverity.WARNING));
}
slices.remove(s);
}
}
if (ed.getPath().contains(".") && !ed.getPath().startsWith(tn+".")) {
throw new Error("The element "+ed.getId()+" in the profile '"+derived.getVersionedUrl()+" (["+i+"]) doesn't have the right path (should start with "+tn+".");
throw new Error("The element "+ed.getId()+" in the profile '"+derived.getVersionedUrl()+" doesn't have the right path (should start with "+tn+".");
}
if (ed.hasSliceName() && !slices.containsKey(ed.getPath())) {
String msg = "The element "+ed.getId()+" (["+i+"]) launches straight into slicing without the slicing being set up properly first";
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, url+"#"+ed.getId(), msg, ValidationMessage.IssueSeverity.ERROR).setIgnorableError(true));
String msg = "The element "+ed.getId()+" launches straight into slicing without the slicing being set up properly first";
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE,
"StructureDefinition.snapshot.element["+i+"]", msg, ValidationMessage.IssueSeverity.ERROR).setIgnorableError(true));
}
if (ed.hasSliceName() && slices.containsKey(ed.getPath())) {
if (!slices.get(ed.getPath()).count(ed, ed.getSliceName())) {
String msg = "Duplicate slice name "+ed.getSliceName()+" on "+ed.getId()+" (["+i+"])";
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, url+"#"+ed.getId(), msg, ValidationMessage.IssueSeverity.ERROR).setIgnorableError(true));
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE,
"StructureDefinition.snapshot.element["+i+"]", msg, ValidationMessage.IssueSeverity.ERROR).setIgnorableError(true));
}
}
i++;
}
i = 0;
// last, check for wrong profiles or target profiles
for (ElementDefinition ed : derived.getSnapshot().getElement()) {
for (TypeRefComponent t : ed.getType()) {
for (UriType u : t.getProfile()) {
StructureDefinition sd = context.fetchResource(StructureDefinition.class, u.getValue(), derived);
if (sd == null) {
if (xver != null && xver.matchingUrl(u.getValue()) && xver.status(u.getValue()) == XVerExtensionStatus.Valid) {
if (makeXVer().matchingUrl(u.getValue()) && xver.status(u.getValue()) == XVerExtensionStatus.Valid) {
sd = xver.makeDefinition(u.getValue());
}
}
if (sd == null) {
if (messages != null) {
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, url+"#"+ed.getId(), "The type of profile "+u.getValue()+" cannot be checked as the profile is not known", IssueSeverity.WARNING));
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE,
"StructureDefinition.snapshot.element["+i+"]", "The type of profile "+u.getValue()+" cannot be checked as the profile is not known", IssueSeverity.WARNING));
}
} else {
String wt = t.getWorkingCode();
@ -878,6 +896,7 @@ public class ProfileUtilities extends TranslatingUtilities {
}
}
}
i++;
}
} catch (Exception e) {
// if we had an exception generating the snapshot, make sure we don't leave any half generated snapshot behind
@ -891,6 +910,13 @@ public class ProfileUtilities extends TranslatingUtilities {
}
}
private XVerExtensionManager makeXVer() {
if (xver == null) {
xver = new XVerExtensionManager(context);
}
return xver;
}
private ElementDefinition getElementInCurrentContext(String path, List<ElementDefinition> list) {
for (int i = list.size() -1; i >= 0; i--) {
ElementDefinition t = list.get(i);
@ -1358,7 +1384,7 @@ public class ProfileUtilities extends TranslatingUtilities {
return true;
}
if (tr.getWorkingCode().equals(t.getCode())) {
System.out.println("Type error: use of a simple type \""+t.getCode()+"\" wrongly constraining "+base.getPath());
System.err.println("Type error: use of a simple type \""+t.getCode()+"\" wrongly constraining "+base.getPath());
return true;
}
}
@ -1759,14 +1785,14 @@ public class ProfileUtilities extends TranslatingUtilities {
if (type.hasProfile()) {
sd = context.fetchResource(StructureDefinition.class, type.getProfile().get(0).getValue(), src);
if (sd == null) {
if (xver != null && xver.matchingUrl(type.getProfile().get(0).getValue()) && xver.status(type.getProfile().get(0).getValue()) == XVerExtensionStatus.Valid) {
if (makeXVer().matchingUrl(type.getProfile().get(0).getValue()) && xver.status(type.getProfile().get(0).getValue()) == XVerExtensionStatus.Valid) {
sd = xver.makeDefinition(type.getProfile().get(0).getValue());
generateSnapshot(context.fetchTypeDefinition("Extension"), sd, sd.getUrl(), webUrl, sd.getName());
}
}
if (sd == null) {
if (debug) {
System.out.println("Failed to find referenced profile: " + type.getProfile());
System.err.println("Failed to find referenced profile: " + type.getProfile());
}
}
@ -1774,14 +1800,14 @@ public class ProfileUtilities extends TranslatingUtilities {
if (sd == null)
sd = context.fetchTypeDefinition(type.getWorkingCode());
if (sd == null)
System.out.println("XX: failed to find profle for type: " + type.getWorkingCode()); // debug GJM
System.err.println("XX: failed to find profle for type: " + type.getWorkingCode()); // debug GJM
return sd;
}
protected StructureDefinition getProfileForDataType(String type) {
StructureDefinition sd = context.fetchTypeDefinition(type);
if (sd == null)
System.out.println("XX: failed to find profle for type: " + type); // debug GJM
System.err.println("XX: failed to find profle for type: " + type); // debug GJM
return sd;
}
@ -2252,7 +2278,7 @@ public class ProfileUtilities extends TranslatingUtilities {
}
protected void updateFromDefinition(ElementDefinition dest, ElementDefinition source, String pn, boolean trimDifferential, String purl, StructureDefinition srcSD, StructureDefinition derivedSrc) throws DefinitionException, FHIRException {
protected void updateFromDefinition(ElementDefinition dest, ElementDefinition source, String pn, boolean trimDifferential, String purl, StructureDefinition srcSD, StructureDefinition derivedSrc, String path) throws DefinitionException, FHIRException {
source.setUserData(UD_GENERATED_IN_SNAPSHOT, dest);
// we start with a clone of the base profile ('dest') and we copy from the profile ('source')
// over the top for anything the source has
@ -2297,8 +2323,25 @@ public class ProfileUtilities extends TranslatingUtilities {
if (base.hasSliceName()) {
profile = base.getType().size() == 1 && base.getTypeFirstRep().hasProfile() ? context.fetchResource(StructureDefinition.class, base.getTypeFirstRep().getProfile().get(0).getValue(), srcSD) : null;
}
if (profile==null) {
profile = source.getType().size() == 1 && source.getTypeFirstRep().hasProfile() ? context.fetchResource(StructureDefinition.class, source.getTypeFirstRep().getProfile().get(0).getValue(), derivedSrc) : null;
if (profile == null && source.getTypeFirstRep().hasProfile()) {
String pu = source.getTypeFirstRep().getProfile().get(0).getValue();
profile = context.fetchResource(StructureDefinition.class, pu, derivedSrc);
if (profile == null) {
if (makeXVer().matchingUrl(pu)) {
switch (xver.status(pu)) {
case BadVersion:
throw new FHIRException("Reference to invalid version in extension url " + pu);
case Invalid:
throw new FHIRException("Reference to invalid extension " + pu);
case Unknown:
throw new FHIRException("Reference to unknown extension " + pu);
case Valid:
profile = xver.makeDefinition(pu);
generateSnapshot(context.fetchTypeDefinition("Extension"), profile, profile.getUrl(), context.getSpecUrl(), profile.getName());
}
}
}
if (profile != null && !"Extension".equals(profile.getType()) && profile.getKind() != StructureDefinitionKind.RESOURCE && profile.getKind() != StructureDefinitionKind.LOGICAL) {
// this is a problem - we're kind of hacking things here. The problem is that we sometimes want the details from the profile to override the
// inherited attributes, and sometimes not
@ -2666,7 +2709,7 @@ public class ProfileUtilities extends TranslatingUtilities {
if (!Base.compareDeep(derived.getType(), base.getType(), false)) {
if (base.hasType()) {
for (TypeRefComponent ts : derived.getType()) {
checkTypeDerivation(purl, derivedSrc, base, derived, ts);
checkTypeDerivation(purl, derivedSrc, base, derived, ts, path);
}
}
base.getType().clear();
@ -2792,7 +2835,7 @@ public class ProfileUtilities extends TranslatingUtilities {
}
}
private void checkTypeDerivation(String purl, StructureDefinition srcSD, ElementDefinition base, ElementDefinition derived, TypeRefComponent ts) {
private void checkTypeDerivation(String purl, StructureDefinition srcSD, ElementDefinition base, ElementDefinition derived, TypeRefComponent ts, String path) {
boolean ok = false;
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder();
String t = ts.getWorkingCode();
@ -2814,13 +2857,14 @@ public class ProfileUtilities extends TranslatingUtilities {
}
}
// work around for old badly generated SDs
if (DONT_DO_THIS && Utilities.existsInList(tt, "Extension", "uri", "string", "Element")) {
matchType = true;
}
if (DONT_DO_THIS && Utilities.existsInList(tt, "Resource","DomainResource") && pkp.isResource(t)) {
matchType = true;
}
// if (DONT_DO_THIS && Utilities.existsInList(tt, "Extension", "uri", "string", "Element")) {
// matchType = true;
// }
// if (DONT_DO_THIS && Utilities.existsInList(tt, "Resource","DomainResource") && pkp.isResource(t)) {
// matchType = true;
// }
if (matchType) {
ts.copyExtensions(td, "http://hl7.org/fhir/StructureDefinition/elementdefinition-type-must-support", "http://hl7.org/fhir/StructureDefinition/elementdefinition-pattern", "http://hl7.org/fhir/StructureDefinition/obligation");
if (ts.hasTargetProfile()) {
// check that any derived target has a reference chain back to one of the base target profiles
for (UriType u : ts.getTargetProfile()) {
@ -2830,7 +2874,7 @@ public class ProfileUtilities extends TranslatingUtilities {
StructureDefinition sd = context.fetchResource(StructureDefinition.class, url);
if (sd == null) {
if (messages != null) {
messages.add(new ValidationMessage(Source.InstanceValidator, IssueType.BUSINESSRULE, purl + "#" + derived.getPath(), "Cannot check whether the target profile " + url + " is valid constraint on the base because it is not known", IssueSeverity.WARNING));
messages.add(new ValidationMessage(Source.InstanceValidator, IssueType.BUSINESSRULE, path, "Cannot check whether the target profile " + url + " on "+derived.getPath()+" is valid constraint on the base because it is not known", IssueSeverity.WARNING));
}
url = null;
tgtOk = true; // suppress error message
@ -2839,9 +2883,9 @@ public class ProfileUtilities extends TranslatingUtilities {
tgtOk = td.hasTargetProfile(url);
}
}
if (tgtOk)
if (tgtOk) {
ok = true;
else {
} else {
if (messages == null) {
throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT__THE_TARGET_PROFILE__IS_NOT__VALID_CONSTRAINT_ON_THE_BASE_, purl, derived.getPath(), url, td.getTargetProfile()));
} else {

View File

@ -1490,6 +1490,8 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
String system = null;
String code = null;
String version = null;
List<OperationOutcomeIssueComponent> issues = new ArrayList<>();
TerminologyServiceErrorClass err = TerminologyServiceErrorClass.UNKNOWN;
for (ParametersParameterComponent p : pOut.getParameter()) {
if (p.hasValue()) {
@ -1506,7 +1508,19 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
} else if (p.getName().equals("code")) {
code = ((PrimitiveType<?>) p.getValue()).asStringValue();
} else if (p.getName().equals("x-caused-by-unknown-system")) {
err = TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED;
err = TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED;
} else if (p.getName().equals("warning-withdrawn")) {
OperationOutcomeIssueComponent iss = new OperationOutcomeIssueComponent(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.INFORMATION, org.hl7.fhir.r5.model.OperationOutcome.IssueType.EXPIRED);
iss.getDetails().setText(formatMessage(I18nConstants.MSG_WITHDRAWN, ((PrimitiveType<?>) p.getValue()).asStringValue()));
issues.add(iss);
} else if (p.getName().equals("warning-deprecated")) {
OperationOutcomeIssueComponent iss = new OperationOutcomeIssueComponent(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.INFORMATION, org.hl7.fhir.r5.model.OperationOutcome.IssueType.EXPIRED);
iss.getDetails().setText(formatMessage(I18nConstants.MSG_DEPRECATED, ((PrimitiveType<?>) p.getValue()).asStringValue()));
issues.add(iss);
} else if (p.getName().equals("warning-retired")) {
OperationOutcomeIssueComponent iss = new OperationOutcomeIssueComponent(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.INFORMATION, org.hl7.fhir.r5.model.OperationOutcome.IssueType.EXPIRED);
iss.getDetails().setText(formatMessage(I18nConstants.MSG_RETIRED, ((PrimitiveType<?>) p.getValue()).asStringValue()));
issues.add(iss);
} else if (p.getName().equals("cause")) {
try {
IssueType it = IssueType.fromCode(((StringType) p.getValue()).getValue());
@ -1524,15 +1538,18 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
}
}
}
ValidationResult res = null;
if (!ok) {
return new ValidationResult(IssueSeverity.ERROR, message+" (from "+tcc.getClient().getId()+")", err, null).setTxLink(txLog.getLastId());
res = new ValidationResult(IssueSeverity.ERROR, message+" (from "+tcc.getClient().getId()+")", err, null).setTxLink(txLog.getLastId());
} else if (message != null && !message.equals("No Message returned")) {
return new ValidationResult(IssueSeverity.WARNING, message+" (from "+tcc.getClient().getId()+")", system, version, new ConceptDefinitionComponent().setDisplay(display).setCode(code), display, null).setTxLink(txLog.getLastId());
res = new ValidationResult(IssueSeverity.WARNING, message+" (from "+tcc.getClient().getId()+")", system, version, new ConceptDefinitionComponent().setDisplay(display).setCode(code), display, null).setTxLink(txLog.getLastId());
} else if (display != null) {
return new ValidationResult(system, version, new ConceptDefinitionComponent().setDisplay(display).setCode(code), display).setTxLink(txLog.getLastId());
res = new ValidationResult(system, version, new ConceptDefinitionComponent().setDisplay(display).setCode(code), display).setTxLink(txLog.getLastId());
} else {
return new ValidationResult(system, version, new ConceptDefinitionComponent().setCode(code), null).setTxLink(txLog.getLastId());
res = new ValidationResult(system, version, new ConceptDefinitionComponent().setCode(code), null).setTxLink(txLog.getLastId());
}
res.setIssues(issues );
return res;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------

View File

@ -124,7 +124,7 @@ public interface IWorkerContext {
private List<OperationOutcomeIssueComponent> issues = new ArrayList<>();
private CodeableConcept codeableConcept;
private Set<String> unknownSystems;
@Override
public String toString() {
return "ValidationResult [definition=" + definition + ", system=" + system + ", severity=" + severity + ", message=" + message + ", errorClass="
@ -315,6 +315,14 @@ public interface IWorkerContext {
}
}
public void setIssues(List<OperationOutcomeIssueComponent> issues) {
if (this.issues != null) {
issues.addAll(this.issues);
}
this.issues = issues;
}
}
public class CodingValidationRequest {

View File

@ -544,8 +544,9 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
if (s.startsWith("version=")) {
if (version == null)
version = s.substring(8);
else if (!version.equals(s.substring(8)))
else if (!version.equals(s.substring(8))) {
throw new DefinitionException(formatMessage(I18nConstants.VERSION_MISMATCH_THE_CONTEXT_HAS_VERSION__LOADED_AND_THE_NEW_CONTENT_BEING_LOADED_IS_VERSION_, version, s.substring(8)));
}
}
if (s.startsWith("revision="))
revision = s.substring(9);

View File

@ -695,10 +695,7 @@ public class TerminologyCache {
}
protected String hashJson(String s) {
s = StringUtils.remove(s, ' ');
s = StringUtils.remove(s, '\n');
s = StringUtils.remove(s, '\r');
return String.valueOf(s.hashCode());
return String.valueOf(s.trim().hashCode());
}
// management

View File

@ -498,6 +498,14 @@ public abstract class Element extends Base implements IBaseHasExtensions, IBaseE
}
}
public void copyNewExtensions(org.hl7.fhir.r5.model.Element src, String... urls) {
for (Extension e : src.getExtension()) {
if (Utilities.existsInList(e.getUrl(), urls) && !!hasExtension(e.getUrl())) {
addExtension(e.copy());
}
}
}
// end addition

View File

@ -12748,6 +12748,15 @@ If a pattern[x] is declared on a repeating element, the pattern applies to all r
}
return b.toString();
}
public List<String> typeList() {
List<String> res = new ArrayList<>();
for (TypeRefComponent tr : getType()) {
if (tr.hasCode())
res.add(tr.getWorkingCode());
}
return res;
}
public String typeSummaryVB() {
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder("|");

View File

@ -1753,6 +1753,14 @@ public String toString() {
return true;
}
return false;
}
public boolean hasParameterValue(String name, String value) {
for (ParametersParameterComponent p : getParameter()) {
if (p.getName().equals(name) && p.hasValue() && value.equals(p.getValue().primitiveValue()))
return true;
}
return false;
}
public boolean hasParameter(String name) {

View File

@ -2839,12 +2839,24 @@ public class ValueSet extends MetadataResource {
, total, offset, parameter, property, contains);
}
public String fhirType() {
return "ValueSet.expansion";
public boolean hasParameterValue(String name, String value) {
for (ValueSetExpansionParameterComponent p : getParameter()) {
if (name.equals(p.getName()) && p.hasValue() && value.equals(p.getValue().primitiveValue())) {
return true;
}
}
return false;
}
}
public void addParameter(String name, DataType value) {
getParameter().add(new ValueSetExpansionParameterComponent(name).setValue(value));
}
public String fhirType() {
return "ValueSet.expansion";
}
}
}
@Block()
public static class ValueSetExpansionParameterComponent extends BackboneElement implements IBaseBackboneElement {

View File

@ -198,7 +198,6 @@ public class ValueSetRenderer extends TerminologyRenderer {
generateContentModeNotices(x, vs.getExpansion(), vs);
generateVersionNotice(x, vs.getExpansion(), vs);
CodeSystem allCS = null;
boolean doLevel = false;
for (ValueSetExpansionContainsComponent cc : vs.getExpansion().getContains()) {
if (cc.hasContains()) {
@ -206,8 +205,9 @@ public class ValueSetRenderer extends TerminologyRenderer {
break;
}
}
boolean doInactive = checkDoInactive(vs.getExpansion().getContains());
boolean doDefinition = checkDoDefinition(vs.getExpansion().getContains());
XhtmlNode t = x.table( "codes");
XhtmlNode tr = t.tr();
if (doLevel)
@ -221,6 +221,9 @@ public class ValueSetRenderer extends TerminologyRenderer {
scanForDesignations(c, langs, designations);
}
scanForProperties(vs.getExpansion(), langs, properties);
if (doInactive) {
tr.td().b().tx("Inactive");
}
if (doDefinition) {
tr.td().b().tx("Definition");
doDesignations = false;
@ -250,7 +253,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
addMapHeaders(tr, maps);
for (ValueSetExpansionContainsComponent c : vs.getExpansion().getContains()) {
addExpansionRowToTable(t, vs, c, 1, doLevel, true, doDefinition, maps, allCS, langs, designations, doDesignations, properties);
addExpansionRowToTable(t, vs, c, 1, doLevel, doDefinition, doInactive, maps, langs, designations, doDesignations, properties);
}
// now, build observed languages
@ -673,6 +676,17 @@ public class ValueSetRenderer extends TerminologyRenderer {
return false;
}
private boolean checkDoInactive(List<ValueSetExpansionContainsComponent> contains) {
for (ValueSetExpansionContainsComponent c : contains) {
if (c.hasInactive()) {
return true;
}
if (checkDoInactive(c.getContains()))
return true;
}
return false;
}
private boolean allFromOneSystem(ValueSet vs) {
if (vs.getExpansion().getContains().isEmpty())
@ -754,7 +768,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
}
}
private void addExpansionRowToTable(XhtmlNode t, ValueSet vs, ValueSetExpansionContainsComponent c, int i, boolean doLevel, boolean doSystem, boolean doDefinition, List<UsedConceptMap> maps, CodeSystem allCS, List<String> langs, Map<String, String> designations, boolean doDesignations, Map<String, String> properties) throws FHIRFormatError, DefinitionException, IOException {
private void addExpansionRowToTable(XhtmlNode t, ValueSet vs, ValueSetExpansionContainsComponent c, int i, boolean doLevel, boolean doDefinition, boolean doInactive, List<UsedConceptMap> maps, List<String> langs, Map<String, String> designations, boolean doDesignations, Map<String, String> properties) throws FHIRFormatError, DefinitionException, IOException {
XhtmlNode tr = t.tr();
if (ValueSetUtilities.isDeprecated(vs, c)) {
tr.setAttribute("style", "background-color: #ffeeee");
@ -772,19 +786,21 @@ public class ValueSetRenderer extends TerminologyRenderer {
String s = Utilities.padLeft("", '\u00A0', i*2);
td.attribute("style", "white-space:nowrap").addText(s);
addCodeToTable(c.getAbstract(), c.getSystem(), c.getCode(), c.getDisplay(), td);
if (doSystem) {
td = tr.td();
td.addText(c.getSystem());
}
td = tr.td();
td.addText(c.getSystem());
td = tr.td();
if (c.hasDisplayElement())
td.addText(c.getDisplay());
if (doDefinition) {
CodeSystem cs = allCS;
if (cs == null)
cs = getContext().getWorker().fetchCodeSystem(c.getSystem());
if (doInactive) {
td = tr.td();
if (c.getInactive()) {
td.tx("inactive");
}
}
if (doDefinition) {
td = tr.td();
CodeSystem cs = getContext().getWorker().fetchCodeSystem(c.getSystem());
if (cs != null) {
String defn = CodeSystemUtilities.getCodeDefinition(cs, c.getCode());
addMarkdown(td, defn, cs.getWebPath());
@ -817,7 +833,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
addLangaugesToRow(c, langs, tr);
}
for (ValueSetExpansionContainsComponent cc : c.getContains()) {
addExpansionRowToTable(t, vs, cc, i+1, doLevel, doSystem, doDefinition, maps, allCS, langs, designations, doDesignations, properties);
addExpansionRowToTable(t, vs, cc, i+1, doLevel, doDefinition, doInactive, maps, langs, designations, doDesignations, properties);
}
}

View File

@ -369,6 +369,10 @@ public class CodeSystemUtilities {
if ("inactive".equals(p.getCode()) && p.hasValueBooleanType()) {
return p.getValueBooleanType().getValue();
}
if ("inactive".equals(p.getCode()) && p.hasValueCodeType()) {
String code = p.getValueCodeType().primitiveValue();
return "true".equals(code);
}
}
return false;
}

View File

@ -124,7 +124,6 @@ public class ValueSetExpander extends ValueSetProcessBase {
private static final boolean REPORT_VERSION_ANYWAY = true;
private IWorkerContext context;
private ValueSet focus;
private List<String> allErrors = new ArrayList<>();
private List<String> requiredSupplements = new ArrayList<>();
@ -151,9 +150,9 @@ public class ValueSetExpander extends ValueSetProcessBase {
private ValueSetExpansionContainsComponent addCode(WorkingContext wc, String system, String code, String display, String dispLang, ValueSetExpansionContainsComponent parent, List<ConceptDefinitionDesignationComponent> designations, Parameters expParams,
boolean isAbstract, boolean inactive, String definition, List<ValueSet> filters, boolean noInactive, boolean deprecated, List<ValueSetExpansionPropertyComponent> vsProp,
List<ConceptPropertyComponent> csProps, List<org.hl7.fhir.r5.model.ValueSet.ConceptPropertyComponent> expProps, List<Extension> csExtList, List<Extension> vsExtList) throws ETooCostly {
List<ConceptPropertyComponent> csProps, List<org.hl7.fhir.r5.model.ValueSet.ConceptPropertyComponent> expProps, List<Extension> csExtList, List<Extension> vsExtList, ValueSetExpansionComponent exp) throws ETooCostly {
if (filters != null && !filters.isEmpty() && !filterContainsCode(filters, system, code))
if (filters != null && !filters.isEmpty() && !filterContainsCode(filters, system, code, exp))
return null;
if (noInactive && inactive) {
return null;
@ -285,10 +284,12 @@ public class ValueSetExpander extends ValueSetProcessBase {
return n;
}
private boolean filterContainsCode(List<ValueSet> filters, String system, String code) {
for (ValueSet vse : filters)
private boolean filterContainsCode(List<ValueSet> filters, String system, String code, ValueSetExpansionComponent exp) {
for (ValueSet vse : filters) {
checkCanonical(exp, vse);
if (expansionContainsCode(vse.getExpansion().getContains(), system, code))
return true;
}
return false;
}
@ -312,18 +313,18 @@ public class ValueSetExpander extends ValueSetProcessBase {
return null;
}
private void addCodeAndDescendents(WorkingContext wc, ValueSetExpansionContainsComponent focus, ValueSetExpansionContainsComponent parent, Parameters expParams, List<ValueSet> filters, boolean noInactive, List<ValueSetExpansionPropertyComponent> vsProps, ValueSet vsSrc) throws FHIRException, ETooCostly {
private void addCodeAndDescendents(WorkingContext wc, ValueSetExpansionContainsComponent focus, ValueSetExpansionContainsComponent parent, Parameters expParams, List<ValueSet> filters, boolean noInactive, List<ValueSetExpansionPropertyComponent> vsProps, ValueSet vsSrc, ValueSetExpansionComponent exp) throws FHIRException, ETooCostly {
focus.checkNoModifiers("Expansion.contains", "expanding");
ValueSetExpansionContainsComponent np = null;
for (String code : getCodesForConcept(focus, expParams)) {
ValueSetExpansionContainsComponent t = addCode(wc, focus.getSystem(), code, focus.getDisplay(), vsSrc.getLanguage(), parent,
convert(focus.getDesignation()), expParams, focus.getAbstract(), focus.getInactive(), focus.getExtensionString(ToolingExtensions.EXT_DEFINITION), filters, noInactive, false, vsProps, null, focus.getProperty(), null, focus.getExtension());
convert(focus.getDesignation()), expParams, focus.getAbstract(), focus.getInactive(), focus.getExtensionString(ToolingExtensions.EXT_DEFINITION), filters, noInactive, false, vsProps, null, focus.getProperty(), null, focus.getExtension(), exp);
if (np == null) {
np = t;
}
}
for (ValueSetExpansionContainsComponent c : focus.getContains())
addCodeAndDescendents(wc, c, np, expParams, filters, noInactive, vsProps, vsSrc);
addCodeAndDescendents(wc, c, np, expParams, filters, noInactive, vsProps, vsSrc, exp);
}
private List<String> getCodesForConcept(ValueSetExpansionContainsComponent focus, Parameters expParams) {
@ -349,8 +350,8 @@ public class ValueSetExpander extends ValueSetProcessBase {
return list;
}
private void addCodeAndDescendents(WorkingContext wc,CodeSystem cs, String system, ConceptDefinitionComponent def, ValueSetExpansionContainsComponent parent, Parameters expParams, List<ValueSet> filters,
ConceptDefinitionComponent exclusion, ConceptFilter filterFunc, boolean noInactive, List<ValueSetExpansionPropertyComponent> vsProps, List<WorkingContext> otherFilters) throws FHIRException, ETooCostly {
private void addCodeAndDescendents(WorkingContext wc, CodeSystem cs, String system, ConceptDefinitionComponent def, ValueSetExpansionContainsComponent parent, Parameters expParams, List<ValueSet> filters,
ConceptDefinitionComponent exclusion, ConceptFilter filterFunc, boolean noInactive, List<ValueSetExpansionPropertyComponent> vsProps, List<WorkingContext> otherFilters, ValueSetExpansionComponent exp) throws FHIRException, ETooCostly {
def.checkNoModifiers("Code in Code System", "expanding");
if (exclusion != null) {
if (exclusion.getCode().equals(def.getCode()))
@ -362,19 +363,19 @@ public class ValueSetExpander extends ValueSetProcessBase {
boolean dep = CodeSystemUtilities.isDeprecated(cs, def, false);
if ((includeAbstract || !abs) && filterFunc.includeConcept(cs, def) && passesOtherFilters(otherFilters, cs, def.getCode())) {
for (String code : getCodesForConcept(def, expParams)) {
ValueSetExpansionContainsComponent t = addCode(wc, system, code, def.getDisplay(), cs.getLanguage(), parent, def.getDesignation(), expParams, abs, inc, def.getDefinition(), filters, noInactive, dep, vsProps, def.getProperty(), null, def.getExtension(), null);
ValueSetExpansionContainsComponent t = addCode(wc, system, code, def.getDisplay(), cs.getLanguage(), parent, def.getDesignation(), expParams, abs, inc, def.getDefinition(), filters, noInactive, dep, vsProps, def.getProperty(), null, def.getExtension(), null, exp);
if (np == null) {
np = t;
}
}
}
for (ConceptDefinitionComponent c : def.getConcept()) {
addCodeAndDescendents(wc, cs, system, c, np, expParams, filters, exclusion, filterFunc, noInactive, vsProps, otherFilters);
addCodeAndDescendents(wc, cs, system, c, np, expParams, filters, exclusion, filterFunc, noInactive, vsProps, otherFilters, exp);
}
if (def.hasUserData(CodeSystemUtilities.USER_DATA_CROSS_LINK)) {
List<ConceptDefinitionComponent> children = (List<ConceptDefinitionComponent>) def.getUserData(CodeSystemUtilities.USER_DATA_CROSS_LINK);
for (ConceptDefinitionComponent c : children)
addCodeAndDescendents(wc, cs, system, c, np, expParams, filters, exclusion, filterFunc, noInactive, vsProps, otherFilters);
addCodeAndDescendents(wc, cs, system, c, np, expParams, filters, exclusion, filterFunc, noInactive, vsProps, otherFilters, exp);
}
}
@ -401,7 +402,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
private void addCodes(ValueSetExpansionComponent expand, List<ValueSetExpansionParameterComponent> params, Parameters expParams, List<ValueSet> filters, boolean noInactive, List<ValueSetExpansionPropertyComponent> vsProps, ValueSet vsSrc) throws ETooCostly, FHIRException {
private void addCodes(ValueSetExpansionComponent expand, List<ValueSetExpansionParameterComponent> params, Parameters expParams, List<ValueSet> filters, boolean noInactive, List<ValueSetExpansionPropertyComponent> vsProps, ValueSet vsSrc, ValueSetExpansionComponent exp) throws ETooCostly, FHIRException {
if (expand != null) {
if (expand.getContains().size() > maxExpansionSize)
throw failCostly(context.formatMessage(I18nConstants.VALUESET_TOO_COSTLY, vsSrc.getUrl(), ">" + Integer.toString(expand.getContains().size())));
@ -410,7 +411,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
params.add(p);
}
copyImportContains(expand.getContains(), null, expParams, filters, noInactive, vsProps, vsSrc);
copyImportContains(expand.getContains(), null, expParams, filters, noInactive, vsProps, vsSrc, exp);
}
}
@ -450,8 +451,6 @@ public class ValueSetExpander extends ValueSetProcessBase {
throw fail("not done yet - multiple filters");
}
private void excludeCodes(WorkingContext wc, ValueSetExpansionComponent expand, List<ValueSetExpansionParameterComponent> params) {
for (ValueSetExpansionContainsComponent c : expand.getContains()) {
excludeCode(wc, c.getSystem(), c.getCode());
@ -460,8 +459,9 @@ public class ValueSetExpander extends ValueSetProcessBase {
private boolean existsInParams(List<ValueSetExpansionParameterComponent> params, String name, DataType value) {
for (ValueSetExpansionParameterComponent p : params) {
if (p.getName().equals(name) && PrimitiveType.compareDeep(p.getValue(), value, false))
if (p.getName().equals(name) && PrimitiveType.compareDeep(p.getValue(), value, false)) {
return true;
}
}
return false;
}
@ -503,6 +503,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
focus.setExpansion(new ValueSet.ValueSetExpansionComponent());
focus.getExpansion().setTimestampElement(DateTimeType.now());
focus.getExpansion().setIdentifier(Factory.createUUID());
checkCanonical(focus.getExpansion(), focus);
for (ParametersParameterComponent p : expParams.getParameter()) {
if (Utilities.existsInList(p.getName(), "includeDesignations", "excludeNested", "activeOnly", "offset", "count")) {
focus.getExpansion().addParameter().setName(p.getName()).setValue(p.getValue());
@ -642,6 +643,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
throw fail("Unable to find imported value set " + value);
}
}
checkCanonical(exp, vs);
if (noInactive) {
expParams = expParams.copy();
expParams.addParameter("activeOnly", true);
@ -714,12 +716,12 @@ public class ValueSetExpander extends ValueSetProcessBase {
}
}
private void copyImportContains(List<ValueSetExpansionContainsComponent> list, ValueSetExpansionContainsComponent parent, Parameters expParams, List<ValueSet> filter, boolean noInactive, List<ValueSetExpansionPropertyComponent> vsProps, ValueSet vsSrc) throws FHIRException, ETooCostly {
private void copyImportContains(List<ValueSetExpansionContainsComponent> list, ValueSetExpansionContainsComponent parent, Parameters expParams, List<ValueSet> filter, boolean noInactive, List<ValueSetExpansionPropertyComponent> vsProps, ValueSet vsSrc, ValueSetExpansionComponent exp) throws FHIRException, ETooCostly {
for (ValueSetExpansionContainsComponent c : list) {
c.checkNoModifiers("Imported Expansion in Code System", "expanding");
ValueSetExpansionContainsComponent np = addCode(dwc, c.getSystem(), c.getCode(), c.getDisplay(), vsSrc.getLanguage(), parent, null, expParams, c.getAbstract(), c.getInactive(), c.getExtensionString(ToolingExtensions.EXT_DEFINITION),
filter, noInactive, false, vsProps, null, c.getProperty(), null, c.getExtension());
copyImportContains(c.getContains(), np, expParams, filter, noInactive, vsProps, vsSrc);
filter, noInactive, false, vsProps, null, c.getProperty(), null, c.getExtension(), exp);
copyImportContains(c.getContains(), np, expParams, filter, noInactive, vsProps, vsSrc, exp);
}
}
@ -734,9 +736,10 @@ public class ValueSetExpander extends ValueSetProcessBase {
if (imports.isEmpty()) // though this is not supposed to be the case
return;
ValueSet base = imports.get(0);
checkCanonical(exp, base);
imports.remove(0);
base.checkNoModifiers("Imported ValueSet", "expanding");
copyImportContains(base.getExpansion().getContains(), null, expParams, imports, noInactive, base.getExpansion().getProperty(), base);
copyImportContains(base.getExpansion().getContains(), null, expParams, imports, noInactive, base.getExpansion().getProperty(), base, exp);
} else {
CodeSystem cs = context.fetchSupplementedCodeSystem(inc.getSystem());
if (ValueSetUtilities.isServerSide(inc.getSystem()) || (cs == null || (cs.getContent() != CodeSystemContentMode.COMPLETE && cs.getContent() != CodeSystemContentMode.FRAGMENT))) {
@ -783,7 +786,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
}
}
for (ValueSetExpansionContainsComponent cc : vs.getExpansion().getContains()) {
addCodeAndDescendents(dwc, cc, null, expParams, imports, noInactive, vsProps, vs);
addCodeAndDescendents(dwc, cc, null, expParams, imports, noInactive, vsProps, vs, exp);
}
}
@ -795,6 +798,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
else
throw failTSE("Unable to find code system " + inc.getSystem().toString());
}
checkCanonical(exp, cs);
cs.checkNoModifiers("Code System", "expanding");
if (cs.getContent() != CodeSystemContentMode.COMPLETE && cs.getContent() != CodeSystemContentMode.FRAGMENT)
throw failTSE("Code system " + inc.getSystem().toString() + " is incomplete");
@ -813,7 +817,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
if (inc.getConcept().size() == 0 && inc.getFilter().size() == 0) {
// special case - add all the code system
for (ConceptDefinitionComponent def : cs.getConcept()) {
addCodeAndDescendents(dwc, cs, inc.getSystem(), def, null, expParams, imports, null, new AllConceptsFilter(allErrors), noInactive, exp.getProperty(), null);
addCodeAndDescendents(dwc, cs, inc.getSystem(), def, null, expParams, imports, null, new AllConceptsFilter(allErrors), noInactive, exp.getProperty(), null, exp);
}
if (cs.getContent() == CodeSystemContentMode.FRAGMENT) {
addFragmentWarning(exp, cs);
@ -846,7 +850,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
isAbstract = CodeSystemUtilities.isNotSelectable(cs, def);
}
addCode(dwc, inc.getSystem(), c.getCode(), !Utilities.noString(c.getDisplay()) ? c.getDisplay() : def == null ? null : def.getDisplay(), c.hasDisplay() ? vsSrc.getLanguage() : cs.getLanguage(), null, mergeDesignations(def, convertDesignations(c.getDesignation())),
expParams, isAbstract, inactive, def == null ? null : def.getDefinition(), imports, noInactive, false, exp.getProperty(), def != null ? def.getProperty() : null, null, def == null ? null : def.getExtension(), c.getExtension());
expParams, isAbstract, inactive, def == null ? null : def.getDefinition(), imports, noInactive, false, exp.getProperty(), def != null ? def.getProperty() : null, null, def == null ? null : def.getExtension(), c.getExtension(), exp);
}
}
if (inc.getFilter().size() > 0) {
@ -876,14 +880,14 @@ public class ValueSetExpander extends ValueSetProcessBase {
ConceptDefinitionComponent def = getConceptForCode(cs.getConcept(), fc.getValue());
if (def == null)
throw failTSE("Code '" + fc.getValue() + "' not found in system '" + inc.getSystem() + "'");
addCodeAndDescendents(wc, cs, inc.getSystem(), def, null, expParams, imports, null, new AllConceptsFilter(allErrors), noInactive, exp.getProperty(), filters);
addCodeAndDescendents(wc, cs, inc.getSystem(), def, null, expParams, imports, null, new AllConceptsFilter(allErrors), noInactive, exp.getProperty(), filters, exp);
} else if ("concept".equals(fc.getProperty()) && fc.getOp() == FilterOperator.ISNOTA) {
// special: all codes in the target code system that are not under the value
ConceptDefinitionComponent defEx = getConceptForCode(cs.getConcept(), fc.getValue());
if (defEx == null)
throw failTSE("Code '" + fc.getValue() + "' not found in system '" + inc.getSystem() + "'");
for (ConceptDefinitionComponent def : cs.getConcept()) {
addCodeAndDescendents(wc, cs, inc.getSystem(), def, null, expParams, imports, defEx, new AllConceptsFilter(allErrors), noInactive, exp.getProperty(), filters);
addCodeAndDescendents(wc, cs, inc.getSystem(), def, null, expParams, imports, defEx, new AllConceptsFilter(allErrors), noInactive, exp.getProperty(), filters, exp);
}
} else if ("concept".equals(fc.getProperty()) && fc.getOp() == FilterOperator.DESCENDENTOF) {
// special: all codes in the target code system under the value
@ -891,11 +895,11 @@ public class ValueSetExpander extends ValueSetProcessBase {
if (def == null)
throw failTSE("Code '" + fc.getValue() + "' not found in system '" + inc.getSystem() + "'");
for (ConceptDefinitionComponent c : def.getConcept())
addCodeAndDescendents(wc, cs, inc.getSystem(), c, null, expParams, imports, null, new AllConceptsFilter(allErrors), noInactive, exp.getProperty(), filters);
addCodeAndDescendents(wc, cs, inc.getSystem(), c, null, expParams, imports, null, new AllConceptsFilter(allErrors), noInactive, exp.getProperty(), filters, exp);
if (def.hasUserData(CodeSystemUtilities.USER_DATA_CROSS_LINK)) {
List<ConceptDefinitionComponent> children = (List<ConceptDefinitionComponent>) def.getUserData(CodeSystemUtilities.USER_DATA_CROSS_LINK);
for (ConceptDefinitionComponent c : children)
addCodeAndDescendents(wc, cs, inc.getSystem(), c, null, expParams, imports, null, new AllConceptsFilter(allErrors), noInactive, exp.getProperty(), filters);
addCodeAndDescendents(wc, cs, inc.getSystem(), c, null, expParams, imports, null, new AllConceptsFilter(allErrors), noInactive, exp.getProperty(), filters, exp);
}
} else if ("display".equals(fc.getProperty()) && fc.getOp() == FilterOperator.EQUAL) {
@ -907,18 +911,18 @@ public class ValueSetExpander extends ValueSetProcessBase {
if (def.getDisplay().contains(fc.getValue()) && passesOtherFilters(filters, cs, def.getCode())) {
for (String code : getCodesForConcept(def, expParams)) {
ValueSetExpansionContainsComponent t = addCode(wc, inc.getSystem(), code, def.getDisplay(), cs.getLanguage(), null, def.getDesignation(), expParams, CodeSystemUtilities.isNotSelectable(cs, def), CodeSystemUtilities.isInactive(cs, def),
def.getDefinition(), imports, noInactive, false, exp.getProperty(), def.getProperty(), null, def.getExtension(), null);
def.getDefinition(), imports, noInactive, false, exp.getProperty(), def.getProperty(), null, def.getExtension(), null, exp);
}
}
}
}
} else if (isDefinedProperty(cs, fc.getProperty())) {
for (ConceptDefinitionComponent def : cs.getConcept()) {
addCodeAndDescendents(wc, cs, inc.getSystem(), def, null, expParams, imports, null, new PropertyFilter(allErrors, fc, getPropertyDefinition(cs, fc.getProperty())), noInactive, exp.getProperty(), filters);
addCodeAndDescendents(wc, cs, inc.getSystem(), def, null, expParams, imports, null, new PropertyFilter(allErrors, fc, getPropertyDefinition(cs, fc.getProperty())), noInactive, exp.getProperty(), filters, exp);
}
} else if ("code".equals(fc.getProperty()) && fc.getOp() == FilterOperator.REGEX) {
for (ConceptDefinitionComponent def : cs.getConcept()) {
addCodeAndDescendents(wc, cs, inc.getSystem(), def, null, expParams, imports, null, new RegexFilter(allErrors, fc.getValue()), noInactive, exp.getProperty(), filters);
addCodeAndDescendents(wc, cs, inc.getSystem(), def, null, expParams, imports, null, new RegexFilter(allErrors, fc.getValue()), noInactive, exp.getProperty(), filters, exp);
}
} else {
throw fail("Filter by property[" + fc.getProperty() + "] and op[" + fc.getOp() + "] is not supported yet");

View File

@ -1,20 +1,31 @@
package org.hl7.fhir.r5.terminologies.utilities;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.model.BooleanType;
import org.hl7.fhir.r5.model.CanonicalResource;
import org.hl7.fhir.r5.model.DataType;
import org.hl7.fhir.r5.model.Enumerations.PublicationStatus;
import org.hl7.fhir.r5.model.OperationOutcome.IssueType;
import org.hl7.fhir.r5.model.OperationOutcome.OperationOutcomeIssueComponent;
import org.hl7.fhir.r5.model.Extension;
import org.hl7.fhir.r5.model.Parameters;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.model.BooleanType;
import org.hl7.fhir.r5.model.CodeSystem.ConceptPropertyComponent;
import org.hl7.fhir.r5.model.DataType;
import org.hl7.fhir.r5.model.Parameters.ParametersParameterComponent;
import org.hl7.fhir.r5.model.PrimitiveType;
import org.hl7.fhir.r5.model.UriType;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionComponent;
import org.hl7.fhir.r5.utils.ToolingExtensions;
import org.hl7.fhir.utilities.StandardsStatus;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.i18n.I18nConstants;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
public class ValueSetProcessBase {
protected IWorkerContext context;
public static class AlternateCodesProcessingRules {
private boolean all;
private List<String> uses = new ArrayList<>();
@ -77,6 +88,88 @@ public class ValueSetProcessBase {
}
}
protected List<OperationOutcomeIssueComponent> makeIssue(IssueSeverity level, IssueType type, String location, String message) {
OperationOutcomeIssueComponent result = new OperationOutcomeIssueComponent();
switch (level) {
case ERROR:
result.setSeverity(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.ERROR);
break;
case FATAL:
result.setSeverity(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.FATAL);
break;
case INFORMATION:
result.setSeverity(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.INFORMATION);
break;
case WARNING:
result.setSeverity(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.WARNING);
break;
}
result.setCode(type);
result.addLocation(location);
result.getDetails().setText(message);
ArrayList<OperationOutcomeIssueComponent> list = new ArrayList<>();
list.add(result);
return list;
}
public void checkCanonical(List<OperationOutcomeIssueComponent> issues, String path, CanonicalResource resource) {
if (resource != null) {
StandardsStatus standardsStatus = ToolingExtensions.getStandardsStatus(resource);
if (standardsStatus == StandardsStatus.DEPRECATED) {
addToIssues(issues, makeStatusIssue(path, "deprecated", I18nConstants.MSG_DEPRECATED, resource));
} else if (standardsStatus == StandardsStatus.WITHDRAWN) {
addToIssues(issues, makeStatusIssue(path, "withdrawn", I18nConstants.MSG_WITHDRAWN, resource));
} else if (resource.getStatus() == PublicationStatus.RETIRED) {
addToIssues(issues, makeStatusIssue(path, "retired", I18nConstants.MSG_RETIRED, resource));
}
}
}
private List<OperationOutcomeIssueComponent> makeStatusIssue(String path, String id, String msg, CanonicalResource resource) {
List<OperationOutcomeIssueComponent> iss = makeIssue(IssueSeverity.INFORMATION, IssueType.EXPIRED, path, context.formatMessage(msg, resource.getVersionedUrl()));
// this is a testing hack - see TerminologyServiceTests
iss.get(0).setUserData("status-msg-name", "warning-"+id);
iss.get(0).setUserData("status-msg-value", new UriType(resource.getVersionedUrl()));
return iss;
}
private void addToIssues(List<OperationOutcomeIssueComponent> issues, List<OperationOutcomeIssueComponent> toAdd) {
for (OperationOutcomeIssueComponent t : toAdd) {
boolean found = false;
for (OperationOutcomeIssueComponent i : issues) {
if (i.getSeverity() == t.getSeverity() && i.getCode() == t.getCode() && i.getDetails().getText().equals(t.getDetails().getText())) { // ignore location
found = true;
}
}
if (!found) {
issues.add(t);
}
}
}
public void checkCanonical(ValueSetExpansionComponent params, CanonicalResource resource) {
if (resource != null) {
StandardsStatus standardsStatus = ToolingExtensions.getStandardsStatus(resource);
if (standardsStatus == StandardsStatus.DEPRECATED) {
if (!params.hasParameterValue("warning-deprecated", resource.getVersionedUrl())) {
params.addParameter("warning-deprecated", new UriType(resource.getVersionedUrl()));
}
} else if (standardsStatus == StandardsStatus.WITHDRAWN) {
if (!params.hasParameterValue("warning-withdrawn", resource.getVersionedUrl())) {
params.addParameter("warning-withdrawn", new UriType(resource.getVersionedUrl()));
}
} else if (resource.getStatus() == PublicationStatus.RETIRED) {
if (!params.hasParameterValue("warning-retired", resource.getVersionedUrl())) {
params.addParameter("warning-retired", new UriType(resource.getVersionedUrl()));
}
}
}
}
protected AlternateCodesProcessingRules altCodeParams = new AlternateCodesProcessingRules(false);
protected AlternateCodesProcessingRules allAltCodes = new AlternateCodesProcessingRules(true);
}

View File

@ -29,7 +29,7 @@ public class ValidationProcessInfo {
return issues;
}
public void addIssue(List<OperationOutcomeIssueComponent> issues) {
issues.addAll(issues);
this.issues.addAll(issues);
}
public boolean hasErrors() {

View File

@ -97,7 +97,6 @@ import com.google.j2objc.annotations.ReflectionSupport.Level;
public class ValueSetValidator extends ValueSetProcessBase {
private ValueSet valueset;
private IWorkerContext context;
private Map<String, ValueSetValidator> inner = new HashMap<>();
private ValidationOptions options;
private ValidationContextCarrier localContext;
@ -215,7 +214,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
}
} else {
c.setUserData("cs", cs);
res = validateCode(path+".coding["+i+"]", c, cs, vcc);
res = validateCode(path+".coding["+i+"]", c, cs, vcc, info);
}
info.getIssues().addAll(res.getIssues());
i++;
@ -229,7 +228,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
for (Coding c : code.getCoding()) {
b.append(c.getSystem()+(c.hasVersion() ? "|"+c.getVersion() : "")+"#"+c.getCode());
Boolean ok = codeInValueSet(c.getSystem(), c.getVersion(), c.getCode(), info);
Boolean ok = codeInValueSet(path, c.getSystem(), c.getVersion(), c.getCode(), info);
if (ok == null && result != null && result == false) {
result = null;
} else if (ok != null && ok) {
@ -338,30 +337,6 @@ public class ValueSetValidator extends ValueSetProcessBase {
return versionTest == null && VersionUtilities.versionsMatch(versionTest, versionActual);
}
private List<OperationOutcomeIssueComponent> makeIssue(IssueSeverity level, IssueType type, String location, String message) {
OperationOutcomeIssueComponent result = new OperationOutcomeIssueComponent();
switch (level) {
case ERROR:
result.setSeverity(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.ERROR);
break;
case FATAL:
result.setSeverity(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.FATAL);
break;
case INFORMATION:
result.setSeverity(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.INFORMATION);
break;
case WARNING:
result.setSeverity(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.WARNING);
break;
}
result.setCode(type);
result.addLocation(location);
result.getDetails().setText(message);
ArrayList<OperationOutcomeIssueComponent> list = new ArrayList<>();
list.add(result);
return list;
}
public ValidationResult validateCode(Coding code) throws FHIRException {
return validateCode("Coding", code);
}
@ -374,7 +349,9 @@ public class ValueSetValidator extends ValueSetProcessBase {
boolean inExpansion = false;
boolean inInclude = false;
List<OperationOutcomeIssueComponent> issues = new ArrayList<>();
ValidationProcessInfo info = new ValidationProcessInfo(issues);
VersionInfo vi = new VersionInfo(this);
checkCanonical(issues, path, valueset);
String system = code.hasSystem() ? code.getSystem() : getValueSetSystemOrNull();
if (options.getValueSetMode() != ValueSetMode.CHECK_MEMERSHIP_ONLY) {
@ -434,6 +411,8 @@ public class ValueSetValidator extends ValueSetProcessBase {
}
}
}
} else {
checkCanonical(issues, path, cs);
}
if (cs != null && cs.hasSupplements()) {
String msg = context.formatMessage(I18nConstants.CODESYSTEM_CS_NO_SUPPLEMENT, cs.getUrl());
@ -461,7 +440,8 @@ public class ValueSetValidator extends ValueSetProcessBase {
// we can't validate that here.
throw new FHIRException("Unable to evaluate based on empty code system");
}
res = validateCode(path, code, cs, null);
res = validateCode(path, code, cs, null, info);
res.setIssues(issues);
} else if (cs == null && valueset.hasExpansion() && inExpansion) {
// we just take the value set as face value then
res = new ValidationResult(system, wv, new ConceptDefinitionComponent().setCode(code.getCode()).setDisplay(code.getDisplay()), code.getDisplay());
@ -481,12 +461,11 @@ public class ValueSetValidator extends ValueSetProcessBase {
}
String wv = vi.getVersion(system, code.getVersion());
ValidationProcessInfo info = new ValidationProcessInfo(issues);
// then, if we have a value set, we check it's in the value set
if (valueset != null && options.getValueSetMode() != ValueSetMode.NO_MEMBERSHIP_CHECK) {
if ((res==null || res.isOk())) {
Boolean ok = codeInValueSet(system, wv, code.getCode(), info);
Boolean ok = codeInValueSet(path, system, wv, code.getCode(), info);
if (ok == null || !ok) {
if (res == null) {
res = new ValidationResult((IssueSeverity) null, null, info.getIssues());
@ -654,7 +633,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
return false;
}
private ValidationResult validateCode(String path, Coding code, CodeSystem cs, CodeableConcept vcc) {
private ValidationResult validateCode(String path, Coding code, CodeSystem cs, CodeableConcept vcc, ValidationProcessInfo info) {
ConceptDefinitionComponent cc = cs.hasUserData("tx.cs.special") ? ((SpecialCodeSystem) cs.getUserData("tx.cs.special")).findConcept(code) : findCodeInConcept(cs.getConcept(), code.getCode(), allAltCodes);
if (cc == null) {
if (cs.getContent() == CodeSystemContentMode.FRAGMENT) {
@ -669,6 +648,10 @@ public class ValueSetValidator extends ValueSetProcessBase {
if (vcc != null) {
vcc.addCoding(vc);
}
if (CodeSystemUtilities.isInactive(cs, cc)) {
info.addIssue(makeIssue(IssueSeverity.WARNING, IssueType.EXPIRED, path, context.formatMessage(I18nConstants.INACTIVE_CODE_WARNING, cc.getCode())));
}
boolean ws = false;
if (code.getDisplay() == null) {
return new ValidationResult(code.getSystem(), cs.getVersion(), cc, vc.getDisplay());
}
@ -677,14 +660,20 @@ public class ValueSetValidator extends ValueSetProcessBase {
b.append("'"+cc.getDisplay()+"'");
if (code.getDisplay().equalsIgnoreCase(cc.getDisplay())) {
return new ValidationResult(code.getSystem(), cs.getVersion(), cc, getPreferredDisplay(cc, cs));
} else if (Utilities.normalize(code.getDisplay()).equals(Utilities.normalize(cc.getDisplay()))) {
ws = true;
}
}
for (ConceptDefinitionDesignationComponent ds : cc.getDesignation()) {
if (isOkLanguage(ds.getLanguage())) {
b.append("'"+ds.getValue()+"'");
if (code.getDisplay().equalsIgnoreCase(ds.getValue())) {
return new ValidationResult(code.getSystem(),cs.getVersion(), cc, getPreferredDisplay(cc, cs));
}
if (Utilities.normalize(code.getDisplay()).equalsIgnoreCase(Utilities.normalize(ds.getValue()))) {
ws = true;
}
}
}
// also check to see if the value set has another display
@ -711,7 +700,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
String msg = context.formatMessagePlural(options.getLanguages().size(), I18nConstants.NO_VALID_DISPLAY_FOUND, code.getSystem(), code.getCode(), code.getDisplay(), options.langSummary());
return new ValidationResult(IssueSeverity.WARNING, msg, code.getSystem(), cs.getVersion(), cc, getPreferredDisplay(cc, cs), makeIssue(IssueSeverity.WARNING, IssueType.INVALID, path+".display", msg));
} else {
String msg = context.formatMessagePlural(b.count(), I18nConstants.DISPLAY_NAME_FOR__SHOULD_BE_ONE_OF__INSTEAD_OF, code.getSystem(), code.getCode(), b.toString(), code.getDisplay(), options.langSummary());
String msg = context.formatMessagePlural(b.count(), ws ? I18nConstants.DISPLAY_NAME_WS_FOR__SHOULD_BE_ONE_OF__INSTEAD_OF : I18nConstants.DISPLAY_NAME_FOR__SHOULD_BE_ONE_OF__INSTEAD_OF, code.getSystem(), code.getCode(), b.toString(), code.getDisplay(), options.langSummary());
return new ValidationResult(dispWarningStatus(), msg, code.getSystem(), cs.getVersion(), cc, getPreferredDisplay(cc, cs), makeIssue(dispWarning(), IssueType.INVALID, path+".display", msg));
}
}
@ -982,14 +971,11 @@ public class ValueSetValidator extends ValueSetProcessBase {
return true;
}
public Boolean codeInValueSet(String system, String version, String code, ValidationProcessInfo info) throws FHIRException {
return codeInValueSet("code", system, version, code, info);
}
public Boolean codeInValueSet(String path, String system, String version, String code, ValidationProcessInfo info) throws FHIRException {
if (valueset == null) {
return false;
}
checkCanonical(info.getIssues(), path, valueset);
Boolean result = false;
VersionInfo vi = new VersionInfo(this);
@ -1029,15 +1015,15 @@ public class ValueSetValidator extends ValueSetProcessBase {
if (isValueSetUnionImports()) {
ok = false;
for (UriType uri : vsi.getValueSet()) {
if (inImport(uri.getValue(), system, version, code)) {
if (inImport(path, uri.getValue(), system, version, code, info)) {
return true;
}
}
} else {
ok = inImport(vsi.getValueSet().get(0).getValue(), system, version, code);
ok = inImport(path, vsi.getValueSet().get(0).getValue(), system, version, code, info);
for (int i = 1; i < vsi.getValueSet().size(); i++) {
UriType uri = vsi.getValueSet().get(i);
ok = ok && inImport(uri.getValue(), system, version, code);
ok = ok && inImport(path, uri.getValue(), system, version, code, info);
}
}
}
@ -1097,6 +1083,13 @@ public class ValueSetValidator extends ValueSetProcessBase {
return null;
}
} else {
checkCanonical(info.getIssues(), path, cs);
if (valueset.getCompose().hasInactive() && !valueset.getCompose().getInactive()) {
if (CodeSystemUtilities.isInactive(cs, code)) {
return false;
}
}
if (vsi.hasFilter()) {
ok = true;
for (ConceptSetFilterComponent f : vsi.getFilter()) {
@ -1231,12 +1224,12 @@ public class ValueSetValidator extends ValueSetProcessBase {
return vsc;
}
private boolean inImport(String uri, String system, String version, String code) throws FHIRException {
private boolean inImport(String path, String uri, String system, String version, String code, ValidationProcessInfo info) throws FHIRException {
ValueSetValidator vs = getVs(uri);
if (vs == null) {
return false;
} else {
Boolean ok = vs.codeInValueSet(system, version, code, null);
Boolean ok = vs.codeInValueSet(path, system, version, code, info);
return ok != null && ok;
}
}

View File

@ -45,7 +45,7 @@ public class CompareUtilities extends BaseTestingUtilities {
String result = compareXml(expected, actual);
if (result != null && SHOW_DIFF) {
String diff = getDiffTool();
if (new File(diff).exists() || Utilities.isToken(diff)) {
if (diff != null && new File(diff).exists() || Utilities.isToken(diff)) {
Runtime.getRuntime().exec(new String[]{diff, expected, actual});
}
}

View File

@ -668,7 +668,7 @@ public class FHIRPathEngine {
if (sd == null) {
throw makeException(expr, I18nConstants.FHIRPATH_UNKNOWN_CONTEXT, t);
}
types = new TypeDetails(CollectionStatus.SINGLETON, sd.getUrl());
types.addType(sd.getUrl());
} else {
String ctxt = t.substring(0, t.indexOf('.'));
StructureDefinition sd = cu.findType(ctxt);
@ -680,11 +680,10 @@ public class FHIRPathEngine {
throw makeException(expr, I18nConstants.FHIRPATH_UNKNOWN_CONTEXT_ELEMENT, t);
}
if (ed.fixedType != null) {
types = new TypeDetails(CollectionStatus.SINGLETON, ed.fixedType);
types.addType(ed.fixedType);
} else if (ed.getDefinition().getType().isEmpty() || isAbstractType(ed.getDefinition().getType())) {
types = new TypeDetails(CollectionStatus.SINGLETON, sd.getType()+"#"+t);
types.addType(sd.getType()+"#"+t);
} else {
types = new TypeDetails(CollectionStatus.SINGLETON);
for (TypeRefComponent tt : ed.getDefinition().getType()) {
types.addType(tt.getCode());
}
@ -3545,7 +3544,7 @@ public class FHIRPathEngine {
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_DateTime);
case Resolve : {
checkContextReference(focus, "resolve", exp);
return new TypeDetails(CollectionStatus.ORDERED, "DomainResource");
return new TypeDetails(focus.getCollectionStatus(), "Resource");
}
case Extension : {
checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String));

View File

@ -256,4 +256,34 @@ public class XVerExtensionManager {
return v.length() == 3 && Character.isDigit(v.charAt(0)) && v.charAt(1) == '.' && Character.isDigit(v.charAt(2));
}
public String getReference(String url) {
String version = getVersion(url);
String base = VersionUtilities.getSpecUrl(version);
if (base == null) {
return null;
} else {
String path = url.substring(url.indexOf("-")+1);
if (!path.contains(".")) {
return null;
}
String type = path.substring(0, path.indexOf("."));
if (Utilities.existsInList(type, "Annotation", "Attachment", "Identifier", "CodeableConcept", "Coding", "Quantity", "Duration", "Range", "Period", "Ratio", "RatioRange", "SampledData", "Signature", "HumanName", "Address", "ContactPoint", "Timing")) {
return Utilities.pathURL(base, "datatypes-definitions.html#"+path+"|"+VersionUtilities.getNameForVersion(version)+" "+path);
}
if (Utilities.existsInList(type, "Element", "BackboneElement", "BackboneType", "PrimitiveType", "DataType", "Base")) {
return Utilities.pathURL(base, "types-definitions.html#"+path+"|"+VersionUtilities.getNameForVersion(version)+" "+path);
}
if (Utilities.existsInList(type, "UsageContext", "RelatedArtifact", "DataRequirement", "ParameterDefinition", "TriggerDefinition", "Expression", "ContactDetail", "ExtendedContactDetail", "VirtualServiceDetail", "Availability", "MonetaryComponent", "Contributor")) {
return Utilities.pathURL(base, "metadatatypes-definitions.html#"+path+"|"+VersionUtilities.getNameForVersion(version)+" "+path);
}
if (Utilities.existsInList(type, "Reference", "CodeableReference")) {
return Utilities.pathURL(base, "references-definitions.html#"+path+"|"+VersionUtilities.getNameForVersion(version)+" "+path);
}
if (Utilities.existsInList(type, "Meta")) {
return Utilities.pathURL(base, "resource-definitions.html#"+path+"|"+VersionUtilities.getNameForVersion(version)+" "+path);
}
return Utilities.pathURL(base, type.toLowerCase()+"-definitions.html#"+path+"|"+VersionUtilities.getNameForVersion(version)+" "+path);
}
}
}

View File

@ -149,7 +149,7 @@ public class TerminologyCacheTests implements ResourceLoaderTests {
assertCanonicalResourceEquals(terminologyCapabilities, terminologyCacheB.getTerminologyCapabilities());
assertCanonicalResourceEquals(capabilityStatement, terminologyCacheB.getCapabilityStatement());
assertValidationResultEquals(codingResultA, terminologyCacheB.getValidation( terminologyCacheA.generateValidationToken(CacheTestUtils.validationOptions, coding, valueSet, new Parameters())));
assertValidationResultEquals(codingResultA, terminologyCacheB.getValidation(terminologyCacheA.generateValidationToken(CacheTestUtils.validationOptions, coding, valueSet, new Parameters())));
assertValidationResultEquals(codeableConceptResultA, terminologyCacheB.getValidation(terminologyCacheA.generateValidationToken(CacheTestUtils.validationOptions, concept, valueSet, new Parameters())));
assertExpansionOutcomeEquals(expansionOutcomeA,terminologyCacheB.getExpansion(terminologyCacheA.generateExpandToken(valueSet, true)));
}

View File

@ -12,3 +12,42 @@ e: {
"error" : "Cannot invoke \"org.hl7.fhir.r5.terminologies.client.ITerminologyClient.expandValueset(org.hl7.fhir.r5.model.ValueSet, org.hl7.fhir.r5.model.Parameters, java.util.Map)\" because the return value of \"org.hl7.fhir.r5.terminologies.client.TerminologyClientContext.getClient()\" is null"
}
-------------------------------------------------------------------------------------
{"hierarchical" : false, "valueSet" :{
"resourceType" : "ValueSet",
"compose" : {
"inactive" : true,
"include" : [{
"system" : "urn:ietf:bcp:47"
}]
}
}}####
e: {
"error" : "Cannot invoke \"org.hl7.fhir.r5.terminologies.client.ITerminologyClient.expandValueset(org.hl7.fhir.r5.model.ValueSet, org.hl7.fhir.r5.model.Parameters, java.util.Map)\" because the return value of \"org.hl7.fhir.r5.terminologies.client.TerminologyClientContext.getClient()\" is null"
}
-------------------------------------------------------------------------------------
{"hierarchical" : false, "valueSet" :{
"resourceType" : "ValueSet",
"compose" : {
"inactive" : true,
"include" : [{
"system" : "urn:ietf:bcp:47"
}]
}
}}####
e: {
"error" : "Cannot invoke \"org.hl7.fhir.r5.terminologies.client.ITerminologyClient.expandValueset(org.hl7.fhir.r5.model.ValueSet, org.hl7.fhir.r5.model.Parameters, java.util.Map)\" because the return value of \"org.hl7.fhir.r5.terminologies.client.TerminologyClientContext.getClient()\" is null"
}
-------------------------------------------------------------------------------------
{"hierarchical" : false, "valueSet" :{
"resourceType" : "ValueSet",
"compose" : {
"inactive" : true,
"include" : [{
"system" : "urn:ietf:bcp:47"
}]
}
}}####
e: {
"error" : "Cannot invoke \"org.hl7.fhir.r5.terminologies.client.ITerminologyClient.expandValueset(org.hl7.fhir.r5.model.ValueSet, org.hl7.fhir.r5.model.Parameters, java.util.Map)\" because the return value of \"org.hl7.fhir.r5.terminologies.client.TerminologyClientContext.getClient()\" is null"
}
-------------------------------------------------------------------------------------

View File

@ -44,3 +44,138 @@ e: {
"error" : "Cannot invoke \"org.hl7.fhir.r5.terminologies.client.ITerminologyClient.expandValueset(org.hl7.fhir.r5.model.ValueSet, org.hl7.fhir.r5.model.Parameters, java.util.Map)\" because the return value of \"org.hl7.fhir.r5.terminologies.client.TerminologyClientContext.getClient()\" is null"
}
-------------------------------------------------------------------------------------
{"hierarchical" : false, "valueSet" :{
"resourceType" : "ValueSet",
"compose" : {
"inactive" : true,
"include" : [{
"system" : "http://loinc.org",
"concept" : [{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-label",
"valueString" : "A."
}],
"code" : "LA20752-4",
"display" : "Within 24 hours"
},
{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-label",
"valueString" : "B."
}],
"code" : "LA20753-2",
"display" : "After 24 hours but before 3 days"
},
{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-label",
"valueString" : "C."
}],
"code" : "LA20754-0",
"display" : "Three days or later"
},
{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-label",
"valueString" : "D."
}],
"code" : "LA4489-6",
"display" : "Unknown"
}]
}]
}
}}####
e: {
"error" : "Cannot invoke \"org.hl7.fhir.r5.terminologies.client.ITerminologyClient.expandValueset(org.hl7.fhir.r5.model.ValueSet, org.hl7.fhir.r5.model.Parameters, java.util.Map)\" because the return value of \"org.hl7.fhir.r5.terminologies.client.TerminologyClientContext.getClient()\" is null"
}
-------------------------------------------------------------------------------------
{"hierarchical" : false, "valueSet" :{
"resourceType" : "ValueSet",
"compose" : {
"inactive" : true,
"include" : [{
"system" : "http://loinc.org",
"concept" : [{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-label",
"valueString" : "A."
}],
"code" : "LA20752-4",
"display" : "Within 24 hours"
},
{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-label",
"valueString" : "B."
}],
"code" : "LA20753-2",
"display" : "After 24 hours but before 3 days"
},
{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-label",
"valueString" : "C."
}],
"code" : "LA20754-0",
"display" : "Three days or later"
},
{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-label",
"valueString" : "D."
}],
"code" : "LA4489-6",
"display" : "Unknown"
}]
}]
}
}}####
e: {
"error" : "Cannot invoke \"org.hl7.fhir.r5.terminologies.client.ITerminologyClient.expandValueset(org.hl7.fhir.r5.model.ValueSet, org.hl7.fhir.r5.model.Parameters, java.util.Map)\" because the return value of \"org.hl7.fhir.r5.terminologies.client.TerminologyClientContext.getClient()\" is null"
}
-------------------------------------------------------------------------------------
{"hierarchical" : false, "valueSet" :{
"resourceType" : "ValueSet",
"compose" : {
"inactive" : true,
"include" : [{
"system" : "http://loinc.org",
"concept" : [{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-label",
"valueString" : "A."
}],
"code" : "LA20752-4",
"display" : "Within 24 hours"
},
{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-label",
"valueString" : "B."
}],
"code" : "LA20753-2",
"display" : "After 24 hours but before 3 days"
},
{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-label",
"valueString" : "C."
}],
"code" : "LA20754-0",
"display" : "Three days or later"
},
{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-label",
"valueString" : "D."
}],
"code" : "LA4489-6",
"display" : "Unknown"
}]
}]
}
}}####
e: {
"error" : "Cannot invoke \"org.hl7.fhir.r5.terminologies.client.ITerminologyClient.expandValueset(org.hl7.fhir.r5.model.ValueSet, org.hl7.fhir.r5.model.Parameters, java.util.Map)\" because the return value of \"org.hl7.fhir.r5.terminologies.client.TerminologyClientContext.getClient()\" is null"
}
-------------------------------------------------------------------------------------

View File

@ -12,3 +12,42 @@ e: {
"error" : "Cannot invoke \"org.hl7.fhir.r5.terminologies.client.ITerminologyClient.expandValueset(org.hl7.fhir.r5.model.ValueSet, org.hl7.fhir.r5.model.Parameters, java.util.Map)\" because the return value of \"org.hl7.fhir.r5.terminologies.client.TerminologyClientContext.getClient()\" is null"
}
-------------------------------------------------------------------------------------
{"hierarchical" : false, "valueSet" :{
"resourceType" : "ValueSet",
"compose" : {
"inactive" : true,
"include" : [{
"system" : "urn:ietf:bcp:13"
}]
}
}}####
e: {
"error" : "Cannot invoke \"org.hl7.fhir.r5.terminologies.client.ITerminologyClient.expandValueset(org.hl7.fhir.r5.model.ValueSet, org.hl7.fhir.r5.model.Parameters, java.util.Map)\" because the return value of \"org.hl7.fhir.r5.terminologies.client.TerminologyClientContext.getClient()\" is null"
}
-------------------------------------------------------------------------------------
{"hierarchical" : false, "valueSet" :{
"resourceType" : "ValueSet",
"compose" : {
"inactive" : true,
"include" : [{
"system" : "urn:ietf:bcp:13"
}]
}
}}####
e: {
"error" : "Cannot invoke \"org.hl7.fhir.r5.terminologies.client.ITerminologyClient.expandValueset(org.hl7.fhir.r5.model.ValueSet, org.hl7.fhir.r5.model.Parameters, java.util.Map)\" because the return value of \"org.hl7.fhir.r5.terminologies.client.TerminologyClientContext.getClient()\" is null"
}
-------------------------------------------------------------------------------------
{"hierarchical" : false, "valueSet" :{
"resourceType" : "ValueSet",
"compose" : {
"inactive" : true,
"include" : [{
"system" : "urn:ietf:bcp:13"
}]
}
}}####
e: {
"error" : "Cannot invoke \"org.hl7.fhir.r5.terminologies.client.ITerminologyClient.expandValueset(org.hl7.fhir.r5.model.ValueSet, org.hl7.fhir.r5.model.Parameters, java.util.Map)\" because the return value of \"org.hl7.fhir.r5.terminologies.client.TerminologyClientContext.getClient()\" is null"
}
-------------------------------------------------------------------------------------

View File

@ -96,3 +96,294 @@ e: {
"error" : "Cannot invoke \"org.hl7.fhir.r5.terminologies.client.ITerminologyClient.expandValueset(org.hl7.fhir.r5.model.ValueSet, org.hl7.fhir.r5.model.Parameters, java.util.Map)\" because the return value of \"org.hl7.fhir.r5.terminologies.client.TerminologyClientContext.getClient()\" is null"
}
-------------------------------------------------------------------------------------
{"hierarchical" : false, "valueSet" :{
"resourceType" : "ValueSet",
"compose" : {
"inactive" : true,
"include" : [{
"system" : "http://unitsofmeasure.org",
"concept" : [{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition",
"valueString" : "second"
}],
"code" : "s",
"display" : "second",
"designation" : [{
"language" : "zh",
"value" : "秒"
}]
},
{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition",
"valueString" : "minute"
}],
"code" : "min",
"display" : "minute",
"designation" : [{
"language" : "zh",
"value" : "分钟"
}]
},
{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition",
"valueString" : "hour"
}],
"code" : "h",
"display" : "hour",
"designation" : [{
"language" : "zh",
"value" : "小时"
}]
},
{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition",
"valueString" : "day"
}],
"code" : "d",
"display" : "day",
"designation" : [{
"language" : "zh",
"value" : "天"
}]
},
{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition",
"valueString" : "week"
}],
"code" : "wk",
"display" : "week",
"designation" : [{
"language" : "zh",
"value" : "星期"
}]
},
{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition",
"valueString" : "month - Normal practice is to use the 'mo' code as a calendar month when calculating the next occurrence."
}],
"code" : "mo",
"display" : "month",
"designation" : [{
"language" : "zh",
"value" : "月"
}]
},
{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition",
"valueString" : "year"
}],
"code" : "a",
"display" : "year",
"designation" : [{
"language" : "zh",
"value" : "年"
}]
}]
}]
}
}}####
e: {
"error" : "Cannot invoke \"org.hl7.fhir.r5.terminologies.client.ITerminologyClient.expandValueset(org.hl7.fhir.r5.model.ValueSet, org.hl7.fhir.r5.model.Parameters, java.util.Map)\" because the return value of \"org.hl7.fhir.r5.terminologies.client.TerminologyClientContext.getClient()\" is null"
}
-------------------------------------------------------------------------------------
{"hierarchical" : false, "valueSet" :{
"resourceType" : "ValueSet",
"compose" : {
"inactive" : true,
"include" : [{
"system" : "http://unitsofmeasure.org",
"concept" : [{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition",
"valueString" : "second"
}],
"code" : "s",
"display" : "second",
"designation" : [{
"language" : "zh",
"value" : "秒"
}]
},
{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition",
"valueString" : "minute"
}],
"code" : "min",
"display" : "minute",
"designation" : [{
"language" : "zh",
"value" : "分钟"
}]
},
{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition",
"valueString" : "hour"
}],
"code" : "h",
"display" : "hour",
"designation" : [{
"language" : "zh",
"value" : "小时"
}]
},
{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition",
"valueString" : "day"
}],
"code" : "d",
"display" : "day",
"designation" : [{
"language" : "zh",
"value" : "天"
}]
},
{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition",
"valueString" : "week"
}],
"code" : "wk",
"display" : "week",
"designation" : [{
"language" : "zh",
"value" : "星期"
}]
},
{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition",
"valueString" : "month - Normal practice is to use the 'mo' code as a calendar month when calculating the next occurrence."
}],
"code" : "mo",
"display" : "month",
"designation" : [{
"language" : "zh",
"value" : "月"
}]
},
{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition",
"valueString" : "year"
}],
"code" : "a",
"display" : "year",
"designation" : [{
"language" : "zh",
"value" : "年"
}]
}]
}]
}
}}####
e: {
"error" : "Cannot invoke \"org.hl7.fhir.r5.terminologies.client.ITerminologyClient.expandValueset(org.hl7.fhir.r5.model.ValueSet, org.hl7.fhir.r5.model.Parameters, java.util.Map)\" because the return value of \"org.hl7.fhir.r5.terminologies.client.TerminologyClientContext.getClient()\" is null"
}
-------------------------------------------------------------------------------------
{"hierarchical" : false, "valueSet" :{
"resourceType" : "ValueSet",
"compose" : {
"inactive" : true,
"include" : [{
"system" : "http://unitsofmeasure.org",
"concept" : [{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition",
"valueString" : "second"
}],
"code" : "s",
"display" : "second",
"designation" : [{
"language" : "zh",
"value" : "秒"
}]
},
{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition",
"valueString" : "minute"
}],
"code" : "min",
"display" : "minute",
"designation" : [{
"language" : "zh",
"value" : "分钟"
}]
},
{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition",
"valueString" : "hour"
}],
"code" : "h",
"display" : "hour",
"designation" : [{
"language" : "zh",
"value" : "小时"
}]
},
{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition",
"valueString" : "day"
}],
"code" : "d",
"display" : "day",
"designation" : [{
"language" : "zh",
"value" : "天"
}]
},
{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition",
"valueString" : "week"
}],
"code" : "wk",
"display" : "week",
"designation" : [{
"language" : "zh",
"value" : "星期"
}]
},
{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition",
"valueString" : "month - Normal practice is to use the 'mo' code as a calendar month when calculating the next occurrence."
}],
"code" : "mo",
"display" : "month",
"designation" : [{
"language" : "zh",
"value" : "月"
}]
},
{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition",
"valueString" : "year"
}],
"code" : "a",
"display" : "year",
"designation" : [{
"language" : "zh",
"value" : "年"
}]
}]
}]
}
}}####
e: {
"error" : "Cannot invoke \"org.hl7.fhir.r5.terminologies.client.ITerminologyClient.expandValueset(org.hl7.fhir.r5.model.ValueSet, org.hl7.fhir.r5.model.Parameters, java.util.Map)\" because the return value of \"org.hl7.fhir.r5.terminologies.client.TerminologyClientContext.getClient()\" is null"
}
-------------------------------------------------------------------------------------

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>6.0.24-SNAPSHOT</version>
<version>6.0.26-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>6.0.24-SNAPSHOT</version>
<version>6.0.26-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -65,8 +65,9 @@ public class CSFile extends File {
//attempt to open a file triggers a directory listing
if (exists())
{
if(!this.getCanonicalFile().getName().equals(this.getName()))
if(!this.getCanonicalFile().getName().equals(this.getName())) {
throw new Error("Case mismatch of file "+ pathname+": found "+this.getCanonicalFile().getName());
}
}
}

View File

@ -35,7 +35,7 @@ import org.hl7.fhir.exceptions.FHIRException;
public enum StandardsStatus {
EXTERNAL, INFORMATIVE, DRAFT, TRIAL_USE, DEPRECATED, NORMATIVE;
EXTERNAL, INFORMATIVE, DRAFT, TRIAL_USE, DEPRECATED, NORMATIVE, WITHDRAWN;
public String toDisplay() {
switch (this) {
@ -51,6 +51,8 @@ public enum StandardsStatus {
return "External";
case DEPRECATED:
return "Deprecated";
case WITHDRAWN:
return "Withdrawn";
}
return "?";
}
@ -66,9 +68,11 @@ public enum StandardsStatus {
case INFORMATIVE:
return "informative";
case DEPRECATED:
return "deprecated";
return "deprecated";
case EXTERNAL:
return "external";
case WITHDRAWN:
return "Withdrawn";
}
return "?";
}
@ -93,6 +97,8 @@ public enum StandardsStatus {
return EXTERNAL;
if (value.equalsIgnoreCase("DEPRECATED"))
return DEPRECATED;
if (value.equalsIgnoreCase("WITHDRAWN"))
return WITHDRAWN;
throw new FHIRException("Incorrect Standards Status '"+value+"'");
}
@ -110,6 +116,8 @@ public enum StandardsStatus {
return "XD";
case EXTERNAL:
return "X";
case WITHDRAWN:
return "W";
}
return "?";
}
@ -125,6 +133,7 @@ public enum StandardsStatus {
case INFORMATIVE:
return "#ffffe6";
case DEPRECATED:
case WITHDRAWN:
return "#ffcccc";
case EXTERNAL:
return "#e6ffff";
@ -143,6 +152,7 @@ public enum StandardsStatus {
case INFORMATIVE:
return "#ffffec";
case DEPRECATED:
case WITHDRAWN:
return "#ffcccc";
case EXTERNAL:
return "#ecffff";
@ -159,6 +169,8 @@ public enum StandardsStatus {
return (tgtSS == NORMATIVE || tgtSS == EXTERNAL );
if (this == DEPRECATED)
return (tgtSS == DEPRECATED );
if (this == WITHDRAWN)
return (tgtSS == WITHDRAWN );
return false;
}

View File

@ -307,7 +307,18 @@ public class Utilities {
CSFile src = new CSFile(sourceFolder);
if (!src.exists())
throw new FHIRException("Folder " + sourceFolder + " not found");
createDirectory(destFolder);
File dst = new File(destFolder);
if(!dst.getCanonicalFile().getName().equals(dst.getName())) {
File tmp = new File(destFolder+System.currentTimeMillis());
if (!dst.renameTo(tmp)) {
throw new IOException("fixing case from "+dst.getCanonicalFile().getName()+" to "+tmp.getName()+" failed");
}
if (!tmp.renameTo(dst)) {
throw new IOException("fixing case from "+tmp.getCanonicalFile().getName()+" to "+dst.getName()+" failed");
}
} else if (!dst.exists()) {
createDirectory(destFolder);
}
String[] files = src.list();
for (String f : files) {
@ -318,7 +329,7 @@ public class Utilities {
} else {
if (notifier != null)
notifier.copyFile(sourceFolder + File.separator + f, destFolder + File.separator + f);
copyFile(new CSFile(sourceFolder + File.separator + f), new CSFile(destFolder + File.separator + f));
copyFile(new CSFile(sourceFolder + File.separator + f), new /*CS*/File(destFolder + File.separator + f)); // case doesn't have to match on the target
}
}
}
@ -358,6 +369,10 @@ public class Utilities {
createDirectory(destFile.getParent());
}
destFile.createNewFile();
} else if (!destFile.getCanonicalFile().getName().equals(destFile.getName())) {
// case mismatch
destFile.delete();
destFile.createNewFile();
}
FileInputStream source = null;
@ -2112,4 +2127,8 @@ public class Utilities {
return url.contains("/") ? url.substring(url.lastIndexOf("/")+1) : url;
}
public static String escapeSql(String s) {
return s.replace("'", "''");
}
}

View File

@ -81,6 +81,7 @@ public class I18nConstants {
public static final String DISCRIMINATOR__IS_BASED_ON_TYPE_BUT_SLICE__IN__HAS_NO_TYPES = "Discriminator__is_based_on_type_but_slice__in__has_no_types";
public static final String DISCRIMINATOR_BAD_PATH = "DISCRIMINATOR_BAD_PATH";
public static final String DISPLAY_NAME_FOR__SHOULD_BE_ONE_OF__INSTEAD_OF = "Display_Name_for__should_be_one_of__instead_of";
public static final String DISPLAY_NAME_WS_FOR__SHOULD_BE_ONE_OF__INSTEAD_OF = "Display_Name_WS_for__should_be_one_of__instead_of";
public static final String DOCUMENT = "documentmsg";
public static final String DOCUMENT_DATE_REQUIRED = "Bundle_Document_Date_Missing";
public static final String DOCUMENT_DATE_REQUIRED_HTML = "Bundle_Document_Date_Missing_html";
@ -949,9 +950,12 @@ public class I18nConstants {
public static final String ED_INVARIANT_KEY_ALREADY_USED = "ED_INVARIANT_KEY_ALREADY_USED";
public static final String FHIRPATH_OFTYPE_IMPOSSIBLE = "FHIRPATH_OFTYPE_IMPOSSIBLE";
public static final String ED_SEARCH_EXPRESSION_ERROR = "ED_SEARCH_EXPRESSION_ERROR";
public static final String SD_EXTENSION_URL_MISMATCH = "SD_EXTENSION_URL_MISMATCH";
public static final String MSG_DEPRECATED = "MSG_DEPRECATED";
public static final String MSG_WITHDRAWN = "MSG_WITHDRAWN";
public static final String MSG_RETIRED = "MSG_RETIRED";
public static final String INACTIVE_CODE_WARNING = "INACTIVE_CODE_WARNING";
public static final String SD_EXTENSION_URL_MISSING = "SD_EXTENSION_URL_MISSING";
}

View File

@ -297,6 +297,7 @@ public class NpmPackage {
private Map<String, Object> userData;
private boolean minimalMemory;
private int size;
private boolean warned = false;
/**
* Constructor
@ -1266,6 +1267,11 @@ public class NpmPackage {
return Utilities.existsInList(npm.asString("type"), "fhir.core", "Core");
}
public boolean isCoreExamples() {
return name().startsWith("hl7.fhir.r") && name().endsWith(".examples");
}
public boolean isTx() {
return npm.asString("name").startsWith("hl7.terminology");
}
@ -1369,5 +1375,14 @@ public class NpmPackage {
public void setSize(int size) {
this.size = size;
}
public boolean isWarned() {
return warned;
}
public void setWarned(boolean warned) {
this.warned = warned;
}
}

View File

@ -859,6 +859,50 @@ public class ValidationMessage implements Comparator<ValidationMessage>, Compara
this.ignorableError = ignorableError;
return this;
}
public boolean matches(ValidationMessage other) {
if (location == null) {
if (other.location != null) {
return false;
}
} else {
String l1 = preprocessLocation(location);
String l2 = preprocessLocation(other.location);
if (!l1.equals(l2)) {
return false;
}
}
if (message == null) {
if (other.message != null) {
return false;
}
} else if (!message.equals(other.message)) {
return false;
}
if (messageId == null) {
if (other.messageId != null) {
return false;
}
} else if (!messageId.equals(other.messageId)) {
return false;
}
if (type != other.type) {
return false;
}
if (level != other.level) {
return false;
}
return true;
}
private String preprocessLocation(String loc) {
// some locations are prefixes with a location but they're not different since the location is fixed where .match is called from
if (loc.contains(": ")) {
return loc.substring(loc.indexOf(": ")+2);
}
return loc;
}
}

View File

@ -171,7 +171,7 @@ Terminology_TX_NoValid_13 = The Coding provided ({2}) is not in the value set {0
Terminology_TX_NoValid_14 = The Coding provided ({2}) is not in the value set {0}, and a code is recommended to come from this value set. {1}
Terminology_TX_NoValid_15 = The value provided (''{0}'') could not be validated in the absence of a terminology server
Terminology_TX_NoValid_15A = The value provided (''{0}'') could not be validated because the code system {1} is not known
Terminology_TX_NoValid_16 = The value provided (''{0}'') is not in the value set {1}, and a code is required from this value set){2}
Terminology_TX_NoValid_16 = The value provided (''{0}'') is not in the value set {1}, and a code is required from this value set {2}
Terminology_TX_NoValid_17 = The value provided (''{0}'') is not in the value set {1}, and a code should come from this value set unless it has no suitable code (note that the validator cannot judge what is suitable) {2}
Terminology_TX_NoValid_18 = The value provided (''{0}'') is not in the value set {1}, and a code is recommended to come from this value set){2}
Terminology_TX_NoValid_2_CC = None of the codings provided are in the value set {0}, and a coding should come from this value set unless it has no suitable code (note that the validator cannot judge what is suitable) (codes = {1})
@ -468,6 +468,8 @@ Error_parsing_ = Error parsing {0}:{1}
Unable_to_connect_to_terminology_server_Use_parameter_tx_na_tun_run_without_using_terminology_services_to_validate_LOINC_SNOMED_ICDX_etc_Error__ = Unable to connect to terminology server. Use parameter ''-tx n/a'' to run without using terminology services to validate LOINC, SNOMED, ICD-X etc. Error = {0}
Display_Name_for__should_be_one_of__instead_of_one = Wrong Display Name ''{4}'' for {1}#{2} - should be {3} (for the language(s) ''{5}'')
Display_Name_for__should_be_one_of__instead_of_other = Wrong Display Name ''{4}'' for {1}#{2} - should be one of {0} choices: {3} (for the language(s) ''{5}'')
Display_Name_WS_for__should_be_one_of__instead_of_one = Wrong whitespace in Display Name ''{4}'' for {1}#{2} - should be {3} (for the language(s) ''{5}'')
Display_Name_WS_for__should_be_one_of__instead_of_other = Wrong whitespace in Display Name ''{4}'' for {1}#{2} - should be one of {0} choices: {3} (for the language(s) ''{5}'')
Unknown_Code__in_ = Unknown Code ''{0}'' in the system ''{1}''
UNKNOWN_CODE__IN_FRAGMENT = Unknown Code ''{0}'' in the system ''{1}'' - note that the code system is labeled as a fragment, so the code may be valid in some other fragment
Code_found_in_expansion_however_ = Code found in expansion, however: {0}
@ -1004,4 +1006,11 @@ ED_INVARIANT_DIFF_NO_SOURCE = The invariant {0} defined in the differential must
FHIRPATH_COLLECTION_STATUS_OPERATION_LEFT = The left side is inherently a collection, and so the expression ''{0}'' may fail or return false if there is more than one item in the content being evaluated
FHIRPATH_COLLECTION_STATUS_OPERATION_RIGHT = The right side is inherently a collection, and so this expression ''{0}'' may fail or return false if there is more than one item in the content being evaluated
FHIRPATH_OFTYPE_IMPOSSIBLE = The type specified in ofType is {1} which is not a possible candidate for the existing types ({0}) in the expression {2}. Check the paths and types to be sure this is what is intended
ED_SEARCH_EXPRESSION_ERROR = Error in search expression ''{0}'': {1}
ED_SEARCH_EXPRESSION_ERROR = Error in search expression ''{0}'': {1}
SD_EXTENSION_URL_MISMATCH = The fixed value for the extension URL is {1} which doesn''t match the canonical URL {0}
SD_EXTENSION_URL_MISSING = The value of Extension.url is not fixed to the extension URL {0}
MSG_DEPRECATED = Reference to deprecated item {0}
MSG_WITHDRAWN = Reference to withdrawn item {0}
MSG_RETIRED = Reference to retired item {0}
INACTIVE_CODE_WARNING = The code ''{0}'' is valid but is not active
SD_ED_TYPE_PROFILE_WRONG_TYPE = The type {0} is not in the list of allowed types {1} in the profile {2}

View File

@ -831,4 +831,7 @@ PRIMITIVE_VALUE_ALTERNATIVES_MESSAGE_many =
PRIMITIVE_VALUE_ALTERNATIVES_MESSAGE_other =
UNICODE_XML_BAD_CHARS_one =
UNICODE_XML_BAD_CHARS_many =
UNICODE_XML_BAD_CHARS_other =
UNICODE_XML_BAD_CHARS_other =
Display_Name_WS_for__should_be_one_of__instead_of_one =
Display_Name_WS_for__should_be_one_of__instead_of_many =
Display_Name_WS_for__should_be_one_of__instead_of_other =

View File

@ -422,5 +422,46 @@ class UtilitiesTest {
Assertions.assertFalse("\u0009\n\u000B\u000C\r\u0020\u0085\u00A0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u2028\u2029\u202F\u205F\u3000".matches(".+"));
Assertions.assertFalse("\u0009\n\u000B\u000C\r\u0020\u0085\u00A0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u2028\u2029\u202F\u205F\u3000".matches("^.+$"));
}
@Test
@DisplayName("directory copy case tests")
void testFDirectoryCopy() throws IOException {
String src = Utilities.path("[tmp]", "test", "copy-source");
String dst = Utilities.path("[tmp]", "test", "copy-dest");
makeDir (src);
makeFile(Utilities.path(src, "Test.txt"), "source1");
makeDir (Utilities.path(src, "SUB"));
makeFile(Utilities.path(src, "SUB", "TEST.txt"), "source2");
makeDir (dst);
makeFile(Utilities.path(dst, "test.txt"), "dest1");
makeDir (Utilities.path(dst, "sub"));
makeFile(Utilities.path(dst, "sub", "test.txt"), "dest2");
Utilities.copyDirectory(src, dst, null);
checkDir (dst);
checkFile(Utilities.path(dst, "Test.txt"), "source1");
checkDir (Utilities.path(dst, "SUB"));
checkFile(Utilities.path(dst, "SUB", "TEST.txt"), "source2");
}
private void checkFile(String path, String content) throws IOException {
Assertions.assertTrue(new CSFile(path).exists());
Assertions.assertEquals(content, TextFile.fileToString(path));
}
private void checkDir(String path) throws IOException {
Assertions.assertTrue(new CSFile(path).exists());
}
private void makeFile(String path, String content) throws IOException {
TextFile.stringToFile(content, path);
}
private void makeDir(String path) throws IOException {
Utilities.createDirectory(path);
Utilities.clearDirectory(path);
}
}

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>6.0.24-SNAPSHOT</version>
<version>6.0.26-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>6.0.24-SNAPSHOT</version>
<version>6.0.26-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -520,12 +520,14 @@ public class IgLoader implements IValidationEngineLoader {
}
}
if (loadInContext) {
// getContext().getLoadedPackages().add(pi.name() + "#" + pi.version());
getContext().loadFromPackage(pi, ValidatorUtils.loaderForVersion(pi.fhirVersion()));
}
for (String s : pi.listResources("CodeSystem", "ConceptMap", "ImplementationGuide", "CapabilityStatement", "SearchParameter", "Conformance", "StructureMap", "ValueSet", "StructureDefinition")) {
res.put(s, TextFile.streamToBytes(pi.load("package", s)));
if (!pi.isCoreExamples()) {
if (loadInContext) {
// getContext().getLoadedPackages().add(pi.name() + "#" + pi.version());
getContext().loadFromPackage(pi, ValidatorUtils.loaderForVersion(pi.fhirVersion()));
}
for (String s : pi.listResources("CodeSystem", "ConceptMap", "ImplementationGuide", "CapabilityStatement", "SearchParameter", "Conformance", "StructureMap", "ValueSet", "StructureDefinition")) {
res.put(s, TextFile.streamToBytes(pi.load("package", s)));
}
}
String ini = "[FHIR]\r\nversion=" + pi.fhirVersion() + "\r\n";
res.put("version.info", ini.getBytes());

View File

@ -2024,8 +2024,8 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
return true;
}
plist.add(p);
}
Collections.sort(plist); // logical paths are a set, but we want a predictable order for error messages
for (StructureDefinitionContextComponent ctxt : fixContexts(extUrl, definition.getContext())) {
if (ok) {
@ -2038,36 +2038,45 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
if (en.contains("#")) {
pu = en.substring(0, en.indexOf("#"));
en = en.substring(en.indexOf("#")+1);
} else {
//pu = en;
}
if (Utilities.existsInList(en, "Element", "Any")) {
ok = true;
} else if (en.equals("Resource") && container.isResource()) {
ok = true;
} else if (en.equals("CanonicalResource") && VersionUtilities.getCanonicalResourceNames(context.getVersion()).contains(stack.getLiteralPath())) {
ok = true;
} else if (plist.contains(en) && pu == null) {
ok = true;
}
if (checkConformsToProfile(appContext, errors, resource, container, stack, extUrl, ctxt.getExpression(), pu)) {
for (String p : plist) {
if (ok) {
break;
}
if (p.equals(en)) {
ok = true;
} else {
String pn = p;
String pt = "";
if (p.contains(".")) {
pn = p.substring(0, p.indexOf("."));
pt = p.substring(p.indexOf("."));
if (!ok) {
if (checkConformsToProfile(appContext, errors, resource, container, stack, extUrl, ctxt.getExpression(), pu)) {
for (String p : plist) {
if (ok) {
break;
}
StructureDefinition sd = context.fetchTypeDefinition(pn);
while (sd != null) {
if ((sd.getType() + pt).equals(en)) {
ok = true;
break;
if (p.equals(en)) {
ok = true;
} else {
String pn = p;
String pt = "";
if (p.contains(".")) {
pn = p.substring(0, p.indexOf("."));
pt = p.substring(p.indexOf("."));
}
if (sd.getBaseDefinition() != null) {
sd = context.fetchResource(StructureDefinition.class, sd.getBaseDefinition(), sd);
} else {
sd = null;
StructureDefinition sd = context.fetchTypeDefinition(pn);
while (sd != null) {
if ((sd.getType() + pt).equals(en)) {
ok = true;
break;
}
if (sd.getBaseDefinition() != null) {
sd = context.fetchResource(StructureDefinition.class, sd.getBaseDefinition(), sd);
} else {
sd = null;
}
}
}
}
@ -5960,7 +5969,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
if (ed.hasSlicing()) {
if (slicer != null && slicer.getPath().equals(ed.getPath())) {
String errorContext = "profile " + profile.getVersionedUrl();
if (!resource.getChildValue(ID).isEmpty()) {
if (resource.hasChild(ID) && !resource.getChildValue(ID).isEmpty()) {
errorContext += "; instance " + resource.getChildValue("id");
}
throw new DefinitionException(context.formatMessage(I18nConstants.SLICE_ENCOUNTERED_MIDWAY_THROUGH_SET_PATH___ID___, slicer.getPath(), slicer.getId(), errorContext));

View File

@ -78,6 +78,8 @@ public class StructureDefinitionValidator extends BaseValidator {
StructureDefinition sd = null;
String typeName = null;
try {
String url = src.getNamedChildValue("url");
sd = loadAsSD(src);
checkExtensionContext(errors, src, stack);
@ -101,8 +103,8 @@ public class StructureDefinitionValidator extends BaseValidator {
for (ValidationMessage msg : msgs) {
// we need to set the location for the context
String loc = msg.getLocation();
if (loc.contains("#")) {
msg.setLocation(stack.getLiteralPath()+".differential.element.where(path = '"+loc.substring(loc.indexOf("#")+1)+"')");
if (loc.startsWith("StructureDefinition.")) {
msg.setLocation(stack.getLiteralPath()+loc.substring(loc.indexOf(".")));
} else {
msg.setLocation(stack.getLiteralPath());
}
@ -160,6 +162,20 @@ public class StructureDefinitionValidator extends BaseValidator {
}
c++;
}
// if this is defining an extension, make sure that the extension fixed value matches the URL
String type = src.getNamedChildValue("type");
if ("Extension".equals(type)) {
String baseD = src.getNamedChildValue("baseDefinition");
if ("http://hl7.org/fhir/StructureDefinition/Extension".equals(baseD) && url != null) {
String fixedUrl = getFixedValue(src);
if (rule(errors, "2023-08-05", IssueType.INVALID, stack.getLiteralPath(), fixedUrl != null, I18nConstants.SD_EXTENSION_URL_MISSING, url)) {
ok = rule(errors, "2023-08-05", IssueType.INVALID, stack.getLiteralPath(), url.equals(fixedUrl), I18nConstants.SD_EXTENSION_URL_MISMATCH, url, fixedUrl) && ok;
} else {
ok = false;
}
}
}
} catch (Exception e) {
rule(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.getLiteralPath(), false, I18nConstants.ERROR_GENERATING_SNAPSHOT, e.getMessage());
ok = false;
@ -168,6 +184,19 @@ public class StructureDefinitionValidator extends BaseValidator {
}
private String getFixedValue(Element src) {
Element diff = src.getNamedChild("differential");
if (diff != null) {
for (Element ed : diff.getChildrenByName("element")) {
String path = ed.getNamedChildValue("path");
if ("Extension.url".equals(path)) {
return ed.getNamedChildValue("fixed");
}
}
}
return null;
}
private boolean validateInheritsObligationProfile(List<ValidationMessage> errors, Element extension, NodeStack stack, Element src) {
String tgt = extension.getNamedChildValue("value");
if (rule(errors, "2023-05-27", IssueType.INVALID, stack.getLiteralPath(), tgt != null,

View File

@ -71,7 +71,7 @@ public class ValueSetValidator extends BaseValidator {
List<Element> composes = vs.getChildrenByName("compose");
int cc = 0;
for (Element compose : composes) {
ok = validateValueSetCompose(errors, compose, stack.push(compose, cc, null, null), vs.getNamedChildValue("url"), "retired".equals(vs.getNamedChildValue("url"))) & ok;
ok = validateValueSetCompose(errors, compose, stack.push(compose, composes.size() > 1 ? cc : -1, null, null), vs.getNamedChildValue("url"), "retired".equals(vs.getNamedChildValue("url"))) & ok;
cc++;
}
}

View File

@ -2,8 +2,10 @@ package org.hl7.fhir.validation.instance.utils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.elementmodel.Element;
@ -19,7 +21,7 @@ public class NodeStack {
private Element element;
private ElementDefinition extension;
private String literalPath; // xpath format
private List<String> logicalPaths; // dotted format, various entry points
private Set<String> logicalPaths; // dotted format, various entry points
private NodeStack parent;
private ElementDefinition type;
private String workingLang;
@ -38,7 +40,7 @@ public class NodeStack {
literalPath = (initialPath == null ? "" : initialPath+".") + element.getPath();
workingLang = validationLanguage;
if (!element.getName().equals(element.fhirType())) {
logicalPaths = new ArrayList<>();
logicalPaths = new HashSet<>();
logicalPaths.add(element.fhirType());
}
}
@ -79,8 +81,8 @@ public class NodeStack {
return literalPath == null ? "" : literalPath;
}
public List<String> getLogicalPaths() {
return logicalPaths == null ? new ArrayList<String>() : logicalPaths;
public Set<String> getLogicalPaths() {
return logicalPaths == null ? new HashSet<String>() : logicalPaths;
}
private ElementDefinition getType() {
@ -96,6 +98,9 @@ public class NodeStack {
}
private NodeStack pushInternal(Element element, int count, ElementDefinition definition, ElementDefinition type, String sep) {
if (definition == null & element.getProperty() != null) {
definition = element.getProperty().getDefinition();
}
NodeStack res = new NodeStack(context);
res.ids = ids;
res.parent = this;
@ -121,7 +126,7 @@ public class NodeStack {
res.literalPath = res.literalPath.substring(0, res.literalPath.lastIndexOf(".")) + "." + en;;
}
}
res.logicalPaths = new ArrayList<String>();
res.logicalPaths = new HashSet<String>();
if (type != null) {
// type will be null if we on a stitching point of a contained resource, or if....
res.type = type;
@ -131,23 +136,48 @@ public class NodeStack {
tn = element.fhirType();
}
for (String lp : getLogicalPaths()) {
res.logicalPaths.add(lp + "." + t);
if (t.endsWith("[x]")) {
res.logicalPaths.add(lp + "." + t.substring(0, t.length() - 3) + ".ofType("+type.getPath()+")");
res.logicalPaths.add(lp + "." + t.substring(0, t.length() - 3) + type.getPath());
if (isRealPath(lp, t)) {
res.logicalPaths.add(lp + "." + t);
if (t.endsWith("[x]")) {
res.logicalPaths.add(lp + "." + t.substring(0, t.length() - 3) + ".ofType("+type.getPath()+")");
res.logicalPaths.add(lp + "." + t.substring(0, t.length() - 3) + type.getPath());
}
}
}
res.logicalPaths.add(tn);
} else if (definition != null) {
for (String lp : getLogicalPaths()) {
res.logicalPaths.add(lp + "." + element.getName());
if (isRealPath(lp, element.getName())) {
res.logicalPaths.add(lp + "." + element.getName());
}
}
res.logicalPaths.add(definition.typeSummary());
} else
if (definition.hasContentReference()) {
res.logicalPaths.add(definition.getContentReference().substring(definition.getContentReference().indexOf("#")+1));
} else {
res.logicalPaths.addAll(definition.typeList());
}
} else {
res.logicalPaths.addAll(getLogicalPaths());
}
return res;
}
private boolean isRealPath(String lp, String t) {
if (Utilities.existsInList(lp, "Element")) {
return Utilities.existsInList(t, "id", "extension");
}
if (Utilities.existsInList(lp, "BackboneElement", "BackboneType")) {
return Utilities.existsInList(t, "modifierExtension");
}
if (Utilities.existsInList(lp, "Resource")) {
return Utilities.existsInList(t, "id", "meta", "implicitRules", "language");
}
if (Utilities.existsInList(lp, "DomainResource")) {
return Utilities.existsInList(t, "text", "contained", "extension", "modifierExtension");
}
return true;
}
private void setType(ElementDefinition type) {
this.type = type;
}

View File

@ -3,7 +3,11 @@ package org.hl7.fhir.validation.special;
import java.util.Collections;
import java.util.Comparator;
import org.hl7.fhir.ParametersParameter;
import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.Extension;
import org.hl7.fhir.r5.model.OperationOutcome;
import org.hl7.fhir.r5.model.OperationOutcome.OperationOutcomeIssueComponent;
import org.hl7.fhir.r5.model.Parameters;
import org.hl7.fhir.r5.model.Parameters.ParametersParameterComponent;
import org.hl7.fhir.r5.model.ValueSet;
@ -16,8 +20,14 @@ import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionPropertyComponent;
public class TxTesterSorters {
public static void sortParameters(Parameters po) {
Collections.sort(po.getParameter(), new TxTesterSorters.ParameterSorter());
for (ParametersParameterComponent p : po.getParameter()) {
if (p.getResource() != null && p.getResource() instanceof OperationOutcome) {
Collections.sort(((OperationOutcome) p.getResource()).getIssue(), new TxTesterSorters.OperationIssueSorter());
}
}
}
@ -43,7 +53,24 @@ public class TxTesterSorters {
}
public static class OperationIssueSorter implements Comparator<OperationOutcomeIssueComponent> {
@Override
public int compare(OperationOutcomeIssueComponent o1, OperationOutcomeIssueComponent o2) {
if (o1.hasSeverity() && o2.hasSeverity() && o1.getSeverity() != o2.getSeverity()) {
return o1.getSeverity().compareTo(o2.getSeverity());
}
if (o1.hasCode() && o2.hasCode() && o1.getCode() != o2.getCode()) {
return o1.getCode().compareTo(o2.getCode());
}
if (o1.getDetails().hasText() && o2.getDetails().hasText() && !o1.getDetails().getText().equals(o2.getDetails().getText())) {
return o1.getDetails().getText().compareTo(o2.getDetails().getText());
}
return 0;
}
}
public static class DesignationSorter implements Comparator<ConceptReferenceDesignationComponent> {
@Override

View File

@ -107,7 +107,7 @@ public class SnapShotGenerationXTests {
sort = "true".equals(test.getAttribute("sort"));
fail = "true".equals(test.getAttribute("fail"));
newSliceProcessing = !"false".equals(test.getAttribute("new-slice-processing"));
debug = false; // "true".equals(test.getAttribute("debug"));
debug = "true".equals(test.getAttribute("debug"));
id = test.getAttribute("id");
include = test.getAttribute("include");
@ -510,7 +510,7 @@ public class SnapShotGenerationXTests {
pu.setAllowUnknownProfile(AllowUnknownProfile.ALL_TYPES);
if (test.isSort()) {
List<String> errors = new ArrayList<String>();
int lastCount = output.getDifferential().getElement().size();
// int lastCount = output.getDifferential().getElement().size();
pu.sortDifferential(base, output, test.getSource().getName(), errors, false);
if (errors.size() > 0)
throw new FHIRException("Sort failed: " + errors.toString());

View File

@ -46,9 +46,9 @@ public class ExternalTerminologyServiceTests implements ITxTesterLoader {
private JsonObject test;
}
private static final String SERVER = FhirSettings.getTxFhirDevelopment();
// private static final String SERVER = FhirSettings.getTxFhirLocal();
// private static final String SERVER = "https://r4.ontoserver.csiro.au/fhir";
private static final String SERVER = FhirSettings.getTxFhirDevelopment();
// private static final String SERVER = FhirSettings.getTxFhirLocal();
// private static final String SERVER = "https://r4.ontoserver.csiro.au/fhir";
@Parameters(name = "{index}: id {0}")

View File

@ -563,7 +563,12 @@ public class ValidationTests implements IEvaluationContext, IValidatorResourceFe
JsonObject oj = JsonTrackingParser.parse(json, null);
java.add("outcome", oj);
}
JsonTrackingParser.write(manifest, new File(Utilities.path("[tmp]", "validator", "manifest.new.json")));
File newManifestFile = new File(Utilities.path("[tmp]", "validator", "manifest.new.json"));
if (!newManifestFile.getParentFile().exists()) {
newManifestFile.getParentFile().mkdir();
}
JsonTrackingParser.write(manifest, newManifestFile);
}
Assertions.fail("\r\n"+String.join("\r\n", fails));
}

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<suppressions xmlns="https://jeremylong.github.io/DependencyCheck/dependency-suppression.1.3.xsd">
<suppress>
<notes><![CDATA[
This suppresses CVEs related to a HAPI-FHIR parent pom that no longer exists in fhir-test-cases
]]></notes>
<packageUrl regex="true">^pkg:maven/org\.hl7\.fhir\.testcases/fhir\-test\-cases@.*$</packageUrl>
<cve>CVE-2019-12741</cve>
</suppress>
<suppress>
<notes><![CDATA[
This suppresses CVEs related to a HAPI-FHIR parent pom that no longer exists in fhir-test-cases
]]></notes>
<packageUrl regex="true">^pkg:maven/org\.hl7\.fhir\.testcases/fhir\-test\-cases@.*$</packageUrl>
<cve>CVE-2021-32053</cve>
</suppress>
</suppressions>

View File

@ -14,13 +14,13 @@
HAPI FHIR
-->
<artifactId>org.hl7.fhir.core</artifactId>
<version>6.0.24-SNAPSHOT</version>
<version>6.0.26-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<guava_version>32.0.1-jre</guava_version>
<hapi_fhir_version>6.4.1</hapi_fhir_version>
<validator_test_case_version>1.3.22</validator_test_case_version>
<validator_test_case_version>1.3.25</validator_test_case_version>
<jackson_version>2.15.2</jackson_version>
<junit_jupiter_version>5.9.2</junit_jupiter_version>
<junit_platform_launcher_version>1.8.2</junit_platform_launcher_version>
@ -705,6 +705,11 @@
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<configuration>
<suppressionFiles>
<suppressionFile>owasp-suppression-file.xml</suppressionFile>
</suppressionFiles>
</configuration>
<executions>
<execution>
<goals>