Merge branch 'release' into merge_branch

This commit is contained in:
Mark Iantorno 2020-06-12 19:34:50 -04:00 committed by GitHub
commit f5455bb9e9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 451 additions and 456 deletions

View File

@ -1,7 +1,8 @@
* Override extension methods in BackboneElement to look in modifierExtensions as well as extensions
* First draft of Profile Comparison tools (org.hl7.fhir.r5.comparison)
* Improved error messages when snapshot generation fails when slicing something that doesn't repeat
* Improvements for CDA round-tripping (XML esacping issues, xsi:type related issues, namespacing issues)
* Fix bug rendering DiagnosticReports with multiple categories
* adjust check on Attachment to only be an warning (when no meaningful content exists)
* add security check mode to Validator
* Override extension methods in BackboneElement to look in modifierExtensions as well as extensions
* First draft of Profile Comparison tools (org.hl7.fhir.r5.comparison)
* Improved error messages when snapshot generation fails when slicing something that doesn't repeat
* Improvements for CDA round-tripping (XML esacping issues, xsi:type related issues, namespacing issues)
* Fix bug rendering DiagnosticReports with multiple categories
* adjust check on Attachment to only be an warning (when no meaningful content exists)
* add security check mode to Validator

View File

@ -1,212 +1,213 @@
package org.hl7.fhir.r5.comparison;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
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.ResourceComparison;
import org.hl7.fhir.r5.comparison.ValueSetComparer.ValueSetComparison;
import org.hl7.fhir.r5.conformance.ProfileUtilities;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.formats.IParser.OutputStyle;
import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.ExpressionNode.CollectionStatus;
import org.hl7.fhir.r5.model.StringType;
import org.hl7.fhir.r5.model.Tuple;
import org.hl7.fhir.r5.model.TypeDetails;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.utils.FHIRPathEngine.IEvaluationContext;
import org.hl7.fhir.r5.utils.LiquidEngine;
import org.hl7.fhir.r5.utils.LiquidEngine.LiquidDocument;
import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.xhtml.XhtmlComposer;
public class ComparisonRenderer implements IEvaluationContext {
private IWorkerContext context;
private ComparisonSession session;
private Map<String, String> templates = new HashMap<>();
private String folder;
public ComparisonRenderer(IWorkerContext context, String folder, ComparisonSession session) {
super();
this.context = context;
this.folder = folder;
this.session = session;
}
public Map<String, String> getTemplates() {
return templates;
}
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");
}
Map<String, Base> vars = new HashMap<>();
CodeSystemComparer cs = new CodeSystemComparer(session);
vars.put("title", new StringType(session.getTitle()));
vars.put("list", new StringType(b.toString()));
String template = templates.get("Index");
String cnt = processTemplate(template, "CodeSystem", vars);
TextFile.stringToFile(cnt, file("index.html"));
}
private List<String> sorted(Set<String> keySet) {
List<String> list = new ArrayList<>();
list.addAll(keySet);
Collections.sort(list);
return list;
}
private void dumpBinaries() throws IOException {
for (String k : context.getBinaries().keySet()) {
TextFile.bytesToFile(context.getBinaries().get(k), Utilities.path(folder, k));
}
}
private void renderComparison(String id, ResourceComparison comp) throws IOException {
if (comp instanceof ProfileComparison) {
renderProfile(id, (ProfileComparison) comp);
} else if (comp instanceof ValueSetComparison) {
renderValueSet(id, (ValueSetComparison) comp);
} else if (comp instanceof CodeSystemComparison) {
renderCodeSystem(id, (CodeSystemComparison) comp);
}
}
private void renderCodeSystem(String id, CodeSystemComparison comp) throws IOException {
String template = templates.get("CodeSystem");
Map<String, Base> vars = new HashMap<>();
CodeSystemComparer cs = new CodeSystemComparer(session);
vars.put("left", new StringType(comp.getLeft().present()));
vars.put("right", new StringType(comp.getRight().present()));
vars.put("leftId", new StringType(comp.getLeft().getId()));
vars.put("rightId", new StringType(comp.getRight().getId()));
vars.put("leftUrl", new StringType(comp.getLeft().getUrl()));
vars.put("rightUrl", new StringType(comp.getRight().getUrl()));
vars.put("errors", new StringType(new XhtmlComposer(true).compose(cs.renderErrors(comp))));
vars.put("metadata", new StringType(new XhtmlComposer(true).compose(cs.renderMetadata(comp, "", ""))));
vars.put("concepts", new StringType(new XhtmlComposer(true).compose(cs.renderConcepts(comp, "", ""))));
String cnt = processTemplate(template, "CodeSystem", vars);
TextFile.stringToFile(cnt, file(comp.getId()+".html"));
new org.hl7.fhir.r5.formats.JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path("[tmp]", "comparison", comp.getId() + "-union.json")), comp.getUnion());
new org.hl7.fhir.r5.formats.JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path("[tmp]", "comparison", comp.getId() + "-intersection.json")), comp.getIntersection());
}
private String file(String name) throws IOException {
return Utilities.path(folder, name);
}
private void renderValueSet(String id, ValueSetComparison comp) throws FHIRException, IOException {
String template = templates.get("ValueSet");
Map<String, Base> vars = new HashMap<>();
ValueSetComparer cs = new ValueSetComparer(session);
vars.put("left", new StringType(comp.getLeft().present()));
vars.put("right", new StringType(comp.getRight().present()));
vars.put("leftId", new StringType(comp.getLeft().getId()));
vars.put("rightId", new StringType(comp.getRight().getId()));
vars.put("leftUrl", new StringType(comp.getLeft().getUrl()));
vars.put("rightUrl", new StringType(comp.getRight().getUrl()));
vars.put("errors", new StringType(new XhtmlComposer(true).compose(cs.renderErrors(comp))));
vars.put("metadata", new StringType(new XhtmlComposer(true).compose(cs.renderMetadata(comp, "", ""))));
vars.put("compose", new StringType(new XhtmlComposer(true).compose(cs.renderCompose(comp, "", ""))));
vars.put("expansion", new StringType(new XhtmlComposer(true).compose(cs.renderExpansion(comp, "", ""))));
String cnt = processTemplate(template, "ValueSet", vars);
TextFile.stringToFile(cnt, file(comp.getId()+".html"));
new org.hl7.fhir.r5.formats.JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path("[tmp]", "comparison", comp.getId() + "-union.json")), comp.getUnion());
new org.hl7.fhir.r5.formats.JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path("[tmp]", "comparison", comp.getId() + "-intersection.json")), comp.getIntersection());
}
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, null));
vars.put("left", new StringType(comp.getLeft().present()));
vars.put("right", new StringType(comp.getRight().present()));
vars.put("leftId", new StringType(comp.getLeft().getId()));
vars.put("rightId", new StringType(comp.getRight().getId()));
vars.put("leftUrl", new StringType(comp.getLeft().getUrl()));
vars.put("rightUrl", new StringType(comp.getRight().getUrl()));
vars.put("errors", new StringType(new XhtmlComposer(true).compose(cs.renderErrors(comp))));
vars.put("metadata", new StringType(new XhtmlComposer(true).compose(cs.renderMetadata(comp, "", ""))));
vars.put("structure", new StringType(new XhtmlComposer(true).compose(cs.renderStructure(comp, "", "", "http://hl7.org/fhir"))));
String cnt = processTemplate(template, "CodeSystem", vars);
TextFile.stringToFile(cnt, file(comp.getId()+".html"));
new org.hl7.fhir.r5.formats.JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path("[tmp]", "comparison", comp.getId() + "-union.json")), comp.getUnion());
new org.hl7.fhir.r5.formats.JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path("[tmp]", "comparison", comp.getId() + "-intersection.json")), comp.getIntersection());
}
private String processTemplate(String template, String name, Map<String, Base> vars) {
LiquidEngine engine = new LiquidEngine(context, this);
LiquidDocument doc = engine.parse(template, name+".template");
return engine.evaluate(doc, Tuple.fromMap(vars), vars);
}
@Override
public Base resolveConstant(Object appContext, String name, boolean beforeContext) throws PathEngineException {
@SuppressWarnings("unchecked")
Map<String, Base> vars = (Map<String, Base>) appContext;
return vars.get(name);
}
@Override
public TypeDetails resolveConstantType(Object appContext, String name) throws PathEngineException {
@SuppressWarnings("unchecked")
Map<String, Base> vars = (Map<String, Base>) appContext;
Base b = vars.get(name);
return new TypeDetails(CollectionStatus.SINGLETON, b == null ? "Base" : b.fhirType());
}
@Override
public boolean log(String argument, List<Base> focus) {
return false;
}
@Override
public FunctionDetails resolveFunction(String functionName) {
return null;
}
@Override
public TypeDetails checkFunction(Object appContext, String functionName, List<TypeDetails> parameters) throws PathEngineException {
return null;
}
@Override
public List<Base> executeFunction(Object appContext, String functionName, List<List<Base>> parameters) {
return null;
}
@Override
public Base resolveReference(Object appContext, String url, Base refContext) throws FHIRException {
return null;
}
@Override
public boolean conformsToProfile(Object appContext, Base item, String url) throws FHIRException {
return false;
}
@Override
public ValueSet resolveValueSet(Object appContext, String url) {
return null;
}
}
package org.hl7.fhir.r5.comparison;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
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.ResourceComparison;
import org.hl7.fhir.r5.comparison.ValueSetComparer.ValueSetComparison;
import org.hl7.fhir.r5.conformance.ProfileUtilities;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.formats.IParser.OutputStyle;
import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.ExpressionNode.CollectionStatus;
import org.hl7.fhir.r5.model.StringType;
import org.hl7.fhir.r5.model.Tuple;
import org.hl7.fhir.r5.model.TypeDetails;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.utils.FHIRPathEngine.IEvaluationContext;
import org.hl7.fhir.r5.utils.LiquidEngine;
import org.hl7.fhir.r5.utils.LiquidEngine.LiquidDocument;
import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.xhtml.XhtmlComposer;
public class ComparisonRenderer implements IEvaluationContext {
private IWorkerContext context;
private ComparisonSession session;
private Map<String, String> templates = new HashMap<>();
private String folder;
public ComparisonRenderer(IWorkerContext context, String folder, ComparisonSession session) {
super();
this.context = context;
this.folder = folder;
this.session = session;
}
public Map<String, String> getTemplates() {
return templates;
}
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");
}
Map<String, Base> vars = new HashMap<>();
CodeSystemComparer cs = new CodeSystemComparer(session);
vars.put("title", new StringType(session.getTitle()));
vars.put("list", new StringType(b.toString()));
String template = templates.get("Index");
String cnt = processTemplate(template, "CodeSystem", vars);
TextFile.stringToFile(cnt, file("index.html"));
}
private List<String> sorted(Set<String> keySet) {
List<String> list = new ArrayList<>();
list.addAll(keySet);
Collections.sort(list);
return list;
}
private void dumpBinaries() throws IOException {
for (String k : context.getBinaries().keySet()) {
TextFile.bytesToFile(context.getBinaries().get(k), Utilities.path(folder, k));
}
}
private void renderComparison(String id, ResourceComparison comp) throws IOException {
if (comp instanceof ProfileComparison) {
renderProfile(id, (ProfileComparison) comp);
} else if (comp instanceof ValueSetComparison) {
renderValueSet(id, (ValueSetComparison) comp);
} else if (comp instanceof CodeSystemComparison) {
renderCodeSystem(id, (CodeSystemComparison) comp);
}
}
private void renderCodeSystem(String id, CodeSystemComparison comp) throws IOException {
String template = templates.get("CodeSystem");
Map<String, Base> vars = new HashMap<>();
CodeSystemComparer cs = new CodeSystemComparer(session);
vars.put("left", new StringType(comp.getLeft().present()));
vars.put("right", new StringType(comp.getRight().present()));
vars.put("leftId", new StringType(comp.getLeft().getId()));
vars.put("rightId", new StringType(comp.getRight().getId()));
vars.put("leftUrl", new StringType(comp.getLeft().getUrl()));
vars.put("rightUrl", new StringType(comp.getRight().getUrl()));
vars.put("errors", new StringType(new XhtmlComposer(true).compose(cs.renderErrors(comp))));
vars.put("metadata", new StringType(new XhtmlComposer(true).compose(cs.renderMetadata(comp, "", ""))));
vars.put("concepts", new StringType(new XhtmlComposer(true).compose(cs.renderConcepts(comp, "", ""))));
String cnt = processTemplate(template, "CodeSystem", vars);
TextFile.stringToFile(cnt, file(comp.getId()+".html"));
new org.hl7.fhir.r5.formats.JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path("[tmp]", "comparison", comp.getId() + "-union.json")), comp.getUnion());
new org.hl7.fhir.r5.formats.JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path("[tmp]", "comparison", comp.getId() + "-intersection.json")), comp.getIntersection());
}
private String file(String name) throws IOException {
return Utilities.path(folder, name);
}
private void renderValueSet(String id, ValueSetComparison comp) throws FHIRException, IOException {
String template = templates.get("ValueSet");
Map<String, Base> vars = new HashMap<>();
ValueSetComparer cs = new ValueSetComparer(session);
vars.put("left", new StringType(comp.getLeft().present()));
vars.put("right", new StringType(comp.getRight().present()));
vars.put("leftId", new StringType(comp.getLeft().getId()));
vars.put("rightId", new StringType(comp.getRight().getId()));
vars.put("leftUrl", new StringType(comp.getLeft().getUrl()));
vars.put("rightUrl", new StringType(comp.getRight().getUrl()));
vars.put("errors", new StringType(new XhtmlComposer(true).compose(cs.renderErrors(comp))));
vars.put("metadata", new StringType(new XhtmlComposer(true).compose(cs.renderMetadata(comp, "", ""))));
vars.put("compose", new StringType(new XhtmlComposer(true).compose(cs.renderCompose(comp, "", ""))));
vars.put("expansion", new StringType(new XhtmlComposer(true).compose(cs.renderExpansion(comp, "", ""))));
String cnt = processTemplate(template, "ValueSet", vars);
TextFile.stringToFile(cnt, file(comp.getId()+".html"));
new org.hl7.fhir.r5.formats.JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path("[tmp]", "comparison", comp.getId() + "-union.json")), comp.getUnion());
new org.hl7.fhir.r5.formats.JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path("[tmp]", "comparison", comp.getId() + "-intersection.json")), comp.getIntersection());
}
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, null));
vars.put("left", new StringType(comp.getLeft().present()));
vars.put("right", new StringType(comp.getRight().present()));
vars.put("leftId", new StringType(comp.getLeft().getId()));
vars.put("rightId", new StringType(comp.getRight().getId()));
vars.put("leftUrl", new StringType(comp.getLeft().getUrl()));
vars.put("rightUrl", new StringType(comp.getRight().getUrl()));
vars.put("errors", new StringType(new XhtmlComposer(true).compose(cs.renderErrors(comp))));
vars.put("metadata", new StringType(new XhtmlComposer(true).compose(cs.renderMetadata(comp, "", ""))));
vars.put("structure", new StringType(new XhtmlComposer(true).compose(cs.renderStructure(comp, "", "", "http://hl7.org/fhir"))));
String cnt = processTemplate(template, "CodeSystem", vars);
TextFile.stringToFile(cnt, file(comp.getId()+".html"));
new org.hl7.fhir.r5.formats.JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path("[tmp]", "comparison", comp.getId() + "-union.json")), comp.getUnion());
new org.hl7.fhir.r5.formats.JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path("[tmp]", "comparison", comp.getId() + "-intersection.json")), comp.getIntersection());
}
private String processTemplate(String template, String name, Map<String, Base> vars) {
LiquidEngine engine = new LiquidEngine(context, this);
LiquidDocument doc = engine.parse(template, name+".template");
return engine.evaluate(doc, Tuple.fromMap(vars), vars);
}
@Override
public Base resolveConstant(Object appContext, String name, boolean beforeContext) throws PathEngineException {
@SuppressWarnings("unchecked")
Map<String, Base> vars = (Map<String, Base>) appContext;
return vars.get(name);
}
@Override
public TypeDetails resolveConstantType(Object appContext, String name) throws PathEngineException {
@SuppressWarnings("unchecked")
Map<String, Base> vars = (Map<String, Base>) appContext;
Base b = vars.get(name);
return new TypeDetails(CollectionStatus.SINGLETON, b == null ? "Base" : b.fhirType());
}
@Override
public boolean log(String argument, List<Base> focus) {
return false;
}
@Override
public FunctionDetails resolveFunction(String functionName) {
return null;
}
@Override
public TypeDetails checkFunction(Object appContext, String functionName, List<TypeDetails> parameters) throws PathEngineException {
return null;
}
@Override
public List<Base> executeFunction(Object appContext, String functionName, List<List<Base>> parameters) {
return null;
}
@Override
public Base resolveReference(Object appContext, String url, Base refContext) throws FHIRException {
return null;
}
@Override
public boolean conformsToProfile(Object appContext, Base item, String url) throws FHIRException {
return false;
}
@Override
public ValueSet resolveValueSet(Object appContext, String url) {
return null;
}
}

