Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2024 11 gg custom resources 2 #995

Merged
merged 7 commits into from
Nov 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
* Security: Enforce that XML can't load XML entity declarations
* Loader: Fix missing isModifierReason on modifier extensions
* Version Convertor: fix bug converting NamingSystem.url between versions
* Version Convertor: Fix IG dependsOn.reason conversion
* Validator: fix value set validation on import validation to find external value sets
* Validator: Fix terminology tester for change to language header
* Validator: Adjust wording of R5 slicing check
* Validator: Sort entries in error message about profiles to make the order reproducible
* Validator: support resolving /_history/ URLs in IG publisher
* Renderer: make HTA messages translatable
* Renderer: new release - pubpack
* Renderer: suppress Json resourceType property in some logical models
* Renderer: more support for canonical logical models
* SQL: Fix NPE building package.db
* Go-Publish: Fix bug in publication checker - space in sequence blows logic up
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@
import java.util.HashSet;
import java.util.List;

import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.elementmodel.Element;
import org.hl7.fhir.r5.model.ImplementationGuide.ImplementationGuideDefinitionResourceComponent;
import org.hl7.fhir.r5.utils.UserDataNames;
import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.utilities.json.model.JsonObject;
import org.hl7.fhir.utilities.validation.ValidationMessage;

Expand Down Expand Up @@ -370,6 +372,17 @@ public boolean isCustomResource() {
return getElement().getProperty().getStructure().hasUserData(UserDataNames.loader_custom_resource);
}
}

