version comparison support (#284)

* add package url fixer

* fix problems doing CCDA snapshots

* Fix for http://hl7.org/fhir/StructureDefinition/capabilitystatement-expectation

* improve error message

* fix package id in generated version specific tests

* remove spurious debug statement

* rework package loaders for automatic loading of package dependencies

* fix spelling mistake

* add automatic loading of package dependencies by the context

* significant work on tests to support version comparison

* fix minor loading issue

* compile fix

* utils support

* fixes for version comparison

* rework error handling when expanding valuesets + add error check on value set imports

* fix loading bug

* improve error message
This commit is contained in:
Grahame Grieve 2020-07-27 23:04:31 +10:00 committed by GitHub
parent b9755c8f1f
commit bf0f81f51b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 1139 additions and 265 deletions

View File

@ -0,0 +1,84 @@
package org.hl7.fhir.convertors.loaders;
import org.hl7.fhir.dstu3.context.SimpleWorkerContext.IContextResourceLoader;
import org.hl7.fhir.dstu3.model.Bundle;
import org.hl7.fhir.dstu3.model.ElementDefinition;
import org.hl7.fhir.dstu3.model.Resource;
import org.hl7.fhir.dstu3.model.StructureDefinition;
import org.hl7.fhir.utilities.cache.NpmPackage;
import java.util.ArrayList;
import java.util.List;
public abstract class BaseLoaderR3 implements IContextResourceLoader {
public interface ILoaderKnowledgeProvider {
/**
* get the path for references to this resource.
* @param resource
* @return null if not tracking paths
*/
String getResourcePath(Resource resource);
}
public static class NullLoaderKnowledgeProvider implements ILoaderKnowledgeProvider {
@Override
public String getResourcePath(Resource resource) {
return null;
}
}
protected final String URL_BASE = "http://hl7.org/fhir/";
protected final String URL_DSTU2 = "http://hl7.org/fhir/1.0/";
protected final String URL_DSTU2016MAY = "http://hl7.org/fhir/1.4/";
protected final String URL_DSTU3 = "http://hl7.org/fhir/3.0/";
protected final String URL_R4 = "http://hl7.org/fhir/4.0/";
protected final String URL_ELEMENT_DEF_NAMESPACE = "http://hl7.org/fhir/StructureDefinition/elementdefinition-namespace";
protected boolean patchUrls;
protected boolean killPrimitives;;
private String[] types;
private ILoaderKnowledgeProvider lkp;
public BaseLoaderR3(String[] types, ILoaderKnowledgeProvider lkp) {
super();
this.types = types;
this.lkp = lkp;
}
public String[] getTypes() {
return types;
}
public boolean isPatchUrls() {
return patchUrls;
}
public BaseLoaderR3 setPatchUrls(boolean patchUrls) {
this.patchUrls = patchUrls;
return this;
}
public boolean isKillPrimitives() {
return killPrimitives;
}
public BaseLoaderR3 setKillPrimitives(boolean killPrimitives) {
this.killPrimitives = killPrimitives;
return this;
}
public String getResourcePath(Resource resource) {
return lkp.getResourcePath(resource);
}
public void setPath(Resource r) {
String path = lkp.getResourcePath(r);
if (path != null) {
r.setUserData("path", path);
}
}
}

View File

@ -0,0 +1,85 @@
package org.hl7.fhir.convertors.loaders;
import org.hl7.fhir.r4.context.SimpleWorkerContext.IContextResourceLoader;
import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.CanonicalType;
import org.hl7.fhir.r4.model.ElementDefinition;
import org.hl7.fhir.r4.model.Resource;
import org.hl7.fhir.r4.model.StructureDefinition;
import org.hl7.fhir.utilities.cache.NpmPackage;
import java.util.ArrayList;
import java.util.List;
public abstract class BaseLoaderR4 implements IContextResourceLoader {
public interface ILoaderKnowledgeProvider {
/**
* get the path for references to this resource.
* @param resource
* @return null if not tracking paths
*/
String getResourcePath(Resource resource);
}
public static class NullLoaderKnowledgeProvider implements ILoaderKnowledgeProvider {
@Override
public String getResourcePath(Resource resource) {
return null;
}
}
protected final String URL_BASE = "http://hl7.org/fhir/";
protected final String URL_DSTU2 = "http://hl7.org/fhir/1.0/";
protected final String URL_DSTU2016MAY = "http://hl7.org/fhir/1.4/";
protected final String URL_DSTU3 = "http://hl7.org/fhir/3.0/";
protected final String URL_R4 = "http://hl7.org/fhir/4.0/";
protected final String URL_ELEMENT_DEF_NAMESPACE = "http://hl7.org/fhir/StructureDefinition/elementdefinition-namespace";
protected boolean patchUrls;
protected boolean killPrimitives;;
private String[] types;
private ILoaderKnowledgeProvider lkp;
public BaseLoaderR4(String[] types, ILoaderKnowledgeProvider lkp) {
super();
this.types = types;
this.lkp = lkp;
}
public String[] getTypes() {
return types;
}
public boolean isPatchUrls() {
return patchUrls;
}
public BaseLoaderR4 setPatchUrls(boolean patchUrls) {
this.patchUrls = patchUrls;
return this;
}
public boolean isKillPrimitives() {
return killPrimitives;
}
public BaseLoaderR4 setKillPrimitives(boolean killPrimitives) {
this.killPrimitives = killPrimitives;
return this;
}
public String getResourcePath(Resource resource) {
return lkp.getResourcePath(resource);
}
public void setPath(Resource r) {
String path = lkp.getResourcePath(r);
if (path != null) {
r.setUserData("path", path);
}
}
}

View File

@ -1,16 +1,22 @@
package org.hl7.fhir.convertors.loaders;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r5.context.IWorkerContext.IContextResourceLoader;
import org.hl7.fhir.r5.model.Bundle;
import org.hl7.fhir.r5.model.CanonicalType;
import org.hl7.fhir.r5.model.ElementDefinition;
import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.utilities.cache.NpmPackage;
import com.google.gson.JsonSyntaxException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public abstract class BaseLoaderR5 {
public abstract class BaseLoaderR5 implements IContextResourceLoader {
public interface ILoaderKnowledgeProvider {
/**
@ -19,6 +25,7 @@ public abstract class BaseLoaderR5 {
* @return null if not tracking paths
*/
String getResourcePath(Resource resource);
ILoaderKnowledgeProvider forNewPackage(NpmPackage npm) throws JsonSyntaxException, IOException;
}
public static class NullLoaderKnowledgeProvider implements ILoaderKnowledgeProvider {
@ -26,6 +33,11 @@ public abstract class BaseLoaderR5 {
public String getResourcePath(Resource resource) {
return null;
}
@Override
public ILoaderKnowledgeProvider forNewPackage(NpmPackage npm) {
return this;
}
}
protected final String URL_BASE = "http://hl7.org/fhir/";
protected final String URL_DSTU2 = "http://hl7.org/fhir/1.0/";
@ -38,8 +50,8 @@ public abstract class BaseLoaderR5 {
protected boolean patchUrls;
protected boolean killPrimitives;;
private String[] types;
private ILoaderKnowledgeProvider lkp;
protected String[] types;
protected ILoaderKnowledgeProvider lkp;
public BaseLoaderR5(String[] types, ILoaderKnowledgeProvider lkp) {
super();
@ -80,4 +92,28 @@ public abstract class BaseLoaderR5 {
}
}
public IContextResourceLoader getNewLoader(NpmPackage npm) throws JsonSyntaxException, IOException {
BaseLoaderR5 ret = loaderFactory(npm);
ret.patchUrls = patchUrls;
ret.killPrimitives = killPrimitives;
return ret;
}
protected BaseLoaderR5 loaderFactory(NpmPackage npm) throws JsonSyntaxException, IOException {
if (VersionUtilities.isR5Ver(npm.fhirVersion())) {
return new R5ToR5Loader(types, lkp.forNewPackage(npm));
} else if (VersionUtilities.isR4Ver(npm.fhirVersion())) {
return new R4ToR5Loader(types, lkp.forNewPackage(npm));
} else if (VersionUtilities.isR3Ver(npm.fhirVersion())) {
return new R3ToR5Loader(types, lkp.forNewPackage(npm));
} else if (VersionUtilities.isR2Ver(npm.fhirVersion())) {
return new R2ToR5Loader(types, lkp.forNewPackage(npm));
} else if (VersionUtilities.isR2BVer(npm.fhirVersion())) {
return new R2016MayToR5Loader(types, lkp.forNewPackage(npm));
} else {
throw new FHIRException("Unsupported FHIR Version "+npm.fhirVersion());
}
}
}

View File

@ -55,7 +55,7 @@ import org.hl7.fhir.r4.model.StructureDefinition.StructureDefinitionKind;
import org.hl7.fhir.r4.model.UriType;
import org.hl7.fhir.r4.model.ValueSet;
public class R2016MayToR4Loader extends BaseLoaderR5 implements IContextResourceLoader, VersionConvertorAdvisor40 {
public class R2016MayToR4Loader extends BaseLoaderR4 implements IContextResourceLoader, VersionConvertorAdvisor40 {
private List<CodeSystem> cslist = new ArrayList<>();

View File

@ -57,8 +57,11 @@ import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind;
import org.hl7.fhir.r5.model.UriType;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.utilities.cache.NpmPackage;
public class R2016MayToR5Loader extends BaseLoaderR5 implements IContextResourceLoader, VersionConvertorAdvisor50 {
import com.google.gson.JsonSyntaxException;
public class R2016MayToR5Loader extends BaseLoaderR5 implements VersionConvertorAdvisor50 {
public R2016MayToR5Loader(String[] types, ILoaderKnowledgeProvider lkp) {
super(types, lkp);
@ -193,4 +196,6 @@ public class R2016MayToR5Loader extends BaseLoaderR5 implements IContextResource
return null;
}
}

View File

@ -54,7 +54,7 @@ import org.hl7.fhir.dstu3.model.UriType;
import org.hl7.fhir.dstu3.model.ValueSet;
import org.hl7.fhir.exceptions.FHIRException;
public class R2ToR3Loader extends BaseLoaderR5 implements IContextResourceLoader, VersionConvertorAdvisor30 {
public class R2ToR3Loader extends BaseLoaderR3 implements VersionConvertorAdvisor30 {
private List<CodeSystem> cslist = new ArrayList<>();

View File

@ -55,7 +55,7 @@ import org.hl7.fhir.r4.model.StructureDefinition.StructureDefinitionKind;
import org.hl7.fhir.r4.model.UriType;
import org.hl7.fhir.r4.model.ValueSet;
public class R2ToR4Loader extends BaseLoaderR5 implements IContextResourceLoader, VersionConvertorAdvisor40 {
public class R2ToR4Loader extends BaseLoaderR4 implements VersionConvertorAdvisor40 {
private List<CodeSystem> cslist = new ArrayList<>();

View File

@ -58,6 +58,9 @@ import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind;
import org.hl7.fhir.r5.model.UriType;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.utilities.cache.NpmPackage;
import com.google.gson.JsonSyntaxException;
public class R2ToR5Loader extends BaseLoaderR5 implements IContextResourceLoader, VersionConvertorAdvisor50 {
@ -192,4 +195,5 @@ public class R2ToR5Loader extends BaseLoaderR5 implements IContextResourceLoader
return null;
}
}

View File

@ -51,7 +51,7 @@ import org.hl7.fhir.r4.model.Bundle.BundleType;
import org.hl7.fhir.r4.model.ElementDefinition.TypeRefComponent;
import org.hl7.fhir.r4.model.StructureDefinition.StructureDefinitionKind;
public class R3ToR4Loader extends BaseLoaderR5 implements IContextResourceLoader, VersionConvertorAdvisor40 {
public class R3ToR4Loader extends BaseLoaderR4 implements IContextResourceLoader, VersionConvertorAdvisor40 {
private List<CodeSystem> cslist = new ArrayList<>();

View File

@ -58,6 +58,9 @@ import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind;
import org.hl7.fhir.r5.model.UriType;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.utilities.cache.NpmPackage;
import com.google.gson.JsonSyntaxException;
public class R3ToR5Loader extends BaseLoaderR5 implements IContextResourceLoader, VersionConvertorAdvisor50 {
@ -195,4 +198,5 @@ public class R3ToR5Loader extends BaseLoaderR5 implements IContextResourceLoader
public org.hl7.fhir.r4.model.Resource convertR4(org.hl7.fhir.r5.model.Resource resource) throws FHIRException {
return null;
}
}

View File

@ -58,6 +58,9 @@ import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind;
import org.hl7.fhir.r5.model.UriType;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.utilities.cache.NpmPackage;
import com.google.gson.JsonSyntaxException;
public class R4ToR5Loader extends BaseLoaderR5 implements IContextResourceLoader, VersionConvertorAdvisor50 {

View File

@ -57,8 +57,11 @@ import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind;
import org.hl7.fhir.r5.model.UriType;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.utilities.cache.NpmPackage;
public class R5ToR5Loader extends BaseLoaderR5 implements IContextResourceLoader, VersionConvertorAdvisor50 {
import com.google.gson.JsonSyntaxException;
public class R5ToR5Loader extends BaseLoaderR5 implements VersionConvertorAdvisor50 {
public R5ToR5Loader(String[] types, ILoaderKnowledgeProvider lkp) {
super(types, lkp);

View File

@ -36,6 +36,7 @@ import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.utilities.cache.NpmPackageIndexBuilder;
import org.hl7.fhir.utilities.cache.NpmPackage.NpmPackageFolder;
import org.hl7.fhir.utilities.json.JSONUtil;
import org.hl7.fhir.utilities.json.JsonTrackingParser;
import com.google.common.base.Charsets;
@ -217,6 +218,9 @@ public class NpmPackageVersionConverter {
private byte[] convertPackage(byte[] cnt) throws IOException {
JsonObject json = JsonTrackingParser.parseJson(cnt);
currentVersion = json.getAsJsonArray("fhirVersions").get(0).getAsString();
String name = JSONUtil.str(json, "name");
json.remove("name");
json.addProperty("name", name+"."+vCode);
json.remove("fhirVersions");
json.remove("dependencies");
JsonArray fv = new JsonArray();

View File

@ -9,6 +9,7 @@ import java.util.Map;
import java.util.Set;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r5.comparison.ResourceComparer.MessageCounts;
import org.hl7.fhir.r5.model.CanonicalResource;
import org.hl7.fhir.r5.model.PrimitiveType;
import org.hl7.fhir.utilities.Utilities;
@ -81,6 +82,28 @@ public abstract class CanonicalResourceComparer extends ResourceComparer {
this.intersection = intersection;
}
@Override
protected String toTable() {
String s = null;
if (left != null && right != null && !left.getUrl().equals(right.getUrl())) {
s = "<td>"+left.getUrl()+"</td><td>"+right.getUrl()+"</td>";
} else if (left != null) {
s = "<td colspan=2>"+left.getUrl()+"</td>";
} else {
s = "<td colspan=2>"+right.getUrl()+"</td>";
}
s = s + "<td><a href=\""+getId()+".html\">Comparison</a></td>";
s = s + "<td>"+outcomeSummary()+"</td>";
return "<tr style=\"background-color: "+color()+"\">"+s+"</tr>\r\n";
}
@Override
protected void countMessages(MessageCounts cnts) {
for (StructuralMatch<String> sm : metadata.values()) {
sm.countMessages(cnts);
}
}
}
public CanonicalResourceComparer(ComparisonSession session) {

View File

@ -9,6 +9,7 @@ import java.util.Map;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r5.comparison.ResourceComparer.MessageCounts;
import org.hl7.fhir.r5.model.CodeSystem;
import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent;
import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionDesignationComponent;
@ -55,6 +56,18 @@ public class CodeSystemComparer extends CanonicalResourceComparer {
protected String summary() {
return "CodeSystem: "+left.present()+" vs "+right.present();
}
@Override
protected String fhirType() {
return "CodeSystem";
}
@Override
protected void countMessages(MessageCounts cnts) {
super.countMessages(cnts);
combined.countMessages(cnts);
}
}
private CodeSystem right;

View File

@ -2,6 +2,8 @@ package org.hl7.fhir.r5.comparison;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@ -13,6 +15,7 @@ import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.PathEngineException;
import org.hl7.fhir.r5.comparison.CodeSystemComparer.CodeSystemComparison;
import org.hl7.fhir.r5.comparison.ProfileComparer.ProfileComparison;
import org.hl7.fhir.r5.comparison.ResourceComparer.PlaceHolderComparison;
import org.hl7.fhir.r5.comparison.ResourceComparer.ResourceComparison;
import org.hl7.fhir.r5.comparison.ValueSetComparer.ValueSetComparison;
@ -35,14 +38,16 @@ import org.hl7.fhir.utilities.xhtml.XhtmlComposer;
public class ComparisonRenderer implements IEvaluationContext {
private IWorkerContext context;
private IWorkerContext contextLeft;
private IWorkerContext contextRight;
private ComparisonSession session;
private Map<String, String> templates = new HashMap<>();
private String folder;
public ComparisonRenderer(IWorkerContext context, String folder, ComparisonSession session) {
public ComparisonRenderer(IWorkerContext contextLeft, IWorkerContext contextRight, String folder, ComparisonSession session) {
super();
this.context = context;
this.contextLeft = contextLeft;
this.contextRight = contextRight;
this.folder = folder;
this.session = session;
}
@ -54,12 +59,13 @@ public class ComparisonRenderer implements IEvaluationContext {
public void render() throws IOException {
dumpBinaries();
StringBuilder b = new StringBuilder();
for (String id : sorted(session.getCompares().keySet())) {
ResourceComparison comp = session.getCompares().get(id);
renderComparison(id, comp);
b.append("<li><a href=\""+comp.getId()+".html\">"+Utilities.escapeXml(comp.summary())+"</a></li>\r\n");
}
b.append("<table class=\"grid\">\r\n");
List<String> list = sorted(session.getCompares().keySet());
processList(list, b, "CodeSystem");
processList(list, b, "ValueSet");
processList(list, b, "StructureDefinition");
b.append("</table>\r\n");
Map<String, Base> vars = new HashMap<>();
CodeSystemComparer cs = new CodeSystemComparer(session);
vars.put("title", new StringType(session.getTitle()));
@ -69,6 +75,23 @@ public class ComparisonRenderer implements IEvaluationContext {
TextFile.stringToFile(cnt, file("index.html"));
}
private void processList(List<String> list, StringBuilder b, String name) throws IOException {
// TODO Auto-generated method stub
boolean first = true;
for (String id : list) {
ResourceComparison comp = session.getCompares().get(id);
if (comp.fhirType().equals(name)) {
if (first) {
first = false;
b.append("<tr><td colspan=4><b>"+name+"</b></td></tr>\r\n");
}
renderComparison(id, comp);
b.append(comp.toTable());
//"<li><a href=\""+comp.getId()+".html\">"+Utilities.escapeXml(comp.summary())+"</a></li>\r\n"
}
}
}
private List<String> sorted(Set<String> keySet) {
List<String> list = new ArrayList<>();
list.addAll(keySet);
@ -77,8 +100,11 @@ public class ComparisonRenderer implements IEvaluationContext {
}
private void dumpBinaries() throws IOException {
for (String k : context.getBinaries().keySet()) {
TextFile.bytesToFile(context.getBinaries().get(k), Utilities.path(folder, k));
for (String k : contextLeft.getBinaries().keySet()) {
TextFile.bytesToFile(contextLeft.getBinaries().get(k), Utilities.path(folder, k));
}
for (String k : contextRight.getBinaries().keySet()) {
TextFile.bytesToFile(contextRight.getBinaries().get(k), Utilities.path(folder, k));
}
}
@ -89,9 +115,23 @@ public class ComparisonRenderer implements IEvaluationContext {
renderValueSet(id, (ValueSetComparison) comp);
} else if (comp instanceof CodeSystemComparison) {
renderCodeSystem(id, (CodeSystemComparison) comp);
} else if (comp instanceof PlaceHolderComparison) {
renderPlaceHolder(id, (PlaceHolderComparison) comp);
}
}
private void renderPlaceHolder(String id, PlaceHolderComparison comp) throws IOException {
String cnt = "";
if (comp.getE() != null) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
comp.getE().printStackTrace(pw);
cnt = sw.toString();
}
cnt = "<html><body><pre>"+cnt+"</pre></body></html>\r\n";
TextFile.stringToFile(cnt, file(comp.getId()+".html"));
}
private void renderCodeSystem(String id, CodeSystemComparison comp) throws IOException {
String template = templates.get("CodeSystem");
Map<String, Base> vars = new HashMap<>();
@ -138,7 +178,7 @@ public class ComparisonRenderer implements IEvaluationContext {
private void renderProfile(String id, ProfileComparison comp) throws IOException {
String template = templates.get("Profile");
Map<String, Base> vars = new HashMap<>();
ProfileComparer cs = new ProfileComparer(session, new ProfileUtilities(session.getContext(), null, session.getPkp()));
ProfileComparer cs = new ProfileComparer(session, new ProfileUtilities(session.getContextLeft(), null, session.getPkp()), new ProfileUtilities(session.getContextRight(), null, session.getPkp()));
vars.put("left", new StringType(comp.getLeft().present()));
vars.put("right", new StringType(comp.getRight().present()));
vars.put("leftId", new StringType(comp.getLeft().getId()));
@ -155,7 +195,7 @@ public class ComparisonRenderer implements IEvaluationContext {
}
private String processTemplate(String template, String name, Map<String, Base> vars) {
LiquidEngine engine = new LiquidEngine(context, this);
LiquidEngine engine = new LiquidEngine(contextRight, this);
LiquidDocument doc = engine.parse(template, name+".template");
return engine.evaluate(doc, Tuple.fromMap(vars), vars);
}

View File

@ -25,24 +25,30 @@ import org.hl7.fhir.utilities.Utilities;
public class ComparisonSession {
private Map<String, ResourceComparison> compares = new HashMap<>();
private IWorkerContext context;
private IWorkerContext contextLeft;
private IWorkerContext contextRight;
private String sessiondId;
private int count;
private boolean debug;
private String title;
private ProfileKnowledgeProvider pkp;
public ComparisonSession(IWorkerContext context, String title, ProfileKnowledgeProvider pkp) {
public ComparisonSession(IWorkerContext contextLeft, IWorkerContext contextRight, String title, ProfileKnowledgeProvider pkp) {
super();
this.context = context;
this.contextLeft = contextLeft;
this.contextRight = contextRight;
this.sessiondId = UUID.randomUUID().toString().toLowerCase();
this.title = title;
this.pkp = pkp;
// debug = true;
}
public IWorkerContext getContext() {
return context;
public IWorkerContext getContextLeft() {
return contextLeft;
}
public IWorkerContext getContextRight() {
return contextRight;
}
public String getTitle() {
@ -50,11 +56,11 @@ public class ComparisonSession {
}
public ResourceComparison compare(String left, String right) throws DefinitionException, FHIRFormatError, IOException {
CanonicalResource l = (CanonicalResource) context.fetchResource(Resource.class, left);
CanonicalResource l = (CanonicalResource) contextLeft.fetchResource(Resource.class, left);
if (l == null) {
throw new DefinitionException("Unable to resolve "+left);
}
CanonicalResource r = (CanonicalResource) context.fetchResource(Resource.class, right);
CanonicalResource r = (CanonicalResource) contextRight.fetchResource(Resource.class, right);
if (r == null) {
throw new DefinitionException("Unable to resolve "+right);
}
@ -62,30 +68,54 @@ public class ComparisonSession {
}
public ResourceComparison compare(CanonicalResource left, CanonicalResource right) throws DefinitionException, FHIRFormatError, IOException {
String key = key(left.getUrl(), left.getVersion(), right.getUrl(), right.getVersion());
if (compares.containsKey(key)) {
// if null then the comparison is in progress.
// this can happen when profiles refer to each other
return compares.get(key);
}
compares.put(key, null);
if (left instanceof CodeSystem && right instanceof CodeSystem) {
CodeSystemComparer cs = new CodeSystemComparer(this);
CodeSystemComparison csc = cs.compare((CodeSystem) left, (CodeSystem) right);
if (left != null && right != null) {
String key = key(left.getUrl(), left.getVersion(), right.getUrl(), right.getVersion());
if (compares.containsKey(key)) {
// if null then the comparison is in progress.
// this can happen when profiles refer to each other
return compares.get(key);
}
compares.put(key, null);
try {
if (left instanceof CodeSystem && right instanceof CodeSystem) {
CodeSystemComparer cs = new CodeSystemComparer(this);
CodeSystemComparison csc = cs.compare((CodeSystem) left, (CodeSystem) right);
compares.put(key, csc);
return csc;
} else if (left instanceof ValueSet && right instanceof ValueSet) {
ValueSetComparer cs = new ValueSetComparer(this);
ValueSetComparison csc = cs.compare((ValueSet) left, (ValueSet) right);
compares.put(key, csc);
return csc;
} else if (left instanceof StructureDefinition && right instanceof StructureDefinition) {
ProfileComparer cs = new ProfileComparer(this, new ProfileUtilities(contextLeft, null, pkp), new ProfileUtilities(contextRight, null, pkp));
ProfileComparison csc = cs.compare((StructureDefinition) left, (StructureDefinition) right);
compares.put(key, csc);
return csc;
} else {
throw new FHIRException("Unable to compare resources of type "+left.fhirType()+" and "+right.fhirType());
}
} catch (Throwable e) {
ResourceComparer.PlaceHolderComparison csc = new ResourceComparer.PlaceHolderComparison(left, right, e);
compares.put(key, csc);
return csc;
}
} else if (left != null) {
String key = key(left.getUrl(), left.getVersion(), left.getUrl(), left.getVersion());
if (compares.containsKey(key)) {
return compares.get(key);
}
ResourceComparer.PlaceHolderComparison csc = new ResourceComparer.PlaceHolderComparison(left, right);
compares.put(key, csc);
return csc;
} else if (left instanceof ValueSet && right instanceof ValueSet) {
ValueSetComparer cs = new ValueSetComparer(this);
ValueSetComparison csc = cs.compare((ValueSet) left, (ValueSet) right);
compares.put(key, csc);
return csc;
} else if (left instanceof StructureDefinition && right instanceof StructureDefinition) {
ProfileComparer cs = new ProfileComparer(this, new ProfileUtilities(context, null, pkp));
ProfileComparison csc = cs.compare((StructureDefinition) left, (StructureDefinition) right);
compares.put(key, csc);
return csc;
return csc;
} else {
throw new FHIRException("Unable to compare ");
String key = key(right.getUrl(), right.getVersion(), right.getUrl(), right.getVersion());
if (compares.containsKey(key)) {
return compares.get(key);
}
ResourceComparer.PlaceHolderComparison csc = new ResourceComparer.PlaceHolderComparison(left, right);
compares.put(key, csc);
return csc;
}
}

View File

@ -9,9 +9,11 @@ import java.util.List;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r5.comparison.ResourceComparer.MessageCounts;
import org.hl7.fhir.r5.comparison.ValueSetComparer.ValueSetComparison;
import org.hl7.fhir.r5.conformance.ProfileUtilities;
import org.hl7.fhir.r5.conformance.ProfileUtilities.UnusedTracker;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.formats.IParser;
import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.Coding;
@ -63,16 +65,29 @@ public class ProfileComparer extends CanonicalResourceComparer {
protected String summary() {
return "Profile: "+left.present()+" vs "+right.present();
}
@Override
protected String fhirType() {
return "StructureDefinition";
}
@Override
protected void countMessages(MessageCounts cnts) {
super.countMessages(cnts);
combined.countMessages(cnts);
}
}
private ProfileUtilities utils;
private ProfileUtilities utilsLeft;
private ProfileUtilities utilsRight;
public ProfileComparer(ComparisonSession session, ProfileUtilities utils) {
public ProfileComparer(ComparisonSession session, ProfileUtilities utilsLeft, ProfileUtilities utilsRight) {
super(session);
this.utils = utils;
this.utilsLeft = utilsLeft;
this.utilsRight = utilsRight;
}
@Override
@ -110,8 +125,8 @@ public class ProfileComparer extends CanonicalResourceComparer {
comparePrimitives("baseDefinition", left.getBaseDefinitionElement(), right.getBaseDefinitionElement(), res.getMetadata(), IssueSeverity.ERROR, res);
if (left.getType().equals(right.getType())) {
DefinitionNavigator ln = new DefinitionNavigator(session.getContext(), left);
DefinitionNavigator rn = new DefinitionNavigator(session.getContext(), right);
DefinitionNavigator ln = new DefinitionNavigator(session.getContextLeft(), left);
DefinitionNavigator rn = new DefinitionNavigator(session.getContextRight(), right);
StructuralMatch<ElementDefinition> sm = new StructuralMatch<ElementDefinition>(ln.current(), rn.current());
compareElements(res, sm, ln.path(), null, ln, rn);
res.combined = sm;
@ -122,9 +137,9 @@ public class ProfileComparer extends CanonicalResourceComparer {
private void check(StructureDefinition sd, String name) {
if (sd == null)
throw new DefinitionException("No StructureDefinition provided ("+name+": "+sd.getName()+")");
if (sd.getType().equals("Extension")) {
throw new DefinitionException("StructureDefinition is for an extension - use ExtensionComparer instead ("+name+": "+sd.getName()+")");
}
// if (sd.getType().equals("Extension")) {
// throw new DefinitionException("StructureDefinition is for an extension - use ExtensionComparer instead ("+name+": "+sd.getName()+")");
// }
if (sd.getDerivation() == TypeDerivationRule.SPECIALIZATION) {
throw new DefinitionException("StructureDefinition is not for an profile - can't be compared ("+name+": "+sd.getName()+")");
}
@ -143,10 +158,10 @@ public class ProfileComparer extends CanonicalResourceComparer {
}
// not allowed to be different:
ruleEqual(comp, res, left.current().getDefaultValue(), right.current().getDefaultValue(), "defaultValue", path);
ruleEqual(comp, res, left.current().getMeaningWhenMissingElement(), right.current().getMeaningWhenMissingElement(), "meaningWhenMissing", path);
ruleEqual(comp, res, left.current().getIsModifierElement(), right.current().getIsModifierElement(), "isModifier", path);
ruleEqual(comp, res, left.current().getIsSummaryElement(), right.current().getIsSummaryElement(), "isSummary", path);
// ruleEqual(comp, res, left.current().getDefaultValue(), right.current().getDefaultValue(), "defaultValue", path);
// ruleEqual(comp, res, left.current().getMeaningWhenMissingElement(), right.current().getMeaningWhenMissingElement(), "meaningWhenMissing", path);
// ruleEqual(comp, res, left.current().getIsModifierElement(), right.current().getIsModifierElement(), "isModifier", path); - this check belongs in the core
// ruleEqual(comp, res, left.current().getIsSummaryElement(), right.current().getIsSummaryElement(), "isSummary", path); - so does this
// we ignore slicing right now - we're going to clone the root one anyway, and then think about clones
// simple stuff
@ -317,15 +332,15 @@ public class ProfileComparer extends CanonicalResourceComparer {
} else if (vRight == null) {
vm(IssueSeverity.ERROR, "Removed "+name, path, comp.getMessages(), res.getMessages());
} else if (!Base.compareDeep(vLeft, vRight, false)) {
vm(IssueSeverity.ERROR, name+" must be the same ("+toString(vLeft)+"/"+toString(vRight)+")", path, comp.getMessages(), res.getMessages());
vm(IssueSeverity.ERROR, name+" must be the same ("+toString(vLeft, true)+"/"+toString(vRight, false)+")", path, comp.getMessages(), res.getMessages());
}
}
private String toString(DataType val) throws IOException {
private String toString(DataType val, boolean left) throws IOException {
if (val instanceof PrimitiveType)
return "\"" + ((PrimitiveType) val).getValueAsString()+"\"";
IParser jp = session.getContext().newJsonParser();
IParser jp = left ? session.getContextLeft().newJsonParser() : session.getContextRight().newJsonParser();
return jp.composeString(val, "value");
}
@ -468,13 +483,13 @@ public class ProfileComparer extends CanonicalResourceComparer {
private Collection<? extends TypeRefComponent> unionTypes(ProfileComparison comp, StructuralMatch<ElementDefinition> res, String path, List<TypeRefComponent> left, List<TypeRefComponent> right) throws DefinitionException, IOException, FHIRFormatError {
List<TypeRefComponent> result = new ArrayList<TypeRefComponent>();
for (TypeRefComponent l : left)
checkAddTypeUnion(comp, res, path, result, l);
checkAddTypeUnion(comp, res, path, result, l, session.getContextLeft());
for (TypeRefComponent r : right)
checkAddTypeUnion(comp, res, path, result, r);
checkAddTypeUnion(comp, res, path, result, r, session.getContextRight());
return result;
}
private void checkAddTypeUnion(ProfileComparison comp, StructuralMatch<ElementDefinition> res, String path, List<TypeRefComponent> results, TypeRefComponent nw) throws DefinitionException, IOException, FHIRFormatError {
private void checkAddTypeUnion(ProfileComparison comp, StructuralMatch<ElementDefinition> res, String path, List<TypeRefComponent> results, TypeRefComponent nw, IWorkerContext ctxt) throws DefinitionException, IOException, FHIRFormatError {
boolean pfound = false;
boolean tfound = false;
nw = nw.copy();
@ -491,15 +506,15 @@ public class ProfileComparer extends CanonicalResourceComparer {
ex.setProfile(null);
} else {
// both have profiles. Is one derived from the other?
StructureDefinition sdex = session.getContext().fetchResource(StructureDefinition.class, ex.getProfile().get(0).getValue());
StructureDefinition sdnw = session.getContext().fetchResource(StructureDefinition.class, nw.getProfile().get(0).getValue());
StructureDefinition sdex = ((IWorkerContext) ex.getUserData("ctxt")).fetchResource(StructureDefinition.class, ex.getProfile().get(0).getValue());
StructureDefinition sdnw = ctxt.fetchResource(StructureDefinition.class, nw.getProfile().get(0).getValue());
if (sdex != null && sdnw != null) {
if (sdex == sdnw) {
if (sdex.getUrl().equals(sdnw.getUrl())) {
pfound = true;
} else if (derivesFrom(sdex, sdnw)) {
} else if (derivesFrom(sdex, sdnw, ((IWorkerContext) ex.getUserData("ctxt")))) {
ex.setProfile(nw.getProfile());
pfound = true;
} else if (derivesFrom(sdnw, sdex)) {
} else if (derivesFrom(sdnw, sdex, ctxt)) {
pfound = true;
} else if (sdnw.getSnapshot().getElement().get(0).getPath().equals(sdex.getSnapshot().getElement().get(0).getPath())) {
ProfileComparison compP = (ProfileComparison) session.compare(sdex, sdnw);
@ -519,15 +534,15 @@ public class ProfileComparer extends CanonicalResourceComparer {
ex.setTargetProfile(null);
} else {
// both have profiles. Is one derived from the other?
StructureDefinition sdex = session.getContext().fetchResource(StructureDefinition.class, ex.getTargetProfile().get(0).getValue());
StructureDefinition sdnw = session.getContext().fetchResource(StructureDefinition.class, nw.getTargetProfile().get(0).getValue());
StructureDefinition sdex = ((IWorkerContext) ex.getUserData("ctxt")).fetchResource(StructureDefinition.class, ex.getTargetProfile().get(0).getValue());
StructureDefinition sdnw = ctxt.fetchResource(StructureDefinition.class, nw.getTargetProfile().get(0).getValue());
if (sdex != null && sdnw != null) {
if (sdex == sdnw) {
if (matches(sdex, sdnw)) {
tfound = true;
} else if (derivesFrom(sdex, sdnw)) {
} else if (derivesFrom(sdex, sdnw, ((IWorkerContext) ex.getUserData("ctxt")))) {
ex.setTargetProfile(nw.getTargetProfile());
tfound = true;
} else if (derivesFrom(sdnw, sdex)) {
} else if (derivesFrom(sdnw, sdex, ctxt)) {
tfound = true;
} else if (sdnw.getSnapshot().getElement().get(0).getPath().equals(sdex.getSnapshot().getElement().get(0).getPath())) {
ProfileComparison compP = (ProfileComparison) session.compare(sdex, sdnw);
@ -540,17 +555,33 @@ public class ProfileComparer extends CanonicalResourceComparer {
}
}
}
if (!tfound || !pfound)
if (!tfound || !pfound) {
nw.setUserData("ctxt", ctxt);
results.add(nw);
}
}
private boolean derivesFrom(StructureDefinition left, StructureDefinition right) {
private boolean matches(StructureDefinition s1, StructureDefinition s2) {
if (!s1.getUrl().equals(s2.getUrl())) {
return false;
}
if (s1.getDerivation() == TypeDerivationRule.SPECIALIZATION && s2.getDerivation() == TypeDerivationRule.SPECIALIZATION) {
return true; // arbitrary; we're just not interested in pursuing cross version differences
}
if (s1.hasVersion()) {
return s1.getVersion().equals(s2.getVersion());
} else {
return !s2.hasVersion();
}
}
private boolean derivesFrom(StructureDefinition left, StructureDefinition right, IWorkerContext ctxt) {
StructureDefinition sd = left;
while (sd != null) {
if (right.getUrl().equals(sd.getBaseDefinition())) {
return true;
}
sd = sd.hasBaseDefinition() ? session.getContext().fetchResource(StructureDefinition.class, sd.getBaseDefinition()) : null;
sd = sd.hasBaseDefinition() ? ctxt.fetchResource(StructureDefinition.class, sd.getBaseDefinition()) : null;
}
return false;
}
@ -574,14 +605,14 @@ public class ProfileComparer extends CanonicalResourceComparer {
pfound = true;
c.setProfile(r.getProfile());
} else {
StructureDefinition sdl = resolveProfile(comp, res, path, l.getProfile().get(0).getValue(), comp.getLeft().getName());
StructureDefinition sdr = resolveProfile(comp, res, path, r.getProfile().get(0).getValue(), comp.getRight().getName());
StructureDefinition sdl = resolveProfile(comp, res, path, l.getProfile().get(0).getValue(), comp.getLeft().getName(), session.getContextLeft());
StructureDefinition sdr = resolveProfile(comp, res, path, r.getProfile().get(0).getValue(), comp.getRight().getName(), session.getContextRight());
if (sdl != null && sdr != null) {
if (sdl == sdr) {
pfound = true;
} else if (derivesFrom(sdl, sdr)) {
} else if (derivesFrom(sdl, sdr, session.getContextLeft())) {
pfound = true;
} else if (derivesFrom(sdr, sdl)) {
} else if (derivesFrom(sdr, sdl, session.getContextRight())) {
c.setProfile(r.getProfile());
pfound = true;
} else if (sdl.getType().equals(sdr.getType())) {
@ -601,14 +632,14 @@ public class ProfileComparer extends CanonicalResourceComparer {
tfound = true;
c.setTargetProfile(r.getTargetProfile());
} else {
StructureDefinition sdl = resolveProfile(comp, res, path, l.getTargetProfile().get(0).getValue(), comp.getLeft().getName());
StructureDefinition sdr = resolveProfile(comp, res, path, r.getTargetProfile().get(0).getValue(), comp.getRight().getName());
StructureDefinition sdl = resolveProfile(comp, res, path, l.getTargetProfile().get(0).getValue(), comp.getLeft().getName(), session.getContextLeft());
StructureDefinition sdr = resolveProfile(comp, res, path, r.getTargetProfile().get(0).getValue(), comp.getRight().getName(), session.getContextRight());
if (sdl != null && sdr != null) {
if (sdl == sdr) {
if (matches(sdl, sdr)) {
tfound = true;
} else if (derivesFrom(sdl, sdr)) {
} else if (derivesFrom(sdl, sdr, session.getContextLeft())) {
tfound = true;
} else if (derivesFrom(sdr, sdl)) {
} else if (derivesFrom(sdr, sdl, session.getContextRight())) {
c.setTargetProfile(r.getTargetProfile());
tfound = true;
} else if (sdl.getType().equals(sdr.getType())) {
@ -713,8 +744,8 @@ public class ProfileComparer extends CanonicalResourceComparer {
return true;
} else {
// ok, now we compare the value sets. This may be unresolvable.
ValueSet lvs = resolveVS(comp.getLeft(), left.getValueSet());
ValueSet rvs = resolveVS(comp.getRight(), right.getValueSet());
ValueSet lvs = resolveVS(comp.getLeft(), left.getValueSet(), session.getContextLeft());
ValueSet rvs = resolveVS(comp.getRight(), right.getValueSet(), session.getContextRight());
if (lvs == null) {
vm(IssueSeverity.ERROR, "Unable to resolve left value set "+left.getValueSet().toString()+" at "+path, path, comp.getMessages(), res.getMessages());
return true;
@ -739,6 +770,9 @@ public class ProfileComparer extends CanonicalResourceComparer {
if (!lvs.getUrl().equals(rvs.getUrl())) {
return false;
}
if (isCore(lvs) && isCore(rvs)) {
return true;
}
if (lvs.hasVersion()) {
if (!lvs.getVersion().equals(rvs.getVersion())) {
return false;
@ -749,6 +783,10 @@ public class ProfileComparer extends CanonicalResourceComparer {
return true;
}
private boolean isCore(ValueSet vs) {
return vs.getUrl().startsWith("http://hl7.org/fhir/ValueSet");
}
private List<ElementDefinitionConstraintComponent> intersectConstraints(String path, List<ElementDefinitionConstraintComponent> left, List<ElementDefinitionConstraintComponent> right) {
List<ElementDefinitionConstraintComponent> result = new ArrayList<ElementDefinitionConstraintComponent>();
for (ElementDefinitionConstraintComponent l : left) {
@ -771,7 +809,9 @@ public class ProfileComparer extends CanonicalResourceComparer {
if (Utilities.equals(r.getId(), l.getId()) || (Utilities.equals(r.getXpath(), l.getXpath()) && r.getSeverity() == l.getSeverity()))
found = true;
if (!found) {
vm(IssueSeverity.INFORMATION, "StructureDefinition "+comp.getLeft().getName()+" has a constraint that is removed in "+comp.getRight().getName()+" and it is uncertain whether they are compatible ("+l.getExpression()+")", path, comp.getMessages(), res.getMessages());
if (!Utilities.existsInList(l.getExpression(), "hasValue() or (children().count() > id.count())", "extension.exists() != value.exists()")) {
vm(IssueSeverity.INFORMATION, "StructureDefinition "+comp.getLeft().getName()+" has a constraint that is removed in "+comp.getRight().getName()+" and it is uncertain whether they are compatible ("+l.getExpression()+")", path, comp.getMessages(), res.getMessages());
}
}
result.add(l);
}
@ -781,14 +821,16 @@ public class ProfileComparer extends CanonicalResourceComparer {
if (Utilities.equals(r.getId(), l.getId()) || (Utilities.equals(r.getXpath(), l.getXpath()) && r.getSeverity() == l.getSeverity()))
found = true;
if (!found) {
vm(IssueSeverity.INFORMATION, "StructureDefinition "+comp.getRight().getName()+" has added constraint that is not found in "+comp.getLeft().getName()+" and it is uncertain whether they are compatible ("+r.getExpression()+")", path, comp.getMessages(), res.getMessages());
if (!Utilities.existsInList(r.getExpression(), "hasValue() or (children().count() > id.count())", "extension.exists() != value.exists()")) {
vm(IssueSeverity.INFORMATION, "StructureDefinition "+comp.getRight().getName()+" has added constraint that is not found in "+comp.getLeft().getName()+" and it is uncertain whether they are compatible ("+r.getExpression()+")", path, comp.getMessages(), res.getMessages());
}
}
}
return result;
}
private StructureDefinition resolveProfile(ProfileComparison comp, StructuralMatch<ElementDefinition> res, String path, String url, String name) {
StructureDefinition sd = session.getContext().fetchResource(StructureDefinition.class, url);
private StructureDefinition resolveProfile(ProfileComparison comp, StructuralMatch<ElementDefinition> res, String path, String url, String name, IWorkerContext ctxt) {
StructureDefinition sd = ctxt.fetchResource(StructureDefinition.class, url);
if (sd == null) {
ValidationMessage vm = vmI(IssueSeverity.WARNING, "Unable to resolve profile "+url+" in profile "+name, path);
}
@ -809,8 +851,8 @@ public class ProfileComparer extends CanonicalResourceComparer {
if (Base.compareDeep(left.getValueSet(), right.getValueSet(), false))
union.setValueSet(left.getValueSet());
else {
ValueSet lvs = resolveVS(comp.getLeft(), left.getValueSet());
ValueSet rvs = resolveVS(comp.getRight(), right.getValueSet());
ValueSet lvs = resolveVS(comp.getLeft(), left.getValueSet(), session.getContextLeft());
ValueSet rvs = resolveVS(comp.getRight(), right.getValueSet(), session.getContextRight());
if (lvs != null && rvs != null) {
ValueSetComparison compP = (ValueSetComparison) session.compare(lvs, rvs);
if (compP != null) {
@ -825,15 +867,15 @@ public class ProfileComparer extends CanonicalResourceComparer {
return union;
}
private ValueSet resolveVS(StructureDefinition ctxtLeft, String vsRef) {
private ValueSet resolveVS(StructureDefinition ctxtLeft, String vsRef, IWorkerContext ctxt) {
if (vsRef == null)
return null;
return session.getContext().fetchResource(ValueSet.class, vsRef);
return ctxt.fetchResource(ValueSet.class, vsRef);
}
public XhtmlNode renderStructure(ProfileComparison comp, String id, String prefix, String corePath) throws FHIRException, IOException {
HierarchicalTableGenerator gen = new HierarchicalTableGenerator(Utilities.path("[tmp]", "compare"), false, true);
gen.setTranslator(session.getContext().translator());
gen.setTranslator(session.getContextRight().translator());
TableModel model = gen.initComparisonTable(corePath, id);
genElementComp(null /* oome back to this later */, gen, model.getRows(), comp.combined, corePath, prefix, null, true);
return gen.generate(model, prefix, 0, null);
@ -849,7 +891,7 @@ public class ProfileComparer extends CanonicalResourceComparer {
rows.add(row);
String path = combined.either().getPath();
row.setAnchor(path);
row.setColor(utils.getRowColor(combined.either(), false));
row.setColor(utilsRight.getRowColor(combined.either(), false));
if (eitherHasSlicing(combined))
row.setLineColor(1);
else if (eitherHasSliceName(combined))
@ -895,17 +937,17 @@ public class ProfileComparer extends CanonicalResourceComparer {
String leftColor = !combined.hasLeft() ? COLOR_NO_ROW_LEFT : combined.hasErrors() ? COLOR_DIFFERENT : null;
String rightColor = !combined.hasRight() ? COLOR_NO_ROW_LEFT : combined.hasErrors() ? COLOR_DIFFERENT : null;
if (combined.hasLeft()) {
nc = utils.genElementNameCell(gen, combined.getLeft(), "??", true, corePath, prefix, root, false, false, null, typesRow, row, false, ext, used , ref, sName);
nc = utilsRight.genElementNameCell(gen, combined.getLeft(), "??", true, corePath, prefix, root, false, false, null, typesRow, row, false, ext, used , ref, sName);
} else {
nc = utils.genElementNameCell(gen, combined.getRight(), "??", true, corePath, prefix, root, false, false, null, typesRow, row, false, ext, used , ref, sName);
nc = utilsRight.genElementNameCell(gen, combined.getRight(), "??", true, corePath, prefix, root, false, false, null, typesRow, row, false, ext, used , ref, sName);
}
if (combined.hasLeft()) {
frame(utils.genElementCells(gen, combined.getLeft(), "??", true, corePath, prefix, root, false, false, null, typesRow, row, false, ext, used , ref, sName, nc), leftColor);
frame(utilsRight.genElementCells(gen, combined.getLeft(), "??", true, corePath, prefix, root, false, false, null, typesRow, row, false, ext, used , ref, sName, nc), leftColor);
} else {
frame(spacers(row, 4, gen), leftColor);
}
if (combined.hasRight()) {
frame(utils.genElementCells(gen, combined.getRight(), "??", true, corePath, prefix, root, false, false, null, typesRow, row, false, ext, used, ref, sName, nc), rightColor);
frame(utilsRight.genElementCells(gen, combined.getRight(), "??", true, corePath, prefix, root, false, false, null, typesRow, row, false, ext, used, ref, sName, nc), rightColor);
} else {
frame(spacers(row, 4, gen), rightColor);
}

View File

@ -3,6 +3,13 @@ package org.hl7.fhir.r5.comparison;
import java.util.ArrayList;
import java.util.List;
import org.hl7.fhir.r5.comparison.ResourceComparer.MessageCounts;
import org.hl7.fhir.r5.comparison.ResourceComparer.ResourceComparison;
import org.hl7.fhir.r5.model.CanonicalResource;
import org.hl7.fhir.r5.model.CodeSystem;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
@ -14,11 +21,37 @@ import org.hl7.fhir.utilities.xhtml.NodeType;
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
public class ResourceComparer {
public static class MessageCounts {
private int errors;
private int warnings;
private int hints;
public int getErrors() {
return errors;
}
public int getWarnings() {
return warnings;
}
public int getHints() {
return hints;
}
public void error() {
errors++;
}
public void warning() {
warnings++;
}
public void hint() {
hints++;
}
}
public abstract class ResourceComparison {
public static abstract class ResourceComparison {
private String id;
private String leftId;
private String rightId;
private MessageCounts cnts;
public ResourceComparison(String leftId, String rightId) {
super();
@ -48,14 +81,144 @@ public class ResourceComparer {
}
protected abstract String summary();
protected abstract String fhirType();
protected abstract String toTable();
protected String color() {
if (hasErrors()) {
return COLOR_DIFFERENT;
} else if (noChange()) {
return COLOR_NO_CHANGE;
} else {
return COLOR_DIFFERENT_LESS;
}
}
protected boolean hasErrors() {
MessageCounts cnts = getCounts();
return cnts.getErrors() > 0;
}
protected boolean noChange() {
MessageCounts cnts = getCounts();
return cnts.getErrors() + cnts.getWarnings() + cnts.getHints() == 0;
}
protected String outcomeSummary() {
MessageCounts cnts = getCounts();
return
Integer.toString(cnts.getErrors())+" "+Utilities.pluralize("Breaking Change", cnts.getErrors())+", "+
Integer.toString(cnts.getWarnings())+" "+Utilities.pluralize("Change", cnts.getWarnings())+", "+
Integer.toString(cnts.getHints())+" "+Utilities.pluralize("Note", cnts.getHints());
}
public MessageCounts getCounts() {
if (cnts == null) {
cnts = new MessageCounts();
countMessages(cnts);
}
return cnts;
}
protected abstract void countMessages(MessageCounts cnts);
}
public static class PlaceHolderComparison extends ResourceComparison {
private CanonicalResource left;
private CanonicalResource right;
private Throwable e;
public PlaceHolderComparison(CanonicalResource left, CanonicalResource right) {
super(left == null ? right.getId() : left.getId(), right == null ? left.getId() : right.getId());
this.left = left;
this.right = right;
}
public PlaceHolderComparison(CanonicalResource left, CanonicalResource right, Throwable e) {
super(left == null ? right.getId() : left.getId(), right == null ? left.getId() : right.getId());
this.e = e;
this.left = left;
this.right = right;
}
@Override
protected String abbreviation() {
CanonicalResource cr = left == null ? right : left;
if (cr instanceof CodeSystem) {
return "cs";
} else if (cr instanceof ValueSet) {
return "vs";
} else if (cr instanceof StructureDefinition) {
return "sd";
} else {
return "xx";
}
}
@Override
protected String summary() {
if (e != null) {
return e.getMessage();
}
CanonicalResource cr = left == null ? right : left;
return cr.fhirType()+(left == null ? " Added" : " Removed");
}
@Override
protected String fhirType() {
CanonicalResource cr = left == null ? right : left;
return cr.fhirType();
}
@Override
protected String toTable() {
String s = null;
String color = null;
if (left != null && right != null && !left.getUrl().equals(right.getUrl())) {
s = "<td>"+left.getUrl()+"</td><td>"+right.getUrl()+"</td>";
} else if (left != null) {
s = "<td colspan=2>"+left.getUrl()+"</td>";
} else {
s = "<td colspan=2>"+right.getUrl()+"</td>";
}
if (left == null) {
s = s + "<td>Added</td>";
color = COLOR_NO_ROW_LEFT;
} else if (right == null) {
s = s + "<td>Removed</td>";
color = COLOR_NO_ROW_RIGHT;
} else {
s = s + "<td><a href=\""+getId()+".html\">Failed<a></td>";
color = COLOR_ISSUE;
}
s = s + "<td>"+(e != null ? Utilities.escapeXml(e.getMessage()) : "")+"</td>";
return "<tr style=\"background-color: "+color+"\">"+s+"</tr>\r\n";
}
public Throwable getE() {
return e;
}
@Override
protected void countMessages(MessageCounts cnts) {
if (e != null) {
cnts.error();
}
}
}
public final static String COLOR_NO_ROW_LEFT = "#ffffb3";
public final static String COLOR_NO_CELL_LEFT = "#ffff4d";
public final static String COLOR_NO_ROW_RIGHT = "#ffecb3";
public final static String COLOR_NO_CELL_RIGHT = "#ffcc33";
public final static String COLOR_DIFFERENT = "#f0b3ff";
public final static String COLOR_DIFFERENT_LESS = "#f8e6ff";
public final static String COLOR_ISSUE = "#ffad99";
public final static String COLOR_NO_CHANGE = "#ffffff";
protected ComparisonSession session;

View File

@ -3,6 +3,7 @@ package org.hl7.fhir.r5.comparison;
import java.util.ArrayList;
import java.util.List;
import org.hl7.fhir.r5.comparison.ResourceComparer.MessageCounts;
import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
@ -87,5 +88,21 @@ public class StructuralMatch<T> {
return false;
}
public void countMessages(MessageCounts cnts) {
for (ValidationMessage vm : getMessages()) {
if (vm.getLevel() == IssueSeverity.ERROR) {
cnts.error();
} else if (vm.getLevel() == IssueSeverity.WARNING) {
cnts.warning();
} else if (vm.getLevel() == IssueSeverity.INFORMATION) {
cnts.hint();
}
}
for (StructuralMatch<T> c : children) {
c.countMessages(cnts);
}
}
}

View File

@ -7,6 +7,8 @@ import java.util.List;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r5.comparison.ResourceComparer.MessageCounts;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.model.CanonicalType;
import org.hl7.fhir.r5.model.Element;
import org.hl7.fhir.r5.model.ValueSet;
@ -66,7 +68,26 @@ public class ValueSetComparer extends CanonicalResourceComparer {
@Override
protected String summary() {
return "ValueSet: "+left.present()+" vs "+right.present();
}
@Override
protected String fhirType() {
return "ValueSet";
}
@Override
protected void countMessages(MessageCounts cnts) {
super.countMessages(cnts);
if (includes != null) {
includes.countMessages(cnts);
}
if (excludes != null) {
excludes.countMessages(cnts);
}
if (expansion != null) {
expansion.countMessages(cnts);
}
}
}
public ValueSetComparer(ComparisonSession session) {
@ -372,16 +393,16 @@ public class ValueSetComparer extends CanonicalResourceComparer {
}
private void compareExpansions(ValueSet left, ValueSet right, ValueSetComparison res) {
ValueSet expL = left.hasExpansion() ? left : expand(left, res, "left");
ValueSet expR = left.hasExpansion() ? left : expand(right, res, "right");
ValueSet expL = left.hasExpansion() ? left : expand(left, res, "left", session.getContextLeft());
ValueSet expR = left.hasExpansion() ? left : expand(right, res, "right", session.getContextRight());
if (expL != null && expR != null) {
// ignore the parameters for now
compareConcepts(expL.getExpansion().getContains(), expR.getExpansion().getContains(), res.forceExpansion(), res.getUnion().getExpansion().getContains(), res.getIntersection().getExpansion().getContains(), "ValueSet.expansion.contains", res);
}
}
private ValueSet expand(ValueSet vs, ValueSetComparison res, String name) {
ValueSetExpansionOutcome vse =session.getContext().expandVS(vs, true, false);
private ValueSet expand(ValueSet vs, ValueSetComparison res, String name, IWorkerContext ctxt) {
ValueSetExpansionOutcome vse = ctxt.expandVS(vs, true, false);
if (vse.getValueset() != null) {
return vse.getValueset();
} else {
@ -682,6 +703,11 @@ public class ValueSetComparer extends CanonicalResourceComparer {
p.tx("Unable to generate expansion - see errors");
return p;
}
if (csc.getExpansion().getChildren().isEmpty()) {
XhtmlNode p = new XhtmlNode(NodeType.Element, "p");
p.tx("Expansion is empty");
return p;
}
// columns: code(+system), version, display , abstract, inactive,
boolean hasSystem = csc.getExpansion().getChildren().isEmpty() ? false : getSystemVaries(csc.getExpansion(), csc.getExpansion().getChildren().get(0).either().getSystem());
boolean hasVersion = findVersion(csc.getExpansion());

View File

@ -645,7 +645,7 @@ public class ProfileUtilities extends TranslatingUtilities {
wt = "OperationOutcome";
}
if (!sd.getType().equals(wt)) {
boolean ok = isCompatibleType(wt, sd.getType());
boolean ok = isCompatibleType(wt, sd);
if (!ok) {
String smsg = "The profile "+u.getValue()+" has type "+sd.getType()+" which is not consistent with the stated type "+wt;
if (exception)
@ -714,10 +714,17 @@ public class ProfileUtilities extends TranslatingUtilities {
}
private boolean isCompatibleType(String base, String type) {
StructureDefinition sd = context.fetchTypeDefinition(type);
private boolean isCompatibleType(String base, StructureDefinition sdt) {
StructureDefinition sdb = context.fetchTypeDefinition(base);
if (sdb.getType().equals(sdt.getType())) {
return true;
}
StructureDefinition sd = context.fetchTypeDefinition(sdt.getType());
while (sd != null) {
if (sd.getType().equals(base)) {
if (sd.getType().equals(sdb.getType())) {
return true;
}
if (sd.getUrl().equals(sdb.getUrl())) {
return true;
}
sd = context.fetchResource(StructureDefinition.class, sd.getBaseDefinition());
@ -1201,7 +1208,7 @@ public class ProfileUtilities extends TranslatingUtilities {
}
if (hasInnerDiffMatches(differential, currentBase.getPath(), diffCursor, diffLimit, base.getElement(), false)) {
if (baseHasChildren(base, currentBase)) { // not a new type here
throw new Error("This situation is not yet (constrain slicing to 1..1 and fix base slice for inline structure - please report issue to grahame@fhir.org along with a test case that reproduces this error (@ "+cpath+" | "+currentBase.getPath()+")");
throw new Error("This situation is not yet handled (constrain slicing to 1..1 and fix base slice for inline structure - please report issue to grahame@fhir.org along with a test case that reproduces this error (@ "+cpath+" | "+currentBase.getPath()+")");
} else {
StructureDefinition dt = getTypeForElement(differential, diffCursor, profileName, diffMatches, outcome);
contextName = dt.getUrl();
@ -4608,6 +4615,9 @@ public class ProfileUtilities extends TranslatingUtilities {
this.snapshot = snapshot;
this.prefixLength = prefixLength;
this.base = base;
if (Utilities.isAbsoluteUrl(base)) {
throw new Error("Wrong!");
}
this.name = name;
}
@ -4654,9 +4664,9 @@ public class ProfileUtilities extends TranslatingUtilities {
}
if (mandatory) {
if (prefixLength == 0)
errors.add("Differential contains path "+path+" which is not found in the base");
errors.add("Differential contains path "+path+" which is not found in the in base "+name);
else
errors.add("Differential contains path "+path+" which is actually "+actual+", which is not found in the base");
errors.add("Differential contains path "+path+" which is actually "+actual+", which is not found in the in base "+name);
}
return 0;
}
@ -4812,12 +4822,12 @@ public class ProfileUtilities extends TranslatingUtilities {
if (profile==null)
ccmp = null; // this might happen before everything is loaded. And we don't so much care about sot order in this case
else
ccmp = new ElementDefinitionComparer(true, profile.getSnapshot().getElement(), ed.getType().get(0).getWorkingCode(), child.getSelf().getPath().length(), cmp.name);
ccmp = new ElementDefinitionComparer(true, profile.getSnapshot().getElement(), resolveType(ed.getType().get(0).getWorkingCode()), child.getSelf().getPath().length(), cmp.name);
} else if (ed.getType().size() == 1 && !ed.getType().get(0).getWorkingCode().equals("*")) {
StructureDefinition profile = context.fetchResource(StructureDefinition.class, sdNs(ed.getType().get(0).getWorkingCode()));
if (profile==null)
throw new FHIRException(context.formatMessage(I18nConstants.UNABLE_TO_RESOLVE_PROFILE__IN_ELEMENT_, sdNs(ed.getType().get(0).getWorkingCode()), ed.getPath()));
ccmp = new ElementDefinitionComparer(false, profile.getSnapshot().getElement(), ed.getType().get(0).getWorkingCode(), child.getSelf().getPath().length(), cmp.name);
ccmp = new ElementDefinitionComparer(false, profile.getSnapshot().getElement(), resolveType(ed.getType().get(0).getWorkingCode()), child.getSelf().getPath().length(), cmp.name);
} else if (child.getSelf().getType().size() == 1) {
StructureDefinition profile = context.fetchResource(StructureDefinition.class, sdNs(child.getSelf().getType().get(0).getWorkingCode()));
if (profile==null)
@ -4860,6 +4870,16 @@ public class ProfileUtilities extends TranslatingUtilities {
return ccmp;
}
private String resolveType(String code) {
if (Utilities.isAbsoluteUrl(code)) {
StructureDefinition sd = context.fetchResource(StructureDefinition.class, code);
if (sd != null) {
return sd.getType();
}
}
return code;
}
private static String sdNs(String type) {
return sdNs(type, null);
}

View File

@ -1,5 +1,7 @@
package org.hl7.fhir.r5.context;
import java.io.File;
/*
Copyright (c) 2011+, HL7, Inc.
All rights reserved.
@ -614,21 +616,28 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
p.setParameter("includeDefinition", false);
p.setParameter("excludeNested", !heirarchical);
List<String> allErrors = new ArrayList<>();
// ok, first we try to expand locally
ValueSetExpanderSimple vse = new ValueSetExpanderSimple(this);
try {
ValueSetExpanderSimple vse = new ValueSetExpanderSimple(this);
res = vse.doExpand(vs, p);
if (!res.getValueset().hasUrl()) {
throw new Error(formatMessage(I18nConstants.NO_URL_IN_EXPAND_VALUE_SET));
res = vse.expand(vs, p);
allErrors.addAll(vse.getAllErrors());
if (res.getValueset() != null) {
if (!res.getValueset().hasUrl()) {
throw new Error(formatMessage(I18nConstants.NO_URL_IN_EXPAND_VALUE_SET));
}
txCache.cacheExpansion(cacheToken, res, TerminologyCache.TRANSIENT);
return res;
}
txCache.cacheExpansion(cacheToken, res, TerminologyCache.TRANSIENT);
return res;
} catch (Exception e) {
allErrors.addAll(vse.getAllErrors());
e.printStackTrace();
}
// if that failed, we try to expand on the server
if (noTerminologyServer) {
return new ValueSetExpansionOutcome(formatMessage(I18nConstants.ERROR_EXPANDING_VALUESET_RUNNING_WITHOUT_TERMINOLOGY_SERVICES), TerminologyServiceErrorClass.NOSERVICE);
return new ValueSetExpansionOutcome(formatMessage(I18nConstants.ERROR_EXPANDING_VALUESET_RUNNING_WITHOUT_TERMINOLOGY_SERVICES), TerminologyServiceErrorClass.NOSERVICE, allErrors);
}
Map<String, String> params = new HashMap<String, String>();
params.put("_limit", Integer.toString(expandCodesLimit ));
@ -644,13 +653,12 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
}
res = new ValueSetExpansionOutcome(result).setTxLink(txLog.getLastId());
} catch (Exception e) {
res = new ValueSetExpansionOutcome(e.getMessage() == null ? e.getClass().getName() : e.getMessage(), TerminologyServiceErrorClass.UNKNOWN).setTxLink(txLog == null ? null : txLog.getLastId());
res = new ValueSetExpansionOutcome(e.getMessage() == null ? e.getClass().getName() : e.getMessage(), TerminologyServiceErrorClass.UNKNOWN, allErrors).setTxLink(txLog == null ? null : txLog.getLastId());
}
txCache.cacheExpansion(cacheToken, res, TerminologyCache.PERMANENT);
return res;
}
private boolean hasTooCostlyExpansion(ValueSet valueset) {
return valueset != null && valueset.hasExpansion() && ToolingExtensions.hasExtension(valueset.getExpansion(), ToolingExtensions.EXT_EXP_TOOCOSTLY);
}
@ -842,6 +850,9 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
// --------------------------------------------------------------------------------------------------------------------------------------------------------
public void initTS(String cachePath) throws Exception {
if (!new File(cachePath).exists()) {
Utilities.createDirectory(cachePath);
}
txCache = new TerminologyCache(lock, cachePath);
}
@ -1603,4 +1614,12 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
return this;
}
public String getTxCache() {
return txCache.getFolder();
}
public TerminologyClient getTxClient() {
return txClient;
}
}

View File

@ -64,10 +64,13 @@ import org.hl7.fhir.r5.terminologies.ValueSetExpander.TerminologyServiceErrorCla
import org.hl7.fhir.r5.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
import org.hl7.fhir.r5.utils.IResourceValidator;
import org.hl7.fhir.utilities.TranslationServices;
import org.hl7.fhir.utilities.cache.BasePackageCacheManager;
import org.hl7.fhir.utilities.cache.NpmPackage;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
import org.hl7.fhir.utilities.validation.ValidationOptions;
import com.google.gson.JsonSyntaxException;
/**
* This is the standard interface used for access to underlying FHIR
@ -150,7 +153,18 @@ public interface IWorkerContext {
* @param resource
* @return null if not tracking paths
*/
String getResourcePath(Resource resource);
String getResourcePath(Resource resource);
/**
* called when a mew package is being loaded
*
* this is called by loadPacakgeAndDependencies when a new package is loaded
* @param npm
* @return
* @throws IOException
* @throws JsonSyntaxException
*/
IContextResourceLoader getNewLoader(NpmPackage npm) throws JsonSyntaxException, IOException;
}
@ -660,7 +674,45 @@ public interface IWorkerContext {
public String getLinkForUrl(String corePath, String s);
public Map<String, byte[]> getBinaries();
void loadFromPackage(NpmPackage pi, IContextResourceLoader loader, String[] types) throws FileNotFoundException, IOException, FHIRException;
/**
* Load relevant resources of the appropriate types (as specified by the loader) from the nominated package
*
* note that the package system uses lazy loading; the loader will be called later when the classes that use the context need the relevant resource
*
* @param pi - the package to load
* @param loader - an implemenation of IContextResourceLoader that knows how to read the resources in the package (e.g. for the appropriate version).
* @return the number of resources loaded
*/
int loadFromPackage(NpmPackage pi, IContextResourceLoader loader) throws FileNotFoundException, IOException, FHIRException;
/**
* Load relevant resources of the appropriate types (as specified by the loader) from the nominated package
*
* note that the package system uses lazy loading; the loader will be called later when the classes that use the context need the relevant resource
*
* Deprecated - use the simpler method where the types come from the loader.
*
* @param pi - the package to load
* @param loader - an implemenation of IContextResourceLoader that knows how to read the resources in the package (e.g. for the appropriate version).
* @param types - which types of resources to load
* @return the number of resources loaded
*/
@Deprecated
int loadFromPackage(NpmPackage pi, IContextResourceLoader loader, String[] types) throws FileNotFoundException, IOException, FHIRException;
/**
* Load relevant resources of the appropriate types (as specified by the loader) from the nominated package
*
* note that the package system uses lazy loading; the loader will be called later when the classes that use the context need the relevant resource
*
* This method also loads all the packages that the package depends on (recursively)
*
* @param pi - the package to load
* @param loader - an implemenation of IContextResourceLoader that knows how to read the resources in the package (e.g. for the appropriate version).
* @param pcm - used to find and load additional dependencies
* @return the number of resources loaded
*/
int loadFromPackageAndDependencies(NpmPackage pi, IContextResourceLoader loader, BasePackageCacheManager pcm) throws FileNotFoundException, IOException, FHIRException;
public boolean hasPackage(String id, String ver);

View File

@ -88,6 +88,8 @@ import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
import org.hl7.fhir.utilities.validation.ValidationMessage.Source;
import com.google.gson.JsonObject;
import ca.uhn.fhir.parser.DataFormatException;
/*
@ -370,7 +372,46 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
@Override
public void loadFromPackage(NpmPackage pi, IContextResourceLoader loader, String... types) throws FileNotFoundException, IOException, FHIRException {
public int loadFromPackage(NpmPackage pi, IContextResourceLoader loader) throws FileNotFoundException, IOException, FHIRException {
return loadFromPackageInt(pi, loader, loader == null ? defaultTypesToLoad() : loader.getTypes());
}
public static String[] defaultTypesToLoad() {
// there's no penalty for listing resources that don't exist, so we just all the relevant possibilities for all versions
return new String[] {"CodeSystem", "ValueSet", "ConceptMap", "NamingSystem",
"StructureDefinition", "StructureMap",
"SearchParameter", "OperationDefinition", "CapabilityStatement", "Conformance",
"Questionnaire", "ImplementationGuide" };
}
@Override
public int loadFromPackage(NpmPackage pi, IContextResourceLoader loader, String[] types) throws FileNotFoundException, IOException, FHIRException {
return loadFromPackageInt(pi, loader, types);
}
@Override
public int loadFromPackageAndDependencies(NpmPackage pi, IContextResourceLoader loader, BasePackageCacheManager pcm) throws FileNotFoundException, IOException, FHIRException {
return loadFromPackageAndDependenciesInt(pi, loader, pcm, pi.name()+"#"+pi.version());
}
public int loadFromPackageAndDependenciesInt(NpmPackage pi, IContextResourceLoader loader, BasePackageCacheManager pcm, String path) throws FileNotFoundException, IOException, FHIRException {
int t = 0;
for (String e : pi.dependencies()) {
if (!loadedPackages.contains(e) && !VersionUtilities.isCorePackage(e)) {
NpmPackage npm = pcm.loadPackage(e);
if (!version.equals(npm.fhirVersion())) {
System.out.println(formatMessage(I18nConstants.PACKAGE_VERSION_MISMATCH, e, version, npm.fhirVersion(), path));
}
t = t + loadFromPackageAndDependenciesInt(npm, loader.getNewLoader(npm), pcm, path+" -> "+npm.name()+"#"+npm.version());
}
}
t = t + loadFromPackageInt(pi, loader, loader.getTypes());
return t;
}
public int loadFromPackageInt(NpmPackage pi, IContextResourceLoader loader, String... types) throws FileNotFoundException, IOException, FHIRException {
int t = 0;
if (progress) {
System.out.println("Load Package "+pi.name()+"#"+pi.version());
}
@ -388,6 +429,7 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
for (String s : pi.listResources(loader.getTypes())) {
try {
loadDefinitionItem(s, pi.load("package", s), loader, null, new PackageVersion(pi.id(), pi.version()));
t++;
} catch (FHIRException e) {
throw new FHIRException(formatMessage(I18nConstants.ERROR_READING__FROM_PACKAGE__, s, pi.name(), pi.version(), e.getMessage()), e);
}
@ -399,6 +441,7 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
for (PackageResourceInformation pri : pi.listIndexedResources(types)) {
try {
registerResourceFromPackage(new PackageResourceLoader(pri, loader), new PackageVersion(pi.id(), pi.version()));
t++;
} catch (FHIRException e) {
throw new FHIRException(formatMessage(I18nConstants.ERROR_READING__FROM_PACKAGE__, pri.getFilename(), pi.name(), pi.version(), e.getMessage()), e);
}
@ -410,6 +453,7 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
if (version == null) {
version = pi.version();
}
return t;
}
public void loadFromFile(String file, IContextResourceLoader loader) throws IOException, FHIRException {
@ -757,5 +801,7 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
}

View File

@ -469,6 +469,10 @@ public class TerminologyCache {
}
}
}
public String getFolder() {
return folder;
}
}

View File

@ -611,7 +611,6 @@ public class ProfileDrivenRenderer extends ResourceRenderer {
// x.an(v.get("id").primitiveValue());
// }
// }
System.out.print("c");
} else if (!exemptFromRendering(child)) {
List<ElementDefinition> grandChildren = getChildrenForPath(allElements, path+"."+p.getName());
filterGrandChildren(grandChildren, path+"."+p.getName(), p);
@ -807,9 +806,14 @@ public class ProfileDrivenRenderer extends ResourceRenderer {
String[] list = displayHint.split(";");
for (String item : list) {
String[] parts = item.split(":");
if (parts.length != 2)
throw new DefinitionException("error reading display hint: '"+displayHint+"'");
hints.put(parts[0].trim(), parts[1].trim());
if (parts.length == 1) {
hints.put("value", parts[0].trim());
} else {
if (parts.length != 2) {
throw new DefinitionException("error reading display hint: '"+displayHint+"'");
}
hints.put(parts[0].trim(), parts[1].trim());
}
}
}
}

View File

@ -33,6 +33,8 @@ package org.hl7.fhir.r5.terminologies;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.hl7.fhir.r5.model.Parameters;
import org.hl7.fhir.r5.model.ValueSet;
@ -65,6 +67,7 @@ public interface ValueSetExpander {
private String error;
private TerminologyServiceErrorClass errorClass;
private String txLink;
private List<String> allErrors = new ArrayList<>();
public ValueSetExpansionOutcome(ValueSet valueset) {
super();
@ -76,18 +79,31 @@ public interface ValueSetExpander {
this.valueset = valueset;
this.error = error;
this.errorClass = errorClass;
allErrors.add(error);
}
public ValueSetExpansionOutcome(ValueSetChecker service, String error, TerminologyServiceErrorClass errorClass) {
super();
this.valueset = null;
this.error = error;
this.errorClass = errorClass;
allErrors.add(error);
}
public ValueSetExpansionOutcome(String error, TerminologyServiceErrorClass errorClass) {
this.valueset = null;
this.error = error;
this.errorClass = errorClass;
allErrors.add(error);
}
public ValueSetExpansionOutcome(String error, TerminologyServiceErrorClass errorClass, List<String> errList) {
this.valueset = null;
this.error = error;
this.errorClass = errorClass;
this.allErrors.addAll(errList);
if (!allErrors.contains(error)) {
allErrors.add(error);
}
}
public ValueSet getValueset() {
return valueset;
}
@ -104,7 +120,9 @@ public interface ValueSetExpander {
this.txLink = txLink;
return this;
}
public List<String> getAllErrors() {
return allErrors;
}
}
/**

View File

@ -66,6 +66,7 @@ import java.io.IOException;
*/
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@ -104,9 +105,6 @@ import org.hl7.fhir.r5.model.ValueSet.ValueSetComposeComponent;
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionComponent;
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent;
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionParameterComponent;
import org.hl7.fhir.r5.terminologies.ValueSetExpanderSimple.AllConceptsFilter;
import org.hl7.fhir.r5.terminologies.ValueSetExpanderSimple.IConceptFilter;
import org.hl7.fhir.r5.terminologies.ValueSetExpanderSimple.PropertyFilter;
import org.hl7.fhir.r5.utils.ToolingExtensions;
import org.hl7.fhir.utilities.Utilities;
@ -128,18 +126,18 @@ public class ValueSetExpanderSimple implements ValueSetExpander {
if (pc != null) {
String v = pc.getValue().isPrimitive() ? pc.getValue().primitiveValue() : null;
switch (filter.getOp()) {
case DESCENDENTOF: throw new FHIRException("not supported yet");
case DESCENDENTOF: throw fail("not supported yet: "+filter.getOp().toCode());
case EQUAL: return filter.getValue().equals(v);
case EXISTS: throw new FHIRException("not supported yet");
case GENERALIZES: throw new FHIRException("not supported yet");
case IN: throw new FHIRException("not supported yet");
case ISA: throw new FHIRException("not supported yet");
case ISNOTA: throw new FHIRException("not supported yet");
case NOTIN: throw new FHIRException("not supported yet");
case NULL: throw new FHIRException("not supported yet");
case REGEX: throw new FHIRException("not supported yet");
case EXISTS: throw fail("not supported yet: "+filter.getOp().toCode());
case GENERALIZES: throw fail("not supported yet: "+filter.getOp().toCode());
case IN: throw fail("not supported yet: "+filter.getOp().toCode());
case ISA: throw fail("not supported yet: "+filter.getOp().toCode());
case ISNOTA: throw fail("not supported yet: "+filter.getOp().toCode());
case NOTIN: throw fail("not supported yet: "+filter.getOp().toCode());
case NULL: throw fail("not supported yet: "+filter.getOp().toCode());
case REGEX: throw fail("not supported yet: "+filter.getOp().toCode());
default:
throw new FHIRException("Shouldn't get here");
throw fail("Shouldn't get here");
}
} else if (property.getType() == PropertyType.BOOLEAN && filter.getOp() == FilterOperator.EQUAL) {
return "false".equals(filter.getValue());
@ -183,14 +181,22 @@ public class ValueSetExpanderSimple implements ValueSetExpander {
private Set<String> excludeSystems = new HashSet<String>();
private ValueSet focus;
private int maxExpansionSize = 500;
private List<String> allErrors = new ArrayList<>();
private int total;
private boolean checkCodesWhenExpanding;
public ValueSetExpanderSimple(IWorkerContext context) {
super();
this.context = context;
}
public ValueSetExpanderSimple(IWorkerContext context, List<String> allErrors) {
super();
this.context = context;
this.allErrors = allErrors;
}
public void setMaxExpansionSize(int theMaxExpansionSize) {
maxExpansionSize = theMaxExpansionSize;
}
@ -318,7 +324,7 @@ public class ValueSetExpanderSimple implements ValueSetExpander {
private void addCodes(ValueSetExpansionComponent expand, List<ValueSetExpansionParameterComponent> params, Parameters expParams, List<ValueSet> filters) throws ETooCostly, FHIRException {
if (expand != null) {
if (expand.getContains().size() > maxExpansionSize)
throw new ETooCostly("Too many codes to display (>" + Integer.toString(expand.getContains().size()) + ")");
throw failCostly("Too many codes to display (>" + Integer.toString(expand.getContains().size()) + ")");
for (ValueSetExpansionParameterComponent p : expand.getParameter()) {
if (!existsInParams(params, p.getName(), p.getValue()))
params.add(p);
@ -343,7 +349,7 @@ public class ValueSetExpanderSimple implements ValueSetExpander {
}
if (exc.hasValueSet())
throw new Error("Processing Value set references in exclude is not yet done in "+ctxt);
throw fail("Processing Value set references in exclude is not yet done in "+ctxt);
// importValueSet(imp.getValue(), params, expParams);
CodeSystem cs = context.fetchCodeSystem(exc.getSystem());
@ -351,7 +357,7 @@ public class ValueSetExpanderSimple implements ValueSetExpander {
ValueSetExpansionOutcome vse = context.expandVS(exc, false);
ValueSet valueset = vse.getValueset();
if (valueset == null)
throw new TerminologyServiceException("Error Expanding ValueSet: "+vse.getError());
throw failTSE("Error Expanding ValueSet: "+vse.getError());
excludeCodes(valueset.getExpansion(), params);
return;
}
@ -361,9 +367,11 @@ public class ValueSetExpanderSimple implements ValueSetExpander {
}
if (exc.getFilter().size() > 0)
throw new NotImplementedException("not done yet");
throw fail("not done yet - multiple filters");
}
private void excludeCodes(ValueSetExpansionComponent expand, List<ValueSetExpansionParameterComponent> params) {
for (ValueSetExpansionContainsComponent c : expand.getContains()) {
excludeCode(c.getSystem(), c.getCode());
@ -380,22 +388,23 @@ public class ValueSetExpanderSimple implements ValueSetExpander {
@Override
public ValueSetExpansionOutcome expand(ValueSet source, Parameters expParams) {
allErrors.clear();
try {
return doExpand(source, expParams);
return expandInternal(source, expParams);
} catch (NoTerminologyServiceException e) {
// well, we couldn't expand, so we'll return an interface to a checker that can check membership of the set
// that might fail too, but it might not, later.
return new ValueSetExpansionOutcome(e.getMessage(), TerminologyServiceErrorClass.NOSERVICE);
} catch (RuntimeException e) {
// TODO: we should put something more specific instead of just Exception below, since
// it swallows bugs.. what would be expected to be caught there?
throw e;
return new ValueSetExpansionOutcome(e.getMessage(), TerminologyServiceErrorClass.NOSERVICE, allErrors);
} catch (Exception e) {
// well, we couldn't expand, so we'll return an interface to a checker that can check membership of the set
// that might fail too, but it might not, later.
return new ValueSetExpansionOutcome(e.getMessage(), TerminologyServiceErrorClass.UNKNOWN);
return new ValueSetExpansionOutcome(e.getMessage(), TerminologyServiceErrorClass.UNKNOWN, allErrors);
}
}
public ValueSetExpansionOutcome expandInternal(ValueSet source, Parameters expParams) throws FHIRException, FileNotFoundException, ETooCostly, IOException {
return doExpand(source, expParams);
}
public ValueSetExpansionOutcome doExpand(ValueSet source, Parameters expParams) throws FHIRException, ETooCostly, FileNotFoundException, IOException {
if (expParams == null)
@ -467,18 +476,24 @@ public class ValueSetExpanderSimple implements ValueSetExpander {
canBeHeirarchy = false;
includeCodes(inc, exp, expParams, canBeHeirarchy, extensions);
}
}
private ValueSet importValueSet(String value, ValueSetExpansionComponent exp, Parameters expParams) throws ETooCostly, TerminologyServiceException, FileNotFoundException, IOException, FHIRFormatError {
if (value == null)
throw new TerminologyServiceException("unable to find value set with no identity");
throw fail("unable to find value set with no identity");
ValueSet vs = context.fetchResource(ValueSet.class, value);
if (vs == null)
throw new TerminologyServiceException("Unable to find imported value set " + value);
ValueSetExpansionOutcome vso = new ValueSetExpanderSimple(context).expand(vs, expParams);
if (vso.getError() != null)
throw new TerminologyServiceException("Unable to expand imported value set: " + vso.getError());
if (vs == null) {
if (context.fetchResource(CodeSystem.class, value) != null) {
throw fail("Cannot include value set "+value+" because it's actually a code system");
} else {
throw fail("Unable to find imported value set " + value);
}
}
ValueSetExpansionOutcome vso = new ValueSetExpanderSimple(context, allErrors).expand(vs, expParams);
if (vso.getError() != null) {
addErrors(vso.getAllErrors());
throw fail("Unable to expand imported value set "+vs.getUrl()+": " + vso.getError());
}
if (vs.hasVersion())
if (!existsInParams(exp.getParameter(), "version", new UriType(vs.getUrl() + "|" + vs.getVersion())))
exp.getParameter().add(new ValueSetExpansionParameterComponent().setName("version").setValue(new UriType(vs.getUrl() + "|" + vs.getVersion())));
@ -499,6 +514,14 @@ public class ValueSetExpanderSimple implements ValueSetExpander {
return vso.getValueset();
}
private void addErrors(List<String> errs) {
for (String s : errs) {
if (!allErrors.contains(s)) {
allErrors.add(s);
}
}
}
private void copyImportContains(List<ValueSetExpansionContainsComponent> list, ValueSetExpansionContainsComponent parent, Parameters expParams, List<ValueSet> filter) throws FHIRException {
for (ValueSetExpansionContainsComponent c : list) {
c.checkNoModifiers("Imported Expansion in Code System", "expanding");
@ -534,7 +557,7 @@ public class ValueSetExpanderSimple implements ValueSetExpander {
private void doServerIncludeCodes(ConceptSetComponent inc, boolean heirarchical, ValueSetExpansionComponent exp, List<ValueSet> imports, Parameters expParams, List<Extension> extensions) throws FHIRException {
ValueSetExpansionOutcome vso = context.expandVS(inc, heirarchical);
if (vso.getError() != null) {
throw new TerminologyServiceException("Unable to expand imported value set: " + vso.getError());
throw failTSE("Unable to expand imported value set: " + vso.getError());
}
ValueSet vs = vso.getValueset();
if (vs.hasVersion()) {
@ -571,13 +594,13 @@ public class ValueSetExpanderSimple implements ValueSetExpander {
public void doInternalIncludeCodes(ConceptSetComponent inc, ValueSetExpansionComponent exp, Parameters expParams, List<ValueSet> imports, CodeSystem cs) throws NoTerminologyServiceException, TerminologyServiceException, FHIRException {
if (cs == null) {
if (context.isNoTerminologyServer())
throw new NoTerminologyServiceException("Unable to find code system " + inc.getSystem().toString());
throw failTSE("Unable to find code system " + inc.getSystem().toString());
else
throw new TerminologyServiceException("Unable to find code system " + inc.getSystem().toString());
throw failTSE("Unable to find code system " + inc.getSystem().toString());
}
cs.checkNoModifiers("Code System", "expanding");
if (cs.getContent() != CodeSystemContentMode.COMPLETE && cs.getContent() != CodeSystemContentMode.FRAGMENT)
throw new TerminologyServiceException("Code system " + inc.getSystem().toString() + " is incomplete");
throw failTSE("Code system " + inc.getSystem().toString() + " is incomplete");
if (cs.hasVersion())
if (!existsInParams(exp.getParameter(), "version", new UriType(cs.getUrl() + "|" + cs.getVersion())))
exp.getParameter().add(new ValueSetExpansionParameterComponent().setName("version").setValue(new UriType(cs.getUrl() + "|" + cs.getVersion())));
@ -602,7 +625,9 @@ public class ValueSetExpanderSimple implements ValueSetExpander {
if (cs.getContent() == CodeSystemContentMode.FRAGMENT) {
addFragmentWarning(exp, cs);
} else {
throw new TerminologyServiceException("Unable to find code '" + c.getCode() + "' in code system " + cs.getUrl());
if (checkCodesWhenExpanding) {
throw failTSE("Unable to find code '" + c.getCode() + "' in code system " + cs.getUrl());
}
}
} else {
inactive = CodeSystemUtilities.isInactive(cs, def);
@ -612,7 +637,7 @@ public class ValueSetExpanderSimple implements ValueSetExpander {
}
if (inc.getFilter().size() > 1) {
canBeHeirarchy = false; // which will bt the case if we get around to supporting this
throw new TerminologyServiceException("Multiple filters not handled yet"); // need to and them, and this isn't done yet. But this shouldn't arise in non loinc and snomed value sets
throw failTSE("Multiple filters not handled yet"); // need to and them, and this isn't done yet. But this shouldn't arise in non loinc and snomed value sets
}
if (inc.getFilter().size() == 1) {
if (cs.getContent() == CodeSystemContentMode.FRAGMENT) {
@ -623,13 +648,13 @@ public class ValueSetExpanderSimple implements ValueSetExpander {
// special: all codes in the target code system under the value
ConceptDefinitionComponent def = getConceptForCode(cs.getConcept(), fc.getValue());
if (def == null)
throw new TerminologyServiceException("Code '" + fc.getValue() + "' not found in system '" + inc.getSystem() + "'");
throw failTSE("Code '" + fc.getValue() + "' not found in system '" + inc.getSystem() + "'");
addCodeAndDescendents(cs, inc.getSystem(), def, null, expParams, imports, null, new AllConceptsFilter());
} 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 new TerminologyServiceException("Code '" + fc.getValue() + "' not found in system '" + inc.getSystem() + "'");
throw failTSE("Code '" + fc.getValue() + "' not found in system '" + inc.getSystem() + "'");
for (ConceptDefinitionComponent def : cs.getConcept()) {
addCodeAndDescendents(cs, inc.getSystem(), def, null, expParams, imports, defEx, new AllConceptsFilter());
}
@ -637,7 +662,7 @@ public class ValueSetExpanderSimple implements ValueSetExpander {
// special: all codes in the target code system under the value
ConceptDefinitionComponent def = getConceptForCode(cs.getConcept(), fc.getValue());
if (def == null)
throw new TerminologyServiceException("Code '" + fc.getValue() + "' not found in system '" + inc.getSystem() + "'");
throw failTSE("Code '" + fc.getValue() + "' not found in system '" + inc.getSystem() + "'");
for (ConceptDefinitionComponent c : def.getConcept())
addCodeAndDescendents(cs, inc.getSystem(), c, null, expParams, imports, null, new AllConceptsFilter());
if (def.hasUserData(CodeSystemUtilities.USER_DATA_CROSS_LINK)) {
@ -663,7 +688,7 @@ public class ValueSetExpanderSimple implements ValueSetExpander {
addCodeAndDescendents(cs, inc.getSystem(), def, null, expParams, imports, null, new PropertyFilter(fc, getPropertyDefinition(cs, fc.getProperty())));
}
} else {
throw new NotImplementedException("Search by property[" + fc.getProperty() + "] and op[" + fc.getOp() + "] is not supported yet");
throw fail("Search by property[" + fc.getProperty() + "] and op[" + fc.getOp() + "] is not supported yet");
}
}
}
@ -714,4 +739,31 @@ public class ValueSetExpanderSimple implements ValueSetExpander {
return key(c.getSystem(), c.getCode());
}
private FHIRException fail(String msg) {
allErrors.add(msg);
return new FHIRException(msg);
}
private ETooCostly failCostly(String msg) {
allErrors.add(msg);
return new ETooCostly(msg);
}
private TerminologyServiceException failTSE(String msg) {
allErrors.add(msg);
return new TerminologyServiceException(msg);
}
public Collection<? extends String> getAllErrors() {
return allErrors;
}
public boolean isCheckCodesWhenExpanding() {
return checkCodesWhenExpanding;
}
public void setCheckCodesWhenExpanding(boolean checkCodesWhenExpanding) {
this.checkCodesWhenExpanding = checkCodesWhenExpanding;
}
}

View File

@ -87,6 +87,11 @@ public class SnapShotGenerationTests {
return null;
}
@Override
public IContextResourceLoader getNewLoader(NpmPackage npm) {
return this;
}
}
public enum TestFetchMode {

View File

@ -1,6 +1,7 @@
package org.hl7.fhir.utilities.cache;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.utilities.Utilities;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -155,4 +156,8 @@ public abstract class BasePackageCacheManager implements IPackageCacheManager {
}
}
public NpmPackage loadPackage(String idAndVer) throws FHIRException, IOException {
return loadPackage(idAndVer, null);
}
}

View File

@ -14,4 +14,13 @@ public interface IPackageCacheManager {
String getPackageUrl(String packageId) throws IOException;
NpmPackage loadPackage(String id, String version) throws FHIRException, IOException;
/**
*
* @param idAndVer - use id#ver
* @return
* @throws FHIRException
* @throws IOException
*/
NpmPackage loadPackage(String idAndVer) throws FHIRException, IOException;
}

View File

@ -114,4 +114,12 @@ public class PackageHacker {
}
}
public static String fixPackageUrl(String webref) {
// workaround for past publishing problems
if (webref.equals("file://C:\\GitHub\\hl7.fhir.us.qicore#4.0.0\\output")) {
return "http://hl7.org/fhir/us/qicore/STU4";
}
return webref;
}
}

View File

@ -2,12 +2,14 @@ package org.hl7.fhir.utilities.i18n;
public class I18nConstants {
public static final String ADDING_WRONG_PATH = "Adding_wrong_path";
public static final String ADDING_WRONG_PATH_IN_PROFILE___VS_ = "Adding_wrong_path_in_profile___vs_";
public static final String ADDING_WRONG_PATH__OUTCOMEGETPATH___RESULTPATHBASE__ = "Adding_wrong_path__outcomegetPath___resultPathBase__";
public static final String ALL_OBSERVATIONS_SHOULD_HAVE_AN_EFFECTIVEDATETIME_OR_AN_EFFECTIVEPERIOD = "All_observations_should_have_an_effectiveDateTime_or_an_effectivePeriod";
public static final String ALL_OBSERVATIONS_SHOULD_HAVE_A_PERFORMER = "All_observations_should_have_a_performer";
public static final String ALL_OBSERVATIONS_SHOULD_HAVE_A_SUBJECT = "All_observations_should_have_a_subject";
public static final String ALL_OK = "ALL_OK";
public static final String ATTEMPT_TO_A_SLICE_AN_ELEMENT_THAT_DOES_NOT_REPEAT__FROM__IN_ = "Attempt_to_a_slice_an_element_that_does_not_repeat__from__in_";
public static final String ATTEMPT_TO_REPLACE_ELEMENT_NAME_FOR_A_NONCHOICE_TYPE = "Attempt_to_replace_element_name_for_a_nonchoice_type";
public static final String ATTEMPT_TO_USE_A_SNAPSHOT_ON_PROFILE__AS__BEFORE_IT_IS_GENERATED = "Attempt_to_use_a_snapshot_on_profile__as__before_it_is_generated";
@ -79,6 +81,7 @@ public class I18nConstants {
public static final String ERROR_AT_PATH__SLICE_NAME_MUST_BE__BUT_IS_ = "Error_at_path__Slice_name_must_be__but_is_";
public static final String ERROR_AT__THE_TARGET_PROFILE__IS_NOT__VALID_CONSTRAINT_ON_THE_BASE_ = "Error_at__The_target_profile__is_not__valid_constraint_on_the_base_";
public static final String ERROR_EXPANDING_VALUESET_RUNNING_WITHOUT_TERMINOLOGY_SERVICES = "Error_expanding_ValueSet_running_without_terminology_services";
public static final String ERROR_GENERATING_SNAPSHOT = "ERROR_GENERATING_SNAPSHOT";
public static final String ERROR_GENERATING_TABLE_FOR_PROFILE__ = "Error_generating_table_for_profile__";
public static final String ERROR_IN_PROFILE__AT__BASE_ISSUMMARY___DERIVED_ISSUMMARY__ = "Error_in_profile__at__Base_isSummary___derived_isSummary__";
public static final String ERROR_PARSING_ = "Error_parsing_";
@ -103,7 +106,6 @@ public class I18nConstants {
public static final String EXTENSION_EXT_SIMPLE = "Extension_EXT_Simple";
public static final String EXTENSION_EXT_SUBEXTENSION_INVALID = "Extension_EXT_SubExtension_Invalid";
public static final String EXTENSION_EXT_TYPE = "Extension_EXT_Type";
public static final String EXTENSION_PROF_TYPE = "Extension_PROF_Type";
public static final String EXTENSION_EXT_UNKNOWN = "Extension_EXT_Unknown";
public static final String EXTENSION_EXT_UNKNOWN_NOTHERE = "Extension_EXT_Unknown_NotHere";
public static final String EXTENSION_EXT_URL_ABSOLUTE = "Extension_EXT_URL_Absolute";
@ -112,6 +114,50 @@ public class I18nConstants {
public static final String EXTENSION_EXT_VERSION_INVALID = "Extension_EXT_Version_Invalid";
public static final String EXTENSION_EXT_VERSION_INVALIDID = "Extension_EXT_Version_InvalidId";
public static final String EXTENSION_EXT_VERSION_NOCHANGE = "Extension_EXT_Version_NoChange";
public static final String EXTENSION_PROF_TYPE = "Extension_PROF_Type";
public static final String FHIRPATH_ALIAS_COLLECTION = "FHIRPATH_ALIAS_COLLECTION";
public static final String FHIRPATH_CANNOT_USE = "FHIRPATH_CANNOT_USE";
public static final String FHIRPATH_CANT_COMPARE = "FHIRPATH_CANT_COMPARE";
public static final String FHIRPATH_CHECK_FAILED = "FHIRPATH_CHECK_FAILED";
public static final String FHIRPATH_CODED_ONLY = "FHIRPATH_CODED_ONLY";
public static final String FHIRPATH_DISCRIMINATOR_BAD_NAME = "FHIRPATH_DISCRIMINATOR_BAD_NAME";
public static final String FHIRPATH_DISCRIMINATOR_BAD_SYNTAX_CONST = "FHIRPATH_DISCRIMINATOR_BAD_SYNTAX_CONST";
public static final String FHIRPATH_DISCRIMINATOR_BAD_SYNTAX_GROUP = "FHIRPATH_DISCRIMINATOR_BAD_SYNTAX_GROUP";
public static final String FHIRPATH_DISCRIMINATOR_CANT_FIND = "FHIRPATH_DISCRIMINATOR_CANT_FIND";
public static final String FHIRPATH_DISCRIMINATOR_MULTIPLE_PROFILES = "FHIRPATH_DISCRIMINATOR_MULTIPLE_PROFILES";
public static final String FHIRPATH_DISCRIMINATOR_MULTIPLE_TYPES = "FHIRPATH_DISCRIMINATOR_MULTIPLE_TYPES";
public static final String FHIRPATH_DISCRIMINATOR_NAME_ALREADY_SLICED = "FHIRPATH_DISCRIMINATOR_NAME_ALREADY_SLICED";
public static final String FHIRPATH_DISCRIMINATOR_NOTYPE = "FHIRPATH_DISCRIMINATOR_NOTYPE";
public static final String FHIRPATH_DISCRIMINATOR_NO_CODE = "FHIRPATH_DISCRIMINATOR_NO_CODE";
public static final String FHIRPATH_DISCRIMINATOR_RESOLVE_MULTIPLE_TYPES = "FHIRPATH_DISCRIMINATOR_RESOLVE_MULTIPLE_TYPES";
public static final String FHIRPATH_DISCRIMINATOR_RESOLVE_NOT_REFERENCE = "FHIRPATH_DISCRIMINATOR_RESOLVE_NOT_REFERENCE";
public static final String FHIRPATH_DISCRIMINATOR_RESOLVE_NO_TYPE = "FHIRPATH_DISCRIMINATOR_RESOLVE_NO_TYPE";
public static final String FHIRPATH_DISCRIMINATOR_THIS_CANNOT_FIND = "FHIRPATH_DISCRIMINATOR_THIS_CANNOT_FIND";
public static final String FHIRPATH_DISCRIMINATOR_TYPE_MULTIPLE = "FHIRPATH_DISCRIMINATOR_TYPE_MULTIPLE";
public static final String FHIRPATH_DISCRIMINATOR_TYPE_NONE = "FHIRPATH_DISCRIMINATOR_TYPE_NONE";
public static final String FHIRPATH_HO_HOST_SERVICES = "FHIRPATH_HO_HOST_SERVICES";
public static final String FHIRPATH_LEFT_VALUE_PLURAL = "FHIRPATH_LEFT_VALUE_PLURAL";
public static final String FHIRPATH_LEFT_VALUE_WRONG_TYPE = "FHIRPATH_LEFT_VALUE_WRONG_TYPE";
public static final String FHIRPATH_LOCATION = "FHIRPATH_LOCATION";
public static final String FHIRPATH_NOT_IMPLEMENTED = "FHIRPATH_NOT_IMPLEMENTED";
public static final String FHIRPATH_NO_COLLECTION = "FHIRPATH_NO_COLLECTION";
public static final String FHIRPATH_NO_TYPE = "FHIRPATH_NO_TYPE";
public static final String FHIRPATH_OP_INCOMPATIBLE = "FHIRPATH_OP_INCOMPATIBLE";
public static final String FHIRPATH_ORDERED_ONLY = "FHIRPATH_ORDERED_ONLY";
public static final String FHIRPATH_PARAM_WRONG = "FHIRPATH_PARAM_WRONG";
public static final String FHIRPATH_PRIMITIVE_ONLY = "FHIRPATH_PRIMITIVE_ONLY";
public static final String FHIRPATH_REFERENCE_ONLY = "FHIRPATH_ORDERED_ONLY";
public static final String FHIRPATH_RESOLVE_DISCRIMINATOR_CANT_FIND = "FHIRPATH_RESOLVE_DISCRIMINATOR_CANT_FIND";
public static final String FHIRPATH_RESOLVE_DISCRIMINATOR_NO_TARGET = "FHIRPATH_RESOLVE_DISCRIMINATOR_NO_TARGET";
public static final String FHIRPATH_RIGHT_VALUE_PLURAL = "FHIRPATH_RIGHT_VALUE_PLURAL";
public static final String FHIRPATH_RIGHT_VALUE_WRONG_TYPE = "FHIRPATH_RIGHT_VALUE_WRONG_TYPE";
public static final String FHIRPATH_STRING_ONLY = "FHIRPATH_STRING_ONLY";
public static final String FHIRPATH_UNABLE_BOOLEAN = "FHIRPATH_UNABLE_BOOLEAN";
public static final String FHIRPATH_UNKNOWN_CONSTANT = "FHIRPATH_UNKNOWN_CONSTANT";
public static final String FHIRPATH_UNKNOWN_CONTEXT = "FHIRPATH_UNKNOWN_CONTEXT";
public static final String FHIRPATH_UNKNOWN_CONTEXT_ELEMENT = "FHIRPATH_UNKNOWN_CONTEXT_ELEMENT";
public static final String FHIRPATH_UNKNOWN_NAME = "FHIRPATH_UNWKNOWN_NAME";
public static final String FHIRPATH_WRONG_PARAM_TYPE = "FHIRPATH_WRONG_PARAM_TYPE";
public static final String FIXED_TYPE_CHECKS_DT_ADDRESS_LINE = "Fixed_Type_Checks_DT_Address_Line";
public static final String FIXED_TYPE_CHECKS_DT_NAME_FAMILY = "Fixed_Type_Checks_DT_Name_Family";
public static final String FIXED_TYPE_CHECKS_DT_NAME_GIVEN = "Fixed_Type_Checks_DT_Name_Given";
@ -125,8 +171,8 @@ public class I18nConstants {
public static final String ILLEGAL_PATH__IN_DIFFERENTIAL_IN__NAME_PORTION_EXCEEDS_64_CHARS_IN_LENGTH = "Illegal_path__in_differential_in__name_portion_exceeds_64_chars_in_length";
public static final String ILLEGAL_PATH__IN_DIFFERENTIAL_IN__NAME_PORTION_MISING_ = "Illegal_path__in_differential_in__name_portion_mising_";
public static final String ILLEGAL_PATH__IN_DIFFERENTIAL_IN__NO_UNICODE_WHITESPACE = "Illegal_path__in_differential_in__no_unicode_whitespace";
public static final String INTERNAL_ERROR___TYPE_NOT_KNOWN_ = "Internal_error___type_not_known_";
public static final String INTERNAL_ERROR = "Internal_error";
public static final String INTERNAL_ERROR___TYPE_NOT_KNOWN_ = "Internal_error___type_not_known_";
public static final String INTERNAL_INT_BAD_TYPE = "Internal_INT_Bad_Type";
public static final String INTERNAL_RECURSION_DETECTION_FIND_LOOP_PATH_RECURSION____CHECK_PATHS_ARE_VALID_FOR_PATH_ = "Internal_recursion_detection_find_loop_path_recursion____check_paths_are_valid_for_path_";
public static final String INVALID_SLICING__THERE_IS_MORE_THAN_ONE_TYPE_SLICE_AT__BUT_ONE_OF_THEM__HAS_MIN__1_SO_THE_OTHER_SLICES_CANNOT_EXIST = "Invalid_slicing__there_is_more_than_one_type_slice_at__but_one_of_them__has_min__1_so_the_other_slices_cannot_exist";
@ -210,6 +256,7 @@ public class I18nConstants {
public static final String NO_VALUE_SET_IN_URL = "no_value_set";
public static final String NULL_MIN = "null_min";
public static final String OBJECT_MUST_HAVE_SOME_CONTENT = "Object_must_have_some_content";
public static final String PACKAGE_VERSION_MISMATCH = "PACKAGE_VERSION_MISMATCH";
public static final String PARSER_TYPE__NOT_SUPPORTED = "Parser_Type__not_supported";
public static final String PROBLEM_EVALUATING_SLICING_EXPRESSION_FOR_ELEMENT_IN_PROFILE__PATH__FHIRPATH___ = "Problem_evaluating_slicing_expression_for_element_in_profile__path__fhirPath___";
public static final String PROBLEM_PROCESSING_EXPRESSION__IN_PROFILE__PATH__ = "Problem_processing_expression__in_profile__path__";
@ -286,12 +333,17 @@ public class I18nConstants {
public static final String RESOURCE_RES_ID_PROHIBITED = "Resource_RES_ID_Prohibited";
public static final String RESOURCE_TYPE_MISMATCH_FOR___ = "Resource_type_mismatch_for___";
public static final String SAME_ID_ON_MULTIPLE_ELEMENTS__IN_ = "Same_id_on_multiple_elements__in_";
public static final String SEARCHPARAMETER_BASE_WRONG = "SEARCHPARAMETER_BASE_WRONG";
public static final String SEARCHPARAMETER_EXP_WRONG = "SEARCHPARAMETER_EXP_WRONG";
public static final String SEARCHPARAMETER_NOTFOUND = "SEARCHPARAMETER_NOTFOUND";
public static final String SEARCHPARAMETER_TYPE_WRONG = "SEARCHPARAMETER_TYPE_WRONG";
public static final String SECURITY_STRING_CONTENT_ERROR = "SECURITY_STRING_CONTENT_ERROR";
public static final String SECURITY_STRING_CONTENT_WARNING = "SECURITY_STRING_CONTENT_WARNING";
public static final String SLICE_ENCOUNTERED_MIDWAY_THROUGH_SET_PATH___ID___ = "Slice_encountered_midway_through_set_path___id___";
public static final String SLICING_RULES_ON_DIFFERENTIAL__DO_NOT_MATCH_THOSE_ON_BASE___DISCIMINATOR___ = "Slicing_rules_on_differential__do_not_match_those_on_base___disciminator___";
public static final String SLICING_RULES_ON_DIFFERENTIAL__DO_NOT_MATCH_THOSE_ON_BASE___ORDER___ = "Slicing_rules_on_differential__do_not_match_those_on_base___order___";
public static final String SLICING_RULES_ON_DIFFERENTIAL__DO_NOT_MATCH_THOSE_ON_BASE___RULE___ = "Slicing_rules_on_differential__do_not_match_those_on_base___rule___";
public static final String SNAPSHOT_EXISTING_PROBLEM = "SNAPSHOT_EXISTING_PROBLEM";
public static final String STRUCTUREDEFINITION__AT__ILLEGAL_CONSTRAINED_TYPE__FROM__IN_ = "StructureDefinition__at__illegal_constrained_type__from__in_";
public static final String TERMINOLOGY_PASSTHROUGH_TX_MESSAGE = "Terminology_PassThrough_TX_Message";
public static final String TERMINOLOGY_TX_BINDING_CANTCHECK = "Terminology_TX_Binding_CantCheck";
@ -360,6 +412,10 @@ public class I18nConstants {
public static final String THIS_PROPERTY_MUST_BE_A_URI_OR_BNODE_NOT_A_ = "This_property_must_be_a_URI_or_bnode_not_a_";
public static final String THIS_PROPERTY_MUST_BE__NOT_ = "This_property_must_be__not_";
public static final String THIS__CANNOT_BE_PARSED_AS_A_FHIR_OBJECT_NO_NAMESPACE = "This__cannot_be_parsed_as_a_FHIR_object_no_namespace";
public static final String TYPE_CHECKS_FIXED_CC = "TYPE_CHECKS_FIXED_CC";
public static final String TYPE_CHECKS_FIXED_CC_US = "TYPE_CHECKS_FIXED_CC_US";
public static final String TYPE_CHECKS_PATTERN_CC = "TYPE_CHECKS_PATTERN_CC";
public static final String TYPE_CHECKS_PATTERN_CC_US = "TYPE_CHECKS_PATTERN_CC_US";
public static final String TYPE_ON_FIRST_DIFFERENTIAL_ELEMENT = "type_on_first_differential_element";
public static final String TYPE_ON_FIRST_SNAPSHOT_ELEMENT_FOR__IN__FROM_ = "type_on_first_snapshot_element_for__in__from_";
public static final String TYPE_SPECIFIC_CHECKS_CANONICAL_ABSOLUTE = "TYPE_SPECIFIC_CHECKS_CANONICAL_ABSOLUTE";
@ -466,6 +522,7 @@ public class I18nConstants {
public static final String UNXPECTED_INTERNAL_CONDITION__NO_SOURCE_ON_DIFF_ELEMENT = "Unxpected_internal_condition__no_source_on_diff_element";
public static final String VALIDATION_BUNDLE_MESSAGE = "Validation_BUNDLE_Message";
public static final String VALIDATION_VAL_CONTENT_UNKNOWN = "Validation_VAL_Content_Unknown";
public static final String VALIDATION_VAL_GLOBAL_PROFILE_UNKNOWN = "VALIDATION_VAL_GLOBAL_PROFILE_UNKNOWN";
public static final String VALIDATION_VAL_ILLEGAL_TYPE_CONSTRAINT = "VALIDATION_VAL_ILLEGAL_TYPE_CONSTRAINT";
public static final String VALIDATION_VAL_NOTYPE = "Validation_VAL_NoType";
public static final String VALIDATION_VAL_PROFILE_MATCHMULTIPLE = "Validation_VAL_Profile_MatchMultiple";
@ -481,12 +538,21 @@ public class I18nConstants {
public static final String VALIDATION_VAL_PROFILE_NOTSLICE = "Validation_VAL_Profile_NotSlice";
public static final String VALIDATION_VAL_PROFILE_NOTYPE = "Validation_VAL_Profile_NoType";
public static final String VALIDATION_VAL_PROFILE_OUTOFORDER = "Validation_VAL_Profile_OutOfOrder";
public static final String VALIDATION_VAL_PROFILE_SIGNPOST = "VALIDATION_VAL_PROFILE_SIGNPOST";
public static final String VALIDATION_VAL_PROFILE_SIGNPOST_GLOBAL = "VALIDATION_VAL_PROFILE_SIGNPOST_GLOBAL";
public static final String VALIDATION_VAL_PROFILE_SIGNPOST_META = "VALIDATION_VAL_PROFILE_SIGNPOST_META";
public static final String VALIDATION_VAL_PROFILE_SLICEORDER = "Validation_VAL_Profile_SliceOrder";
public static final String VALIDATION_VAL_PROFILE_UNKNOWN = "Validation_VAL_Profile_Unknown";
public static final String VALIDATION_VAL_GLOBAL_PROFILE_UNKNOWN = "VALIDATION_VAL_GLOBAL_PROFILE_UNKNOWN";
public static final String VALIDATION_VAL_PROFILE_WRONGTYPE = "Validation_VAL_Profile_WrongType";
public static final String VALIDATION_VAL_PROFILE_WRONGTYPE2 = "Validation_VAL_Profile_WrongType2";
public static final String VALIDATION_VAL_UNKNOWN_PROFILE = "Validation_VAL_Unknown_Profile";
public static final String VALUESET_INCLUDE_INVALID_CONCEPT_CODE = "VALUESET_INCLUDE_INVALID_CONCEPT_CODE";
public static final String VALUESET_INCLUDE_INVALID_CONCEPT_CODE_VER = "VALUESET_INCLUDE_INVALID_CONCEPT_CODE_VER";
public static final String VALUESET_NO_SYSTEM_WARNING = "VALUESET_NO_SYSTEM_WARNING";
public static final String VALUESET_REFERENCE_INVALID_TYPE = "VALUESET_REFERENCE_INVALID_TYPE";
public static final String VALUESET_REFERENCE_UNKNOWN = "VALUESET_REFERENCE_UNKNOWN";
public static final String VALUESET_UNC_SYSTEM_WARNING = "VALUESET_UNC_SYSTEM_WARNING";
public static final String VALUESET_UNC_SYSTEM_WARNING_VER = "VALUESET_UNC_SYSTEM_WARNING_VER";
public static final String VERSION_MISMATCH_THE_CONTEXT_HAS_VERSION__LOADED_AND_THE_NEW_CONTENT_BEING_LOADED_IS_VERSION_ = "Version_mismatch_The_context_has_version__loaded_and_the_new_content_being_loaded_is_version_";
public static final String WRONG_NAMESPACE__EXPECTED_ = "Wrong_namespace__expected_";
public static final String WRONG_TYPE_FOR_RESOURCE = "Wrong_type_for_resource";
@ -494,6 +560,7 @@ public class I18nConstants {
public static final String XHTML_URL_INVALID = "XHTML_URL_INVALID";
public static final String XHTML_URL_INVALID_CHARS = "XHTML_URL_INVALID_CHARS";
public static final String XHTML_XHTML_ATTRIBUTE_ILLEGAL = "XHTML_XHTML_Attribute_Illegal";
public static final String XHTML_XHTML_DOCTYPE_ILLEGAL = "XHTML_XHTML_DOCTYPE_ILLEGAL";
public static final String XHTML_XHTML_ELEMENT_ILLEGAL = "XHTML_XHTML_Element_Illegal";
public static final String XHTML_XHTML_NAME_INVALID = "XHTML_XHTML_Name_Invalid";
public static final String XHTML_XHTML_NS_INVALID = "XHTML_XHTML_NS_InValid";
@ -504,68 +571,5 @@ public class I18nConstants {
public static final String _HAS_CHILDREN__AND_MULTIPLE_TYPES__IN_PROFILE_ = "_has_children__and_multiple_types__in_profile_";
public static final String _HAS_CHILDREN__FOR_TYPE__IN_PROFILE__BUT_CANT_FIND_TYPE = "_has_children__for_type__in_profile__but_cant_find_type";
public static final String _HAS_NO_CHILDREN__AND_NO_TYPES_IN_PROFILE_ = "_has_no_children__and_no_types_in_profile_";
public static final String ALL_OK = "ALL_OK";
public static final String SEARCHPARAMETER_NOTFOUND = "SEARCHPARAMETER_NOTFOUND";
public static final String SEARCHPARAMETER_BASE_WRONG = "SEARCHPARAMETER_BASE_WRONG";
public static final String SEARCHPARAMETER_TYPE_WRONG = "SEARCHPARAMETER_TYPE_WRONG";
public static final String SEARCHPARAMETER_EXP_WRONG = "SEARCHPARAMETER_EXP_WRONG";
public static final String VALUESET_NO_SYSTEM_WARNING = "VALUESET_NO_SYSTEM_WARNING";
public static final String VALUESET_UNC_SYSTEM_WARNING = "VALUESET_UNC_SYSTEM_WARNING";
public static final String VALUESET_UNC_SYSTEM_WARNING_VER = "VALUESET_UNC_SYSTEM_WARNING_VER";
public static final String VALUESET_INCLUDE_INVALID_CONCEPT_CODE = "VALUESET_INCLUDE_INVALID_CONCEPT_CODE";
public static final String VALUESET_INCLUDE_INVALID_CONCEPT_CODE_VER = "VALUESET_INCLUDE_INVALID_CONCEPT_CODE_VER";
public static final String TYPE_CHECKS_PATTERN_CC = "TYPE_CHECKS_PATTERN_CC";
public static final String TYPE_CHECKS_PATTERN_CC_US = "TYPE_CHECKS_PATTERN_CC_US";
public static final String TYPE_CHECKS_FIXED_CC = "TYPE_CHECKS_FIXED_CC";
public static final String TYPE_CHECKS_FIXED_CC_US = "TYPE_CHECKS_FIXED_CC_US";
public static final String VALIDATION_VAL_PROFILE_SIGNPOST = "VALIDATION_VAL_PROFILE_SIGNPOST";
public static final String VALIDATION_VAL_PROFILE_SIGNPOST_META = "VALIDATION_VAL_PROFILE_SIGNPOST_META";
public static final String VALIDATION_VAL_PROFILE_SIGNPOST_GLOBAL = "VALIDATION_VAL_PROFILE_SIGNPOST_GLOBAL";
public static final String ERROR_GENERATING_SNAPSHOT = "ERROR_GENERATING_SNAPSHOT";
public static final String SNAPSHOT_EXISTING_PROBLEM = "SNAPSHOT_EXISTING_PROBLEM";
public static final String FHIRPATH_LOCATION = "FHIRPATH_LOCATION";
public static final String FHIRPATH_UNKNOWN_CONTEXT = "FHIRPATH_UNKNOWN_CONTEXT";
public static final String FHIRPATH_UNKNOWN_CONTEXT_ELEMENT = "FHIRPATH_UNKNOWN_CONTEXT_ELEMENT";
public static final String FHIRPATH_ALIAS_COLLECTION = "FHIRPATH_ALIAS_COLLECTION";
public static final String FHIRPATH_UNKNOWN_NAME = "FHIRPATH_UNWKNOWN_NAME";
public static final String FHIRPATH_UNKNOWN_CONSTANT = "FHIRPATH_UNKNOWN_CONSTANT";
public static final String FHIRPATH_CANNOT_USE = "FHIRPATH_CANNOT_USE";
public static final String FHIRPATH_CANT_COMPARE = "FHIRPATH_CANT_COMPARE";
public static final String FHIRPATH_LEFT_VALUE_PLURAL = "FHIRPATH_LEFT_VALUE_PLURAL";
public static final String FHIRPATH_LEFT_VALUE_WRONG_TYPE = "FHIRPATH_LEFT_VALUE_WRONG_TYPE";
public static final String FHIRPATH_RIGHT_VALUE_PLURAL = "FHIRPATH_RIGHT_VALUE_PLURAL";
public static final String FHIRPATH_RIGHT_VALUE_WRONG_TYPE = "FHIRPATH_RIGHT_VALUE_WRONG_TYPE";
public static final String FHIRPATH_OP_INCOMPATIBLE = "FHIRPATH_OP_INCOMPATIBLE";
public static final String FHIRPATH_HO_HOST_SERVICES = "FHIRPATH_HO_HOST_SERVICES";
public static final String FHIRPATH_WRONG_PARAM_TYPE = "FHIRPATH_WRONG_PARAM_TYPE";
public static final String FHIRPATH_ORDERED_ONLY = "FHIRPATH_ORDERED_ONLY";
public static final String FHIRPATH_REFERENCE_ONLY = "FHIRPATH_ORDERED_ONLY";
public static final String FHIRPATH_CODED_ONLY = "FHIRPATH_CODED_ONLY";
public static final String FHIRPATH_STRING_ONLY = "FHIRPATH_STRING_ONLY";
public static final String FHIRPATH_PRIMITIVE_ONLY = "FHIRPATH_PRIMITIVE_ONLY";
public static final String FHIRPATH_NO_COLLECTION = "FHIRPATH_NO_COLLECTION";
public static final String FHIRPATH_NOT_IMPLEMENTED = "FHIRPATH_NOT_IMPLEMENTED";
public static final String FHIRPATH_PARAM_WRONG = "FHIRPATH_PARAM_WRONG";
public static final String FHIRPATH_CHECK_FAILED = "FHIRPATH_CHECK_FAILED";
public static final String FHIRPATH_NO_TYPE = "FHIRPATH_NO_TYPE";
public static final String FHIRPATH_DISCRIMINATOR_NAME_ALREADY_SLICED = "FHIRPATH_DISCRIMINATOR_NAME_ALREADY_SLICED";
public static final String FHIRPATH_DISCRIMINATOR_THIS_CANNOT_FIND = "FHIRPATH_DISCRIMINATOR_THIS_CANNOT_FIND";
public static final String FHIRPATH_DISCRIMINATOR_RESOLVE_NO_TYPE = "FHIRPATH_DISCRIMINATOR_RESOLVE_NO_TYPE";
public static final String FHIRPATH_DISCRIMINATOR_RESOLVE_MULTIPLE_TYPES = "FHIRPATH_DISCRIMINATOR_RESOLVE_MULTIPLE_TYPES";
public static final String FHIRPATH_DISCRIMINATOR_RESOLVE_NOT_REFERENCE = "FHIRPATH_DISCRIMINATOR_RESOLVE_NOT_REFERENCE";
public static final String FHIRPATH_RESOLVE_DISCRIMINATOR_NO_TARGET = "FHIRPATH_RESOLVE_DISCRIMINATOR_NO_TARGET";
public static final String FHIRPATH_RESOLVE_DISCRIMINATOR_CANT_FIND = "FHIRPATH_RESOLVE_DISCRIMINATOR_CANT_FIND";
public static final String FHIRPATH_DISCRIMINATOR_TYPE_NONE = "FHIRPATH_DISCRIMINATOR_TYPE_NONE";
public static final String FHIRPATH_DISCRIMINATOR_TYPE_MULTIPLE = "FHIRPATH_DISCRIMINATOR_TYPE_MULTIPLE";
public static final String FHIRPATH_DISCRIMINATOR_NO_CODE = "FHIRPATH_DISCRIMINATOR_NO_CODE";
public static final String FHIRPATH_DISCRIMINATOR_BAD_NAME = "FHIRPATH_DISCRIMINATOR_BAD_NAME";
public static final String FHIRPATH_DISCRIMINATOR_BAD_SYNTAX_GROUP = "FHIRPATH_DISCRIMINATOR_BAD_SYNTAX_GROUP";
public static final String FHIRPATH_DISCRIMINATOR_BAD_SYNTAX_CONST = "FHIRPATH_DISCRIMINATOR_BAD_SYNTAX_CONST";
public static final String FHIRPATH_DISCRIMINATOR_CANT_FIND = "FHIRPATH_DISCRIMINATOR_CANT_FIND";
public static final String FHIRPATH_DISCRIMINATOR_NOTYPE = "FHIRPATH_DISCRIMINATOR_NOTYPE";
public static final String FHIRPATH_DISCRIMINATOR_MULTIPLE_TYPES = "FHIRPATH_DISCRIMINATOR_MULTIPLE_TYPES";
public static final String FHIRPATH_DISCRIMINATOR_MULTIPLE_PROFILES = "FHIRPATH_DISCRIMINATOR_MULTIPLE_PROFILES";
public static final String FHIRPATH_UNABLE_BOOLEAN = "FHIRPATH_UNABLE_BOOLEAN";
public static final String XHTML_XHTML_DOCTYPE_ILLEGAL = "XHTML_XHTML_DOCTYPE_ILLEGAL";
}

View File

@ -1,10 +1,15 @@
package org.hl7.fhir.utilities.json;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import org.hl7.fhir.utilities.TextFile;
/*
Copyright (c) 2011+, HL7, Inc.
All rights reserved.
@ -128,4 +133,10 @@ public class JSONUtil {
}
}
public static JsonObject fetchJson(String source) throws IOException {
URL url = new URL(source);
URLConnection c = url.openConnection();
return (JsonObject) new com.google.gson.JsonParser().parse(TextFile.streamToString(c.getInputStream()));
}
}

View File

@ -147,7 +147,7 @@ Terminology_TX_NoValid_1 = None of the codes provided are in the value set {0} (
Terminology_TX_NoValid_10 = The code provided is not in the maximum value set {0} ({1}), and a code from this value set is required) (code = {2}#{3})
Terminology_TX_NoValid_11 = The code provided is not in the maximum value set {0} ({1}{2})
Terminology_TX_NoValid_12 = The Coding provided is not in the value set {0}, and a code is required from this value set. {1}
Terminology_TX_NoValid_13 = The Coding provided is not in the value set {0}, and a code should come from this value set unless it has no suitable code. {1}
Terminology_TX_NoValid_13 = The Coding provided ({2}) is not in the value set {0}, and a code should come from this value set unless it has no suitable code. {1}
Terminology_TX_NoValid_14 = The Coding provided 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_16 = The value provided ("{0}") is not in the value set {1} ({2}), and a code is required from this value set){3}
@ -567,4 +567,6 @@ FHIRPATH_DISCRIMINATOR_MULTIPLE_TYPES = Error in discriminator at {0}: no childr
FHIRPATH_DISCRIMINATOR_MULTIPLE_PROFILES = Error in discriminator at {0}: no children, multiple type profiles
FHIRPATH_UNABLE_BOOLEAN = Unable to evaluate as a boolean: {0}
XHTML_XHTML_DOCTYPE_ILLEGAL = Malformed XHTML: Found a DocType declaration, and these are not allowed (XXE security vulnerability protection)
PACKAGE_VERSION_MISMATCH = FHIR Version mismatch in package {0}: version is {2} but must be {1} (path: {3})
VALUESET_REFERENCE_UNKNOWN = The value set import {0} could not be found so cannot be checked
VALUESET_REFERENCE_INVALID_TYPE = The value set import {0} points to a resource of type {1} which is not valid

View File

@ -41,6 +41,7 @@ import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.utilities.cache.NpmPackage;
import org.hl7.fhir.utilities.cache.PackageClient;
import org.hl7.fhir.utilities.cache.BasePackageCacheManager;
import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager;
import org.hl7.fhir.utilities.cache.ToolsVersion;
import org.hl7.fhir.utilities.i18n.I18nBase;
@ -770,7 +771,7 @@ public class ValidationEngine implements IValidatorResourceFetcher {
}
public void loadIg(String src, boolean recursive) throws IOException, FHIRException, Exception {
NpmPackage npm = pcm.loadPackage(src, null);
NpmPackage npm = src.matches(FilesystemPackageCacheManager.PACKAGE_REGEX) ? pcm.loadPackage(src, null) : null;
if (npm != null) {
for (String s : npm.dependencies()) {
if (!context.getLoadedPackages().contains(s)) {

View File

@ -239,27 +239,30 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
if (c.getAppContext() instanceof Element) {
Element bnd = (Element) c.getAppContext();
Base res = resolveInBundle(url, bnd);
if (res != null)
if (res != null) {
return res;
}
}
Base res = resolveInBundle(url, c.getResource());
if (res != null)
if (res != null) {
return res;
}
res = resolveInBundle(url, c.getContainer());
if (res != null)
if (res != null) {
return res;
}
if (externalHostServices != null)
if (externalHostServices != null) {
return externalHostServices.resolveReference(c.getAppContext(), url, refContext);
else if (fetcher != null)
} else if (fetcher != null) {
try {
return fetcher.fetch(c.getAppContext(), url);
} catch (IOException e) {
throw new FHIRException(e);
}
else
} else {
throw new Error(context.formatMessage(I18nConstants.NOT_DONE_YET__RESOLVE__LOCALLY_2, url));
}
}
@ -1368,7 +1371,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
if (binding.hasExtension("http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"))
checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringExtension(binding, "http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet"), c, stack);
else
txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_13, describeReference(binding.getValueSet(), valueset), getErrorMessage(vr.getMessage()));
txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_13, describeReference(binding.getValueSet(), valueset), getErrorMessage(vr.getMessage()), gen(c));
} else if (binding.getStrength() == BindingStrength.PREFERRED) {
if (baseOnly) {
txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_14, describeReference(binding.getValueSet(), valueset), getErrorMessage(vr.getMessage()));
@ -1392,6 +1395,10 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
}
}
private String gen(Coding c) {
return c.getSystem()+"#"+c.getCode()+ (c.hasDisplay() ? " \""+c.getDisplay()+"\"" : "");
}
private boolean isValueSet(String url) {
try {
ValueSet vs = context.fetchResourceWithException(ValueSet.class, url);
@ -1633,6 +1640,11 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
if ("http://hl7.org/fhir/StructureDefinition/structuredefinition-normative-version".equals(extUrl)) {
list.get(0).setExpression("Element"); // well, it can't be used anywhere but the list of places it can be used is quite long
}
if (!VersionUtilities.isThisOrLater("4.6", context.getVersion())) {
if (Utilities.existsInList(extUrl, "http://hl7.org/fhir/StructureDefinition/capabilitystatement-expectation", "http://hl7.org/fhir/StructureDefinition/capabilitystatement-prohibited")) {
list.get(0).setExpression("Element"); // well, they can't be used anywhere but the list of places they can be used is quite long
}
}
return list;
}

View File

@ -2,10 +2,13 @@ package org.hl7.fhir.validation.instance.type;
import java.util.List;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.context.IWorkerContext.ValidationResult;
import org.hl7.fhir.r5.elementmodel.Element;
import org.hl7.fhir.r5.model.CodeSystem;
import org.hl7.fhir.r5.model.Coding;
import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.terminologies.ValueSetExpander.TerminologyServiceErrorClass;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.VersionUtilities;
@ -56,6 +59,23 @@ public class ValueSetValidator extends BaseValidator {
String system = include.getChildValue("system");
String version = include.getChildValue("version");
boolean systemOk = true;
List<Element> valuesets = include.getChildrenByName("valueSet");
int i = 0;
for (Element ve : valuesets) {
String v = ve.getValue();
ValueSet vs = context.fetchResource(ValueSet.class, v);
if (vs == null) {
NodeStack ns = stack.push(ve, i, ve.getProperty().getDefinition(), ve.getProperty().getDefinition());
Resource rs = context.fetchResource(Resource.class, v);
if (rs != null) {
warning(errors, IssueType.BUSINESSRULE, ns.getLiteralPath(), false, I18nConstants.VALUESET_REFERENCE_INVALID_TYPE, v, rs.fhirType());
} else {
warning(errors, IssueType.BUSINESSRULE, ns.getLiteralPath(), false, I18nConstants.VALUESET_REFERENCE_UNKNOWN, v);
}
}
i++;
}
List<Element> concepts = include.getChildrenByName("concept");
List<Element> filters = include.getChildrenByName("filter");
if (!Utilities.noString(system)) {

View File

@ -116,7 +116,7 @@ public class ComparisonTests {
CanonicalResource left = load("left");
CanonicalResource right = load("right");
ComparisonSession session = new ComparisonSession(context, "Comparison Tests", null);
ComparisonSession session = new ComparisonSession(context, context, "Comparison Tests", null);
if (left instanceof CodeSystem && right instanceof CodeSystem) {
CodeSystemComparer cs = new CodeSystemComparer(session);
@ -146,7 +146,7 @@ public class ComparisonTests {
ProfileUtilities utils = new ProfileUtilities(context, null, null);
genSnapshot(utils, (StructureDefinition) left);
genSnapshot(utils, (StructureDefinition) right);
ProfileComparer pc = new ProfileComparer(session, utils);
ProfileComparer pc = new ProfileComparer(session, utils, utils);
ProfileComparison csc = pc.compare((StructureDefinition) left, (StructureDefinition) right);
new org.hl7.fhir.r5.formats.JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path("[tmp]", "comparison", name + "-union.json")), csc.getUnion());
new org.hl7.fhir.r5.formats.JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path("[tmp]", "comparison", name + "-intersection.json")), csc.getIntersection());

View File

@ -213,7 +213,7 @@ public class ValidationTestSuite implements IEvaluationContext, IValidatorResour
else
val.validate(null, errors, IOUtils.toInputStream(testCaseContent, Charsets.UTF_8), FhirFormat.XML);
System.out.println(val.reportTimes());
checkOutcomes(errors, content);
checkOutcomes(errors, content, null);
if (content.has("profile")) {
System.out.print("** Profile: ");
JsonObject profile = content.getAsJsonObject("profile");
@ -244,7 +244,7 @@ public class ValidationTestSuite implements IEvaluationContext, IValidatorResour
else
val.validate(null, errorsProfile, IOUtils.toInputStream(testCaseContent, Charsets.UTF_8), FhirFormat.XML, asSdList(sd));
System.out.println(val.reportTimes());
checkOutcomes(errorsProfile, profile);
checkOutcomes(errorsProfile, profile, filename);
}
if (content.has("logical")) {
JsonObject logical = content.getAsJsonObject("logical");
@ -268,7 +268,7 @@ public class ValidationTestSuite implements IEvaluationContext, IValidatorResour
Assert.assertTrue(fp.evaluateToBoolean(null, le, le, le, fp.parse(exp)));
}
}
checkOutcomes(errorsLogical, logical);
checkOutcomes(errorsLogical, logical, "logical");
}
}
@ -330,7 +330,7 @@ public class ValidationTestSuite implements IEvaluationContext, IValidatorResour
}
}
private void checkOutcomes(List<ValidationMessage> errors, JsonObject focus) {
private void checkOutcomes(List<ValidationMessage> errors, JsonObject focus, String profile) {
JsonObject java = focus.getAsJsonObject("java");
int ec = 0;
int wc = 0;
@ -358,11 +358,11 @@ public class ValidationTestSuite implements IEvaluationContext, IValidatorResour
}
}
if (!TestingUtilities.context(version).isNoTerminologyServer() || !focus.has("tx-dependent")) {
Assert.assertEquals("Test " + name + ": Expected " + Integer.toString(java.get("errorCount").getAsInt()) + " errors, but found " + Integer.toString(ec) + ".", java.get("errorCount").getAsInt(), ec);
Assert.assertEquals("Test " + name + (profile == null ? "" : " profile: "+ profile) + ": Expected " + Integer.toString(java.get("errorCount").getAsInt()) + " errors, but found " + Integer.toString(ec) + ".", java.get("errorCount").getAsInt(), ec);
if (java.has("warningCount"))
Assert.assertEquals( "Test " + name + ": Expected " + Integer.toString(java.get("warningCount").getAsInt()) + " warnings, but found " + Integer.toString(wc) + ".", java.get("warningCount").getAsInt(), wc);
Assert.assertEquals( "Test " + name + (profile == null ? "" : " profile: "+ profile) + ": Expected " + Integer.toString(java.get("warningCount").getAsInt()) + " warnings, but found " + Integer.toString(wc) + ".", java.get("warningCount").getAsInt(), wc);
if (java.has("infoCount"))
Assert.assertEquals( "Test " + name + ": Expected " + Integer.toString(java.get("infoCount").getAsInt()) + " hints, but found " + Integer.toString(hc) + ".", java.get("infoCount").getAsInt(), hc);
Assert.assertEquals( "Test " + name + (profile == null ? "" : " profile: "+ profile) + ": Expected " + Integer.toString(java.get("infoCount").getAsInt()) + " hints, but found " + Integer.toString(hc) + ".", java.get("infoCount").getAsInt(), hc);
}
if (java.has("error-locations")) {
JsonArray el = java.getAsJsonArray("error-locations");