View File

@ -1,122 +1,114 @@
package org.hl7.fhir.r5.comparison;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r5.comparison.CodeSystemComparer.CodeSystemComparison;
import org.hl7.fhir.r5.comparison.ProfileComparer.ProfileComparison;
import org.hl7.fhir.r5.comparison.ResourceComparer.ResourceComparison;
import org.hl7.fhir.r5.comparison.ValueSetComparer.ValueSetComparison;
import org.hl7.fhir.r5.conformance.ProfileUtilities;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.model.CanonicalResource;
import org.hl7.fhir.r5.model.CodeSystem;
import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.utilities.Utilities;
public class ComparisonSession {
private Map<String, ResourceComparison> compares = new HashMap<>();
private IWorkerContext context;
private String sessiondId;
private int count;
private boolean debug;
private String title;
public ComparisonSession(IWorkerContext context, String title) {
super();
this.context = context;
this.sessiondId = UUID.randomUUID().toString().toLowerCase();
this.title = title;
// debug = true;
}
public IWorkerContext getContext() {
return context;
}
public String getTitle() {
return title;
}
public ResourceComparison compare(String left, String right) throws DefinitionException, FHIRFormatError, IOException {
CanonicalResource l = (CanonicalResource) context.fetchResource(Resource.class, left);
if (l == null) {
throw new DefinitionException("Unable to resolve "+left);
}
CanonicalResource r = (CanonicalResource) context.fetchResource(Resource.class, right);
if (r == null) {
throw new DefinitionException("Unable to resolve "+right);
}
return compare(l, r);
}
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);
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, null));
ProfileComparison csc = cs.compare((StructureDefinition) left, (StructureDefinition) right);
compares.put(key, csc);
return csc;
} else {
throw new FHIRException("Unable to compare ");
}
}
private String key(String urlL, String verL, String urlR, String verR) {
return urlL+"|"+verL+"||"+urlR+"|"+verR;
}
public void identify(CanonicalResource res) {
count++;
res.setId(sessiondId+"-"+count);
res.setUrl("http://hl7.org/fhir/comparison/"+res.fhirType()+"/"+res.getId());
}
public void identify(ResourceComparison res) {
count++;
}
public boolean isDebug() {
return debug;
}
public void setDebug(boolean debug) {
this.debug = debug;
}
public Map<String, ResourceComparison> getCompares() {
return compares;
}
package org.hl7.fhir.r5.comparison;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r5.comparison.CodeSystemComparer.CodeSystemComparison;
import org.hl7.fhir.r5.comparison.ProfileComparer.ProfileComparison;
import org.hl7.fhir.r5.comparison.ResourceComparer.ResourceComparison;
import org.hl7.fhir.r5.comparison.ValueSetComparer.ValueSetComparison;
import org.hl7.fhir.r5.conformance.ProfileUtilities;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.model.CanonicalResource;
import org.hl7.fhir.r5.model.CodeSystem;
import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.utilities.Utilities;
public class ComparisonSession {
private Map<String, ResourceComparison> compares = new HashMap<>();
private IWorkerContext context;
private String sessiondId;
private int count;
private boolean debug;
private String title;
public ComparisonSession(IWorkerContext context, String title) {
super();
this.context = context;
this.sessiondId = UUID.randomUUID().toString().toLowerCase();
this.title = title;
// debug = true;
}
public IWorkerContext getContext() {
return context;
}
public String getTitle() {
return title;
}
public ResourceComparison compare(String left, String right) throws DefinitionException, FHIRFormatError, IOException {
CanonicalResource l = (CanonicalResource) context.fetchResource(Resource.class, left);
if (l == null) {
throw new DefinitionException("Unable to resolve "+left);
}
CanonicalResource r = (CanonicalResource) context.fetchResource(Resource.class, right);
if (r == null) {
throw new DefinitionException("Unable to resolve "+right);
}
return compare(l, r);
}
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);
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, null));
ProfileComparison csc = cs.compare((StructureDefinition) left, (StructureDefinition) right);
compares.put(key, csc);
return csc;
} else {
throw new FHIRException("Unable to compare ");
}
}
private String key(String urlL, String verL, String urlR, String verR) {
return urlL+"|"+verL+"||"+urlR+"|"+verR;
}
public void identify(CanonicalResource res) {
count++;
res.setId(sessiondId+"-"+count);
res.setUrl("http://hl7.org/fhir/comparison/"+res.fhirType()+"/"+res.getId());
}
public void identify(ResourceComparison res) {
count++;
}
public boolean isDebug() {
return debug;
}
public void setDebug(boolean debug) {
this.debug = debug;
}
public Map<String, ResourceComparison> getCompares() {
return compares;
}
}