public boolean isCanonical(IWorkerContext context) {
StructureDefinition sd = getElement().getProperty().getStructure();
while (sd != null) {
if ("CanonicalResource".equals(sd.getType())) {
return true;
}
sd = context.fetchResource(StructureDefinition.class, sd.getBaseDefinition());
}
return false;
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,18 @@ public String getSourceFor(String ref) {
public void findConfiguration(FetchedFile f, FetchedResource r) {
if (template != null) {
JsonObject cfg = null;
if (r.isExample()) {
if (r.isCanonical(context)) {
if (r.isExample()) {
cfg = defaultConfig.getJsonObject("example:canonical");
}
if (cfg == null) {
cfg = defaultConfig.getJsonObject(r.fhirType()+":canonical");
}
if (cfg == null) {
cfg = defaultConfig.getJsonObject("Any:canonical");
}
}
if (cfg == null && r.isExample()) {
cfg = defaultConfig.getJsonObject("example");
}
if (cfg == null && r.fhirType().equals("StructureDefinition")) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9212,6 +9212,8 @@ private void generateSummaryOutputs(DBBuilder db) throws Exception {
}
if (r.getResource() != null) {
populateResourceEntry(r, item, null);
} else if (r.isCustomResource()) {
populateCustomResourceEntry(r, item, null);
}
JsonArray contained = null;
// contained resources get added twice - once as sub-entries under the resource that contains them, and once as an entry in their own right, for their own rendering
Expand Down Expand Up @@ -9272,7 +9274,233 @@ private void generateSummaryOutputs(DBBuilder db) throws Exception {

json = org.hl7.fhir.utilities.json.parser.JsonParser.compose(data, true);
TextFile.stringToFile(json, Utilities.path(tempDir, "_data", "languages.json"));

}

private void populateCustomResourceEntry(FetchedResource r, JsonObject item, Object object) {
Element e = r.getElement();
// item.add("layout-type", "canonical");
if (e.getChildren("url").size() == 1) {
item.add("url", e.getNamedChildValue("url"));
}
if (e.hasChildren("identifier")) {
List<String> ids = new ArrayList<String>();
for (Element id : e.getChildren("identifier")) {
if (id.hasChild("value")) {
ids.add(dr.displayDataType(ResourceWrapper.forType(cu, id)));
}
}
if (!ids.isEmpty()) {
item.add("identifiers", String.join(", ", ids));
}
}
if (e.getChildren("version").size() == 1) {
item.add("version", e.getNamedChildValue("version"));
}
if (e.getChildren("name").size() == 1) {
item.add("name", e.getNamedChildValue("name"));
}
if (e.getChildren("title").size() == 1) {
item.add("title", e.getNamedChildValue("title"));
// addTranslationsToJson(item, "title", e.getNamedChild("title"), false);
}
if (e.getChildren("experimental").size() == 1) {
item.add("experimental", e.getNamedChildValue("experimental"));
}
if (e.getChildren("date").size() == 1) {
item.add("date", e.getNamedChildValue("date"));
}
if (e.getChildren("description").size() == 1) {
item.add("description", ProfileUtilities.processRelativeUrls(e.getNamedChildValue("description"), "", igpkp.specPath(), context.getResourceNames(), specMaps.get(0).listTargets(), pageTargets(), false));
// addTranslationsToJson(item, "description", e.getNamedChild("description"), false);
}

// if (cr.hasUseContext() && !containedCr) {
// List<String> contexts = new ArrayList<String>();
// for (UsageContext uc : cr.getUseContext()) {
// String label = dr.displayDataType(uc.getCode());
// if (uc.hasValueCodeableConcept()) {
// String value = dr.displayDataType(uc.getValueCodeableConcept());
// if (value!=null) {
// contexts.add(label + ":\u00A0" + value);
// }
// } else if (uc.hasValueQuantity()) {
// String value = dr.displayDataType(uc.getValueQuantity());
// if (value!=null)
// contexts.add(label + ":\u00A0" + value);
// } else if (uc.hasValueRange()) {
// String value = dr.displayDataType(uc.getValueRange());
// if (!value.isEmpty())
// contexts.add(label + ":\u00A0" + value);
//
// } else if (uc.hasValueReference()) {
// String value = null;
// String reference = null;
// if (uc.getValueReference().hasReference()) {
// reference = uc.getValueReference().getReference().contains(":") ? "" : igpkp.getCanonical() + "/";
// reference += uc.getValueReference().getReference();
// }
// if (uc.getValueReference().hasDisplay()) {
// if (reference != null)
// value = "[" + uc.getValueReference().getDisplay() + "](" + reference + ")";
// else
// value = uc.getValueReference().getDisplay();
// } else if (reference!=null)
// value = "[" + uc.getValueReference().getReference() + "](" + reference + ")";
// else if (uc.getValueReference().hasIdentifier()) {
// String idLabel = dr.displayDataType(uc.getValueReference().getIdentifier().getType());
// value = idLabel!=null ? label + ":\u00A0" + uc.getValueReference().getIdentifier().getValue() : uc.getValueReference().getIdentifier().getValue();
// }
// if (value != null)
// contexts.add(value);
// } else if (uc.hasValue()) {
// throw new FHIRException("Unsupported type for UsageContext.value - " + uc.getValue().fhirType());
// }
// }
// if (!contexts.isEmpty())
// item.add("contexts", String.join(", ", contexts));
// }
// if (cr.hasJurisdiction() && !containedCr) {
// File flagDir = new File(tempDir + "/assets/images");
// if (!flagDir.exists())
// flagDir.mkdirs();
// JsonArray jNodes = new JsonArray();
// item.add("jurisdictions", jNodes);
// ValueSet jvs = context.fetchResource(ValueSet.class, "http://hl7.org/fhir/ValueSet/jurisdiction");
// for (CodeableConcept cc : cr.getJurisdiction()) {
// JsonObject jNode = new JsonObject();
// jNodes.add(jNode);
// ValidationResult vr = jvs==null ? null : context.validateCode(new ValidationOptions(FhirPublication.R5, "en-US"), cc, jvs);
// if (vr != null && vr.asCoding()!=null) {
// Coding cd = vr.asCoding();
// jNode.add("code", cd.getCode());
// if (cd.getSystem().equals("http://unstats.un.org/unsd/methods/m49/m49.htm") && cd.getCode().equals("001")) {
// jNode.add("name", "International");
// jNode.add("flag", "001");
// } else if (cd.getSystem().equals("urn:iso:std:iso:3166")) {
// String code = translateCountryCode(cd.getCode()).toLowerCase();
// jNode.add("name", displayForCountryCode(cd.getCode()));
// File flagFile = new File(vsCache + "/" + code + ".svg");
// if (!flagFile.exists() && !ignoreFlags.contains(code)) {
// URL url2 = new URL("https://flagcdn.com/" + shortCountryCode.get(code.toUpperCase()).toLowerCase() + ".svg");
// try {
// InputStream in = url2.openStream();
// Files.copy(in, Paths.get(flagFile.getAbsolutePath()));
// } catch (Exception e2) {
// ignoreFlags.add(code);
// System.out.println("Unable to access " + url2 + " or " + url2+" ("+e2.getMessage()+")");
// }
// }
// if (flagFile.exists()) {
// FileUtils.copyFileToDirectory(flagFile, flagDir);
// jNode.add("flag", code);
// }
// } else if (cd.getSystem().equals("urn:iso:std:iso:3166:-2")) {
// String code = cd.getCode();
// String[] codeParts = cd.getCode().split("-");
// jNode.add("name", displayForStateCode(cd.getCode()) + " (" + displayForCountryCode(codeParts[0]) + ")");
// File flagFile = new File(vsCache + "/" + code + ".svg");
// if (!flagFile.exists()) {
// URL url = new URL("http://flags.ox3.in/svg/" + codeParts[0].toLowerCase() + "/" + codeParts[1].toLowerCase() + ".svg");
// try (InputStream in = url.openStream()) {
// Files.copy(in, Paths.get(flagFile.getAbsolutePath()));
// } catch (Exception e) {
// // If we can't find the file, that's ok.
// }
// }
// if (flagFile.exists()) {
// FileUtils.copyFileToDirectory(flagFile, flagDir);
// jNode.add("flag", code);
// }
// }
// } else {
// jNode.add("name", dr.displayDataType(cc));
// }
// }
// }

if (e.getChildren("purpose").size() == 1) {
item.add("purpose", ProfileUtilities.processRelativeUrls(e.getNamedChildValue("purpose"), "", igpkp.specPath(), context.getResourceNames(), specMaps.get(0).listTargets(), pageTargets(), false));
// addTranslationsToJson(item, "purpose", e.getNamedChild("purpose"), false);
}
if (e.getChildren("status").size() == 1) {
item.add("status", e.getNamedChildValue("status"));
}
if (e.getChildren("copyright").size() == 1) {
item.add("copyright", ProfileUtilities.processRelativeUrls(e.getNamedChildValue("copyright"), "", igpkp.specPath(), context.getResourceNames(), specMaps.get(0).listTargets(), pageTargets(), false));
// addTranslationsToJson(item, "description", e.getNamedChild("description"), false);
}

// if (pcr!=null && pcr.hasExtension(ToolingExtensions.EXT_FMM_LEVEL)) {
// IntegerType fmm = pcr.getExtensionByUrl(ToolingExtensions.EXT_FMM_LEVEL).getValueIntegerType();
// item.add("fmm", fmm.asStringValue());
// if (fmm.hasExtension(ToolingExtensions.EXT_FMM_DERIVED)) {
// String derivedFrom = "FMM derived from: ";
// for (Extension ext: fmm.getExtensionsByUrl(ToolingExtensions.EXT_FMM_DERIVED)) {
// derivedFrom += "\r\n" + ext.getValueCanonicalType().asStringValue();
// }
// item.add("fmmSource", derivedFrom);
// }
// }
// List<String> keywords = new ArrayList<String>();
// if (r.getResource() instanceof StructureDefinition) {
// StructureDefinition sd = (StructureDefinition)r.getResource();
// if (sd.hasKeyword()) {
// for (Coding coding : sd.getKeyword()) {
// String value = dr.displayDataType(coding);
// if (value != null)
// keywords.add(value);
// }
// }
// } else if (r.getResource() instanceof CodeSystem) {
// CodeSystem cs = (CodeSystem)r.getResource();
// for (Extension e : cs.getExtensionsByUrl(ToolingExtensions.EXT_CS_KEYWORD)) {
// keywords.add(e.getValueStringType().asStringValue());
// }
// } else if (r.getResource() instanceof ValueSet) {
// ValueSet vs = (ValueSet)r.getResource();
// for (Extension e : vs.getExtensionsByUrl(ToolingExtensions.EXT_VS_KEYWORD)) {
// keywords.add(e.getValueStringType().asStringValue());
// }
// }
// if (!keywords.isEmpty())
// item.add("keywords", String.join(", ", keywords));
//
//
org.hl7.fhir.igtools.renderers.StatusRenderer.ResourceStatusInformation info = StatusRenderer.analyse(e);
JsonObject jo = new JsonObject();
if (info.getColorClass() != null) {
jo.add("class", info.getColorClass());
}
if (info.getOwner() != null) {
jo.add("owner", info.getOwner());
}
if (info.getOwnerLink() != null) {
jo.add("link", info.getOwnerLink());
}
if (info.getSstatus() != null) {
jo.add("standards-status", info.getSstatus());
} else if (sourceIg.hasExtension(ToolingExtensions.EXT_STANDARDS_STATUS)) {
jo.add("standards-status","informative");
}
if (info.getSstatusSupport() != null) {
jo.add("standards-status-support", info.getSstatusSupport());
}
if (info.getNormVersion() != null) {
item.add("normativeVersion", info.getNormVersion());
}
if (info.getFmm() != null) {
jo.add("fmm", info.getFmm());
}
if (info.getSstatusSupport() != null) {
jo.add("fmm-support", info.getFmmSupport());
}
if (info.getStatus() != null && !jo.has("status")) {
jo.add("status", info.getStatus());
}
if (!jo.getProperties().isEmpty()) {
item.set("status", jo);
}

}

private void genBasePages() throws IOException, Exception {
Expand Down Expand Up @@ -9556,6 +9784,7 @@ private List<DependencyAnalyser.ArtifactDependency> makeDependencies() {

public void populateResourceEntry(FetchedResource r, JsonObject item, ContainedResourceDetails crd) throws Exception {
if (r.getResource() instanceof CanonicalResource || (crd!= null && crd.getCanonical() != null)) {
// item.add("layout-type", "canonical");
boolean containedCr = crd != null && crd.getCanonical() != null;
CanonicalResource cr = containedCr ? crd.getCanonical() : (CanonicalResource) r.getResource();
CanonicalResource pcr = r.getResource() instanceof CanonicalResource ? (CanonicalResource) r.getResource() : null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ public ValidationServices(IWorkerContext context, IGKnowledgeProvider ipg, Imple
public Element fetch(IResourceValidator validator, Object appContext, String url) throws FHIRException, IOException {
if (url == null)
return null;
if (url.contains("/_history/")) {
url = url.substring(0, url.indexOf("/_history"));
}
String turl = (!Utilities.isAbsoluteUrl(url)) ? Utilities.pathURL(ipg.getCanonical(), url) : url;
Resource res = context.fetchResource(getResourceType(turl), turl);
if (res != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -328,12 +328,12 @@ public void saveResource(FetchedFile f, FetchedResource r, byte[] json) {
psql.setInt(3, r.getElement().getProperty().getStructure().hasUserData(UserDataNames.loader_custom_resource) ? 1 : 0);
bindString(psql, 4, r.getId());
bindString(psql, 5, r.getElement().getWebPath());
bindString(psql, 6, r.getElement().getNamedChildValue("url"));
bindString(psql, 7, r.getElement().getNamedChildValue("version"));
bindString(psql, 8, r.getElement().getNamedChildValue("status"));
bindString(psql, 9, r.getElement().getNamedChildValue("date"));
bindString(psql, 10, r.getElement().getChildren("name").size() == 1 && r.getElement().getNamedChild("name").isPrimitive() ? r.getElement().getNamedChildValue("name") : r.getResourceName());
bindString(psql, 11, r.getElement().getNamedChildValue("title"));
bindString(psql, 6, getSingleChildValue(r, "url", null));
bindString(psql, 7, getSingleChildValue(r, "version", null));
bindString(psql, 8, getSingleChildValue(r, "status", null));
bindString(psql, 9, getSingleChildValue(r, "date", null));
bindString(psql, 10, getSingleChildValue(r, "name", r.getResourceName()));
bindString(psql, 11, getSingleChildValue(r, "title", null));
bindString(psql, 12, r.getResourceDescription());
psql.setBytes(13, json);
psql.executeUpdate();
Expand Down Expand Up @@ -380,6 +380,10 @@ public void saveResource(FetchedFile f, FetchedResource r, byte[] json) {
time(start);
}

private String getSingleChildValue(FetchedResource r, String name, String defaultValue) {
return r.getElement().getChildren(name).size() == 1 && r.getElement().getNamedChild(name).isPrimitive() ? r.getElement().getNamedChildValue(name) : defaultValue;
}

public void finishResources() {
long start = System.currentTimeMillis();
if (con == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.hl7.fhir.r5.renderers.utils.RenderingContext.RenderingContextLangs;
import org.hl7.fhir.utilities.MarkDownProcessor;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.i18n.I18nConstants;
import org.hl7.fhir.utilities.xhtml.XhtmlComposer;
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
import org.hl7.fhir.utilities.xhtml.XhtmlParser;
Expand Down Expand Up @@ -216,14 +217,12 @@ private boolean isHL7Ig() {

private String getCopyRightStatement(SystemUsage system) throws IOException {
if ("http://snomed.info/sct".equals(system.system)) {
system.desc = "SNOMED Clinical Terms® (SNOMED CT®)";
return "This material contains content that is copyright of SNOMED International. Implementers of these specifications must have the appropriate SNOMED CT Affiliate license - "+
"for more information contact <a href=\"https://www.snomed.org/get-snomed\">https://www.snomed.org/get-snomed</a> or <a href=\"mailto:[email protected]\">[email protected]</a>.";
system.desc = ctxt.formatMessage(I18nConstants.HTA_SCT_DESC);
return ctxt.formatMessage(I18nConstants.HTA_SCT_MESSAGE);
}
if ("http://loinc.org".equals(system.system)) {
system.desc = "LOINC";
return "This material contains content from <a href=\"http://loinc.org\">LOINC</a>. LOINC is copyright © 1995-2020, Regenstrief Institute, Inc. and the Logical Observation Identifiers Names and Codes (LOINC) "+
"Committee and is available at no cost under the <a href=\"http://loinc.org/license\">license</a>. LOINC® is a registered United States trademark of Regenstrief Institute, Inc.";
system.desc = ctxt.formatMessage(I18nConstants.HTA_LOINC_DESC);
return ctxt.formatMessage(I18nConstants.HTA_LOINC_MESSAGE);
}
if (system.cs != null) {
system.desc = system.cs.present();
Expand Down
Loading
Loading