View File

@ -1,117 +1,118 @@
package org.hl7.fhir.r5.test;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
import javax.xml.parsers.ParserConfigurationException;
import org.hl7.fhir.r5.context.SimpleWorkerContext;
import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat;
import org.hl7.fhir.r5.formats.IParser;
import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.model.StructureMap;
import org.hl7.fhir.r5.test.utils.TestingUtilities;
import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.xml.XMLUtil;
import org.hl7.fhir.validation.ValidationEngine;
import org.hl7.fhir.validation.instance.InstanceValidatorFactory;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
public class FHIRMappingLanguageTests {
private List<Resource> outputs = new ArrayList<Resource>();
static private ValidationEngine validationEngine;
static private SimpleWorkerContext context;
public static Stream<Arguments> data()
throws FileNotFoundException, IOException, ParserConfigurationException, SAXException {
Document tests = XMLUtil.parseToDom(TestingUtilities.loadTestResource("r5", "fml", "manifest.xml"));
Element test = XMLUtil.getFirstChild(tests.getDocumentElement());
List<Arguments> objects = new ArrayList<>();
while (test != null && test.getNodeName().equals("test")) {
objects.add(Arguments.of(test.getAttribute("name"), test.getAttribute("source"), test.getAttribute("map"),
test.getAttribute("output")));
test = XMLUtil.getNextSibling(test);
}
return objects.stream();
}
@BeforeAll
public static void setUp() throws Exception {
validationEngine = new ValidationEngine("hl7.fhir.r4.core#4.0.1");
context = validationEngine.getContext();
context.loadFromFile(TestingUtilities.loadTestResourceStream("validator", "cda", "any.xml"), "any.xml", null);
context.loadFromFile(TestingUtilities.loadTestResourceStream("validator", "cda", "ii.xml"), "ii.xml", null);
context.loadFromFile(TestingUtilities.loadTestResourceStream("validator", "cda", "cd.xml"), "cd.xml", null);
context.loadFromFile(TestingUtilities.loadTestResourceStream("validator", "cda", "ce.xml"), "ce.xml", null);
context.loadFromFile(TestingUtilities.loadTestResourceStream("validator", "cda", "ed.xml"), "ed.xml", null);
context.loadFromFile(TestingUtilities.loadTestResourceStream("validator", "cda", "st.xml"), "st.xml", null);
context.loadFromFile(TestingUtilities.loadTestResourceStream("validator", "cda", "cda.xml"), "cda.xml", null);
for (StructureDefinition sd : context.getStructures()) {
if (!sd.hasSnapshot()) {
System.out.println("generate snapshot for " + sd.getUrl());
context.generateSnapshot(sd, true);
}
}
if (context.getValidatorFactory() == null) {
context.setValidatorFactory(new InstanceValidatorFactory());
}
}
@ParameterizedTest(name = "{index}: {0}")
@MethodSource("data")
public void test(String name, String source, String map, String output) throws Exception {
byte[] byteSource = TestingUtilities.loadTestResourceBytes("r5", "fml", source);
String stringMap = TestingUtilities.loadTestResource("r5", "fml", map);
String outputJson = TestingUtilities.loadTestResource("r5", "fml", output);
String fileOutputRes = TestingUtilities.tempFile("fml", output) + ".out";
String fileOutputResOrig = TestingUtilities.tempFile("fml", output) + ".orig.out";
ByteArrayOutputStream s = null;
outputs.clear();
String msg = null;
try {
StructureMap r = new org.hl7.fhir.r5.utils.StructureMapUtilities(context).parse(stringMap, map);
context.cacheResource(r);
org.hl7.fhir.r5.elementmodel.Element element = validationEngine.transform(byteSource, FhirFormat.JSON, r.getUrl());
s = new ByteArrayOutputStream();
if (output.endsWith(".json"))
new org.hl7.fhir.r5.elementmodel.JsonParser(context).compose(element, s, IParser.OutputStyle.PRETTY, null);
else
new org.hl7.fhir.r5.elementmodel.XmlParser(context).compose(element, s, IParser.OutputStyle.PRETTY, null);
context.dropResource(r);
} catch (Exception e) {
assertTrue(e.getMessage(), false);
}
if (output.endsWith("json")) {
msg = TestingUtilities.checkJsonSrcIsSame(s.toString(), outputJson);
} else {
TextFile.bytesToFile(s.toByteArray(), fileOutputRes);
TextFile.bytesToFile(outputJson.getBytes(), fileOutputResOrig);
msg = TestingUtilities.checkXMLIsSame(new FileInputStream(fileOutputRes), new FileInputStream(fileOutputResOrig));
}
if (!Utilities.noString(msg)) {
System.out.print(s.toString());
}
assertTrue(msg, Utilities.noString(msg));
}
package org.hl7.fhir.r5.test;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
import javax.xml.parsers.ParserConfigurationException;
import org.hl7.fhir.r5.context.SimpleWorkerContext;
import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat;
import org.hl7.fhir.r5.formats.IParser;
import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.model.StructureMap;
import org.hl7.fhir.r5.test.utils.TestingUtilities;
import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.xml.XMLUtil;
import org.hl7.fhir.validation.ValidationEngine;
import org.hl7.fhir.validation.instance.InstanceValidatorFactory;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
public class FHIRMappingLanguageTests {
private List<Resource> outputs = new ArrayList<Resource>();
static private ValidationEngine validationEngine;
static private SimpleWorkerContext context;
public static Stream<Arguments> data()
throws FileNotFoundException, IOException, ParserConfigurationException, SAXException {
Document tests = XMLUtil.parseToDom(TestingUtilities.loadTestResource("r5", "fml", "manifest.xml"));
Element test = XMLUtil.getFirstChild(tests.getDocumentElement());
List<Arguments> objects = new ArrayList<>();
while (test != null && test.getNodeName().equals("test")) {
objects.add(Arguments.of(test.getAttribute("name"), test.getAttribute("source"), test.getAttribute("map"),
test.getAttribute("output")));
test = XMLUtil.getNextSibling(test);
}
return objects.stream();
}
@BeforeAll
public static void setUp() throws Exception {
validationEngine = new ValidationEngine("hl7.fhir.r4.core#4.0.1");
context = validationEngine.getContext();
context.loadFromFile(TestingUtilities.loadTestResourceStream("validator", "cda", "any.xml"), "any.xml", null);
context.loadFromFile(TestingUtilities.loadTestResourceStream("validator", "cda", "ii.xml"), "ii.xml", null);
context.loadFromFile(TestingUtilities.loadTestResourceStream("validator", "cda", "cd.xml"), "cd.xml", null);
context.loadFromFile(TestingUtilities.loadTestResourceStream("validator", "cda", "ce.xml"), "ce.xml", null);
context.loadFromFile(TestingUtilities.loadTestResourceStream("validator", "cda", "ed.xml"), "ed.xml", null);
context.loadFromFile(TestingUtilities.loadTestResourceStream("validator", "cda", "st.xml"), "st.xml", null);
context.loadFromFile(TestingUtilities.loadTestResourceStream("validator", "cda", "cda.xml"), "cda.xml", null);
for (StructureDefinition sd : context.getStructures()) {
if (!sd.hasSnapshot()) {
System.out.println("generate snapshot for " + sd.getUrl());
context.generateSnapshot(sd, true);
}
}
if (context.getValidatorFactory() == null) {
context.setValidatorFactory(new InstanceValidatorFactory());
}
}
@ParameterizedTest(name = "{index}: {0}")
@MethodSource("data")
public void test(String name, String source, String map, String output) throws Exception {
byte[] byteSource = TestingUtilities.loadTestResourceBytes("r5", "fml", source);
String stringMap = TestingUtilities.loadTestResource("r5", "fml", map);
String outputJson = TestingUtilities.loadTestResource("r5", "fml", output);
String fileOutputRes = TestingUtilities.tempFile("fml", output) + ".out";
String fileOutputResOrig = TestingUtilities.tempFile("fml", output) + ".orig.out";
ByteArrayOutputStream s = null;
outputs.clear();
String msg = null;
try {
StructureMap r = new org.hl7.fhir.r5.utils.StructureMapUtilities(context).parse(stringMap, map);
context.cacheResource(r);
org.hl7.fhir.r5.elementmodel.Element element = validationEngine.transform(byteSource, FhirFormat.JSON, r.getUrl());
s = new ByteArrayOutputStream();
if (output.endsWith(".json"))
new org.hl7.fhir.r5.elementmodel.JsonParser(context).compose(element, s, IParser.OutputStyle.PRETTY, null);
else
new org.hl7.fhir.r5.elementmodel.XmlParser(context).compose(element, s, IParser.OutputStyle.PRETTY, null);
context.dropResource(r);
} catch (Exception e) {
assertTrue(e.getMessage(), false);
}
if (output.endsWith("json")) {
msg = TestingUtilities.checkJsonSrcIsSame(s.toString(), outputJson);
} else {
TextFile.bytesToFile(s.toByteArray(), fileOutputRes);
TextFile.bytesToFile(outputJson.getBytes(), fileOutputResOrig);
msg = TestingUtilities.checkXMLIsSame(new FileInputStream(fileOutputRes), new FileInputStream(fileOutputResOrig));
}
if (!Utilities.noString(msg)) {
System.out.print(s.toString());
}
assertTrue(msg, Utilities.noString(msg));
}
}