Merge remote-tracking branch 'origin/master' into do-20240122-base-engine
This commit is contained in:
commit
c2d0207733
|
@ -0,0 +1,56 @@
|
|||
package org.hl7.fhir.convertors.misc;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.hl7.fhir.utilities.TextFile;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.filesystem.DirectoryVisitor;
|
||||
import org.hl7.fhir.utilities.filesystem.DirectoryVisitor.IDirectoryVisitorImplementation;
|
||||
import org.hl7.fhir.utilities.filesystem.ManagedFileAccess;
|
||||
import org.hl7.fhir.utilities.npm.NpmPackage;
|
||||
|
||||
public class SpecMapUnpacker {
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
new SpecMapUnpacker().unpack(args[0]);
|
||||
}
|
||||
|
||||
public class SpecMapScanner implements IDirectoryVisitorImplementation {
|
||||
|
||||
@Override
|
||||
public boolean enterDirectory(File directory) throws IOException {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visitFile(File file) throws IOException {
|
||||
System.out.println("Look at "+file.getAbsolutePath());
|
||||
try {
|
||||
NpmPackage npm = NpmPackage.fromPackage(ManagedFileAccess.inStream(file));
|
||||
if (npm.hasFile("other", "spec.internals")) {
|
||||
byte[] cnt = TextFile.streamToBytes(npm.load("other", "spec.internals"));
|
||||
TextFile.bytesToFile(cnt, Utilities.path(Utilities.getDirectoryForFile(file.getAbsolutePath()), "page-map.json"));
|
||||
System.out.println(" ...extracted");
|
||||
return true;
|
||||
} else {
|
||||
System.out.println(" ...not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
System.out.println(" ...error: "+e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void unpack(String path) throws IOException {
|
||||
System.out.println("Scanning "+path);
|
||||
int count = DirectoryVisitor.visitDirectory(new SpecMapScanner(), path, "tgz");
|
||||
System.out.println("Done. "+count+" files extracted");
|
||||
}
|
||||
|
||||
}
|
|
@ -700,9 +700,11 @@ public class ProfileUtilities {
|
|||
throw new DefinitionException(context.formatMessage(I18nConstants.UNABLE_TO_FIND_BASE__FOR_, base.getBaseDefinition(), base.getUrl()));
|
||||
checkNotGenerating(sdb, "an extension base");
|
||||
generateSnapshot(sdb, base, base.getUrl(), (sdb.hasWebPath()) ? Utilities.extractBaseUrl(sdb.getWebPath()) : webUrl, base.getName());
|
||||
|
||||
}
|
||||
fixTypeOfResourceId(base);
|
||||
if (base.hasExtension(ToolingExtensions.EXT_TYPE_PARAMETER)) {
|
||||
checkTypeParameters(base, derived);
|
||||
}
|
||||
|
||||
if (snapshotStack.contains(derived.getUrl())) {
|
||||
throw new DefinitionException(context.formatMessage(I18nConstants.CIRCULAR_SNAPSHOT_REFERENCES_DETECTED_CANNOT_GENERATE_SNAPSHOT_STACK__, snapshotStack.toString()));
|
||||
|
@ -976,6 +978,29 @@ public class ProfileUtilities {
|
|||
}
|
||||
|
||||
|
||||
private void checkTypeParameters(StructureDefinition base, StructureDefinition derived) {
|
||||
String bt = ToolingExtensions.readStringExtension(base, ToolingExtensions.EXT_TYPE_PARAMETER);
|
||||
if (!derived.hasExtension(ToolingExtensions.EXT_TYPE_PARAMETER)) {
|
||||
throw new DefinitionException(context.formatMessage(I18nConstants.SD_TYPE_PARAMETER_MISSING, base.getVersionedUrl(), bt, derived.getVersionedUrl()));
|
||||
}
|
||||
String dt = ToolingExtensions.readStringExtension(derived, ToolingExtensions.EXT_TYPE_PARAMETER);
|
||||
StructureDefinition bsd = context.fetchTypeDefinition(bt);
|
||||
StructureDefinition dsd = context.fetchTypeDefinition(dt);
|
||||
if (bsd == null) {
|
||||
throw new DefinitionException(context.formatMessage(I18nConstants.SD_TYPE_PARAMETER_UNKNOWN, base.getVersionedUrl(), bt));
|
||||
}
|
||||
if (dsd == null) {
|
||||
throw new DefinitionException(context.formatMessage(I18nConstants.SD_TYPE_PARAMETER_UNKNOWN, derived.getVersionedUrl(), dt));
|
||||
}
|
||||
StructureDefinition t = dsd;
|
||||
while (t != bsd && t != null) {
|
||||
t = context.fetchResource(StructureDefinition.class, t.getBaseDefinition());
|
||||
}
|
||||
if (t == null) {
|
||||
throw new DefinitionException(context.formatMessage(I18nConstants.SD_TYPE_PARAMETER_INVALID, base.getVersionedUrl(), bt, derived.getVersionedUrl(), dt));
|
||||
}
|
||||
}
|
||||
|
||||
private XVerExtensionManager makeXVer() {
|
||||
if (xver == null) {
|
||||
xver = new XVerExtensionManager(context);
|
||||
|
|
|
@ -1483,7 +1483,7 @@ public class DataRenderer extends Renderer implements CodeResolver {
|
|||
x.addText(displayContactPoint(contact));
|
||||
break;
|
||||
case PHONE:
|
||||
if (contact.hasValue() && contact.getValue().startsWith("+")) {
|
||||
if (contact.hasValue() && contact.getValue() != null && contact.getValue().startsWith("+")) {
|
||||
x.ah("tel:"+contact.getValue().replace(" ", "")).tx(contact.getValue());
|
||||
} else {
|
||||
x.addText(displayContactPoint(contact));
|
||||
|
|
|
@ -105,7 +105,7 @@ public class ExampleScenarioRenderer extends TerminologyRenderer {
|
|||
for (ExampleScenarioProcessStepComponent step: process.getStep()) {
|
||||
plantUml += toPlantUml(step, stepPrefix(prefix, step, stepCount), scen, actorsActive, actorKeys);
|
||||
if (step.getPause())
|
||||
plantUml += context.formatPhrase(RenderingContext.EX_SCEN_TIME);
|
||||
plantUml += context.formatPhrase(RenderingContext.EX_SCEN_TIME)+"\n";
|
||||
stepCount++;
|
||||
}
|
||||
|
||||
|
|
|
@ -494,7 +494,7 @@ public abstract class ResourceRenderer extends DataRenderer {
|
|||
if (url.startsWith("#") && res != null) {
|
||||
for (ResourceWrapper r : res.getContained()) {
|
||||
if (r.getId().equals(url.substring(1)))
|
||||
return new ResourceWithReference(ResourceReferenceKind.CONTAINED, null, r);
|
||||
return new ResourceWithReference(ResourceReferenceKind.CONTAINED, url, r);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -79,7 +79,7 @@ import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceContext;
|
|||
import org.hl7.fhir.r5.terminologies.utilities.ValidationResult;
|
||||
import org.hl7.fhir.r5.utils.PublicationHacker;
|
||||
import org.hl7.fhir.r5.utils.ToolingExtensions;
|
||||
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
|
||||
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
|
||||
import org.hl7.fhir.utilities.MarkDownProcessor;
|
||||
import org.hl7.fhir.utilities.StandardsStatus;
|
||||
import org.hl7.fhir.utilities.TextFile;
|
||||
|
@ -1060,6 +1060,19 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
|
|||
}
|
||||
Cell left = gen.new Cell(null, ref, sName, hint, null);
|
||||
row.getCells().add(left);
|
||||
if (profile.hasExtension(ToolingExtensions.EXT_TYPE_PARAMETER)) {
|
||||
Extension etp = profile.getExtensionByUrl(ToolingExtensions.EXT_TYPE_PARAMETER);
|
||||
String name = etp.getExtensionString("name");
|
||||
String type = etp.getExtensionString("type");
|
||||
StructureDefinition t = context.getContext().fetchTypeDefinition(type);
|
||||
if (t == null) {
|
||||
left.addPiece(gen.new Piece(null, "<"+name+" : "+type+">", null));
|
||||
} else if (t.getWebPath() == null) {
|
||||
left.addPiece(gen.new Piece(type, "<"+name+" : "+t.present()+">", null));
|
||||
} else {
|
||||
left.addPiece(gen.new Piece(t.getWebPath(), "<"+name+" : "+t.present()+">", null));
|
||||
}
|
||||
}
|
||||
return left;
|
||||
}
|
||||
|
||||
|
@ -1964,6 +1977,28 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
|
|||
} else {
|
||||
c.addPiece(checkForNoChange(t, gen.new Piece(null, tc, null)));
|
||||
}
|
||||
if (t.hasExtension(ToolingExtensions.EXT_TYPE_PARAMETER)) {
|
||||
c.addPiece(checkForNoChange(t, gen.new Piece(null, "<", null)));
|
||||
boolean pfirst = true;
|
||||
List<Extension> exl = t.getExtensionsByUrl(ToolingExtensions.EXT_TYPE_PARAMETER);
|
||||
for (Extension ex : exl) {
|
||||
if (pfirst) { pfirst = false; } else { c.addPiece(checkForNoChange(t, gen.new Piece(null, ";", null))); }
|
||||
if (exl.size() > 1) {
|
||||
c.addPiece(checkForNoChange(t, gen.new Piece(null, ex.getExtensionString("name")+": ", null)));
|
||||
}
|
||||
String type = ex.getExtensionString("type");
|
||||
StructureDefinition psd = context.getContext().fetchTypeDefinition(type);
|
||||
if (psd == null) {
|
||||
c.addPiece(checkForNoChange(t, gen.new Piece(null, type, null)));
|
||||
} else if (psd.getWebPath() == null) {
|
||||
c.addPiece(checkForNoChange(t, gen.new Piece(type, psd.present(), null)));
|
||||
} else {
|
||||
c.addPiece(checkForNoChange(t, gen.new Piece(psd.getWebPath(), psd.present(), null)));
|
||||
}
|
||||
}
|
||||
c.addPiece(checkForNoChange(t, gen.new Piece(null, ">", null)));
|
||||
|
||||
}
|
||||
if (!mustSupportMode && isMustSupportDirect(t) && e.getMustSupport()) {
|
||||
c.addPiece(gen.new Piece(null, " ", null));
|
||||
c.addStyledText((context.formatPhrase(RenderingContext.STRUC_DEF_TYPE_SUPP)), "S", "white", "red", null, false);
|
||||
|
@ -3670,6 +3705,9 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
|
|||
} else {
|
||||
tableRow(tbl, context.formatPhrase(RenderingContext.GENERAL_TYPE), "datatypes.html", strikethrough, describeTypes(d.getType(), false, d, compare, mode, value, compareValue, sd));
|
||||
}
|
||||
if (root && sd.hasExtension(ToolingExtensions.EXT_TYPE_PARAMETER)) {
|
||||
tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_TYPE_PARAMETER), "http://hl7.org/fhir/tools/StructureDefinition-type-parameter.html", strikethrough, renderTypeParameter(sd.getExtensionByUrl(ToolingExtensions.EXT_TYPE_PARAMETER)));
|
||||
}
|
||||
if (d.hasExtension(ToolingExtensions.EXT_DEF_TYPE)) {
|
||||
tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_DEFAULT_TYPE), "datatypes.html", strikethrough, ToolingExtensions.readStringExtension(d, ToolingExtensions.EXT_DEF_TYPE));
|
||||
}
|
||||
|
@ -3830,6 +3868,20 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
|
|||
tbl.tx("\r\n");
|
||||
}
|
||||
|
||||
private XhtmlNode renderTypeParameter(Extension ext) {
|
||||
XhtmlNode x = new XhtmlNode(NodeType.Element, "div");
|
||||
x.tx(ext.getExtensionString("name"));
|
||||
x.tx(" : ");
|
||||
String t = ext.getExtensionString("type");
|
||||
StructureDefinition sd = context.getContext().fetchTypeDefinition(t);
|
||||
if (sd == null) {
|
||||
x.code().tx(t);
|
||||
} else {
|
||||
x.ah(sd.getWebPath(), t).tx(sd.present());
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
private XhtmlNode presentModifier(ElementDefinition d, int mode, ElementDefinition compare) throws FHIRException, IOException {
|
||||
XhtmlNode x1 = compareString(encodeValue(d.getIsModifierElement(), null), d.getIsModifierElement(), null, "isModifier", d, compare == null ? null : encodeValue(compare.getIsModifierElement(), null), null, mode, false, false);
|
||||
if (x1 != null) {
|
||||
|
@ -4318,7 +4370,28 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
|
|||
} else {
|
||||
ts = compareString(x, t.getWorkingCode(), t, getTypeLink(t, sd), "code", t, compare==null ? null : compare.getWorkingCode(), compare==null ? null : getTypeLink(compare, sd), mode, false, false);
|
||||
}
|
||||
|
||||
if (t.hasExtension(ToolingExtensions.EXT_TYPE_PARAMETER)) {
|
||||
x.tx("<");
|
||||
boolean first = true;
|
||||
List<Extension> exl = t.getExtensionsByUrl(ToolingExtensions.EXT_TYPE_PARAMETER);
|
||||
for (Extension ex : exl) {
|
||||
if (first) { first = false; } else { x.tx("; "); }
|
||||
if (exl.size() > 1) {
|
||||
x.tx(ex.getExtensionString("name"));
|
||||
x.tx(":");
|
||||
}
|
||||
String type = ex.getExtensionString("type");
|
||||
StructureDefinition psd = context.getContext().fetchTypeDefinition(type);
|
||||
if (psd == null) {
|
||||
x.code().tx(type);
|
||||
} else if (psd.getWebPath() == null) {
|
||||
x.ah(type).tx(type);
|
||||
} else {
|
||||
x.ah(psd.getWebPath()).tx(type);
|
||||
}
|
||||
}
|
||||
x.tx(">");
|
||||
}
|
||||
if ((!mustSupportOnly && (t.hasProfile() || (compare!=null && compare.hasProfile()))) || isMustSupport(t.getProfile())) {
|
||||
StatusList<ResolvedCanonical> profiles = analyseProfiles(t.getProfile(), compare == null ? null : compare.getProfile(), mustSupportOnly, mode);
|
||||
if (profiles.size() > 0) {
|
||||
|
@ -4647,6 +4720,9 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (Utilities.noString(newMap) && compare == null) {
|
||||
return null;
|
||||
}
|
||||
if (compare==null)
|
||||
return new XhtmlNode(NodeType.Element, "div").tx(newMap);
|
||||
String oldMap = null;
|
||||
|
@ -4656,7 +4732,9 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Utilities.noString(newMap) && Utilities.noString(oldMap)) {
|
||||
return null;
|
||||
}
|
||||
return compareString(Utilities.escapeXml(newMap), null, null, "mapping", d, Utilities.escapeXml(oldMap), null, mode, false, false);
|
||||
}
|
||||
|
||||
|
|
|
@ -162,7 +162,7 @@ public class FHIRToolingClient extends FHIRBaseToolingClient {
|
|||
try {
|
||||
T output = (T) client.issueGetResourceRequest(resourceUri,
|
||||
withVer(preferredResourceFormat.getHeader(), "5.0"),
|
||||
generateHeaders(),
|
||||
generateHeaders(false),
|
||||
message,
|
||||
timeoutNormal).getReference();
|
||||
if (attemptedResourceFormat != preferredResourceFormat) {
|
||||
|
@ -214,7 +214,7 @@ public class FHIRToolingClient extends FHIRBaseToolingClient {
|
|||
ResourceRequest<Resource> result = null;
|
||||
try {
|
||||
result = client.issueGetResourceRequest(resourceAddress.resolveGetUriFromResourceClassAndId(resourceClass, id),
|
||||
withVer(getPreferredResourceFormat(), "4.0"), generateHeaders(), "Read " + resourceClass + "/" + id,
|
||||
withVer(getPreferredResourceFormat(), "4.0"), generateHeaders(false), "Read " + resourceClass + "/" + id,
|
||||
timeoutNormal);
|
||||
if (result.isUnsuccessfulRequest()) {
|
||||
throw new EFhirClientException("Server returned error code " + result.getHttpStatus(),
|
||||
|
@ -233,7 +233,7 @@ public class FHIRToolingClient extends FHIRBaseToolingClient {
|
|||
try {
|
||||
result = client.issueGetResourceRequest(resourceAddress.resolveGetUriFromResourceClassAndId(resourceClass, id),
|
||||
withVer(getPreferredResourceFormat(), "4.0"),
|
||||
generateHeaders(),
|
||||
generateHeaders(false),
|
||||
"Read " + resourceClass.getName() + "/" + id,
|
||||
timeoutNormal);
|
||||
if (result.isUnsuccessfulRequest()) {
|
||||
|
@ -251,7 +251,7 @@ public class FHIRToolingClient extends FHIRBaseToolingClient {
|
|||
try {
|
||||
result = client.issueGetResourceRequest(resourceAddress.resolveGetUriFromResourceClassAndIdAndVersion(resourceClass, id, version),
|
||||
withVer(getPreferredResourceFormat(), "4.0"),
|
||||
generateHeaders(),
|
||||
generateHeaders(false),
|
||||
"VRead " + resourceClass.getName() + "/" + id + "/?_history/" + version,
|
||||
timeoutNormal);
|
||||
if (result.isUnsuccessfulRequest()) {
|
||||
|
@ -269,7 +269,7 @@ public class FHIRToolingClient extends FHIRBaseToolingClient {
|
|||
try {
|
||||
result = client.issueGetResourceRequest(resourceAddress.resolveGetUriFromResourceClassAndCanonical(resourceClass, canonicalURL),
|
||||
withVer(getPreferredResourceFormat(), "4.0"),
|
||||
generateHeaders(),
|
||||
generateHeaders(false),
|
||||
"Read " + resourceClass.getName() + "?url=" + canonicalURL,
|
||||
timeoutNormal);
|
||||
if (result.isUnsuccessfulRequest()) {
|
||||
|
@ -293,7 +293,7 @@ public class FHIRToolingClient extends FHIRBaseToolingClient {
|
|||
result = client.issuePutRequest(resourceAddress.resolveGetUriFromResourceClassAndId(resource.getClass(), resource.getId()),
|
||||
ByteUtils.resourceToByteArray(resource, false, isJson(getPreferredResourceFormat()), false),
|
||||
withVer(getPreferredResourceFormat(), "4.0"),
|
||||
generateHeaders(),
|
||||
generateHeaders(true),
|
||||
"Update " + resource.fhirType() + "/" + resource.getId(),
|
||||
timeoutOperation);
|
||||
if (result.isUnsuccessfulRequest()) {
|
||||
|
@ -321,7 +321,7 @@ public class FHIRToolingClient extends FHIRBaseToolingClient {
|
|||
result = client.issuePutRequest(resourceAddress.resolveGetUriFromResourceClassAndId(resourceClass, id),
|
||||
ByteUtils.resourceToByteArray(resource, false, isJson(getPreferredResourceFormat()), false),
|
||||
withVer(getPreferredResourceFormat(), "4.0"),
|
||||
generateHeaders(),
|
||||
generateHeaders(true),
|
||||
"Update " + resource.fhirType() + "/" + id,
|
||||
timeoutOperation);
|
||||
if (result.isUnsuccessfulRequest()) {
|
||||
|
@ -357,10 +357,10 @@ public class FHIRToolingClient extends FHIRBaseToolingClient {
|
|||
URI url = resourceAddress.resolveOperationURLFromClass(resourceClass, name, ps);
|
||||
if (complex) {
|
||||
byte[] body = ByteUtils.resourceToByteArray(params, false, isJson(getPreferredResourceFormat()), true);
|
||||
result = client.issuePostRequest(url, body, withVer(getPreferredResourceFormat(), "4.0"), generateHeaders(),
|
||||
result = client.issuePostRequest(url, body, withVer(getPreferredResourceFormat(), "4.0"), generateHeaders(true),
|
||||
"POST " + resourceClass.getName() + "/$" + name, timeoutLong);
|
||||
} else {
|
||||
result = client.issueGetResourceRequest(url, withVer(getPreferredResourceFormat(), "4.0"), generateHeaders(), "GET " + resourceClass.getName() + "/$" + name, timeoutLong);
|
||||
result = client.issueGetResourceRequest(url, withVer(getPreferredResourceFormat(), "4.0"), generateHeaders(false), "GET " + resourceClass.getName() + "/$" + name, timeoutLong);
|
||||
}
|
||||
if (result.isUnsuccessfulRequest()) {
|
||||
throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome) result.getPayload());
|
||||
|
@ -383,7 +383,7 @@ public class FHIRToolingClient extends FHIRBaseToolingClient {
|
|||
Bundle transactionResult = null;
|
||||
try {
|
||||
transactionResult = client.postBatchRequest(resourceAddress.getBaseServiceUri(), ByteUtils.resourceToByteArray(batch, false, isJson(getPreferredResourceFormat()), false), withVer(getPreferredResourceFormat(), "4.0"),
|
||||
generateHeaders(),
|
||||
generateHeaders(true),
|
||||
"transaction", timeoutOperation + (timeoutEntry * batch.getEntry().size()));
|
||||
} catch (Exception e) {
|
||||
handleException("An error occurred trying to process this transaction request", e);
|
||||
|
@ -398,7 +398,7 @@ public class FHIRToolingClient extends FHIRBaseToolingClient {
|
|||
try {
|
||||
result = client.issuePostRequest(resourceAddress.resolveValidateUri(resourceClass, id),
|
||||
ByteUtils.resourceToByteArray(resource, false, isJson(getPreferredResourceFormat()), false),
|
||||
withVer(getPreferredResourceFormat(), "4.0"), generateHeaders(),
|
||||
withVer(getPreferredResourceFormat(), "4.0"), generateHeaders(true),
|
||||
"POST " + resourceClass.getName() + (id != null ? "/" + id : "") + "/$validate", timeoutLong);
|
||||
if (result.isUnsuccessfulRequest()) {
|
||||
throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome) result.getPayload());
|
||||
|
@ -458,7 +458,7 @@ public class FHIRToolingClient extends FHIRBaseToolingClient {
|
|||
result = client.issuePostRequest(resourceAddress.resolveOperationUri(ValueSet.class, "expand"),
|
||||
ByteUtils.resourceToByteArray(p, false, isJson(getPreferredResourceFormat()), true),
|
||||
withVer(getPreferredResourceFormat(), "4.0"),
|
||||
generateHeaders(),
|
||||
generateHeaders(true),
|
||||
"ValueSet/$expand?url=" + source.getUrl(),
|
||||
timeoutExpand);
|
||||
} catch (IOException e) {
|
||||
|
@ -476,7 +476,7 @@ public class FHIRToolingClient extends FHIRBaseToolingClient {
|
|||
try {
|
||||
result = client.issueGetResourceRequest(resourceAddress.resolveOperationUri(CodeSystem.class, "lookup", params),
|
||||
withVer(getPreferredResourceFormat(), "4.0"),
|
||||
generateHeaders(),
|
||||
generateHeaders(false),
|
||||
"CodeSystem/$lookup",
|
||||
timeoutNormal);
|
||||
} catch (IOException e) {
|
||||
|
@ -495,7 +495,7 @@ public class FHIRToolingClient extends FHIRBaseToolingClient {
|
|||
result = client.issuePostRequest(resourceAddress.resolveOperationUri(CodeSystem.class, "lookup"),
|
||||
ByteUtils.resourceToByteArray(p, false, isJson(getPreferredResourceFormat()), true),
|
||||
withVer(getPreferredResourceFormat(), "4.0"),
|
||||
generateHeaders(),
|
||||
generateHeaders(true),
|
||||
"CodeSystem/$lookup",
|
||||
timeoutNormal);
|
||||
} catch (IOException e) {
|
||||
|
@ -514,7 +514,7 @@ public class FHIRToolingClient extends FHIRBaseToolingClient {
|
|||
result = client.issuePostRequest(resourceAddress.resolveOperationUri(ConceptMap.class, "translate"),
|
||||
ByteUtils.resourceToByteArray(p, false, isJson(getPreferredResourceFormat()), true),
|
||||
withVer(getPreferredResourceFormat(), "4.0"),
|
||||
generateHeaders(),
|
||||
generateHeaders(true),
|
||||
"ConceptMap/$translate",
|
||||
timeoutNormal);
|
||||
} catch (IOException e) {
|
||||
|
@ -539,7 +539,7 @@ public class FHIRToolingClient extends FHIRBaseToolingClient {
|
|||
result = client.issuePostRequest(resourceAddress.resolveOperationUri(null, "closure", new HashMap<String, String>()),
|
||||
ByteUtils.resourceToByteArray(params, false, isJson(getPreferredResourceFormat()), true),
|
||||
withVer(getPreferredResourceFormat(), "4.0"),
|
||||
generateHeaders(),
|
||||
generateHeaders(true),
|
||||
"Closure?name=" + name,
|
||||
timeoutNormal);
|
||||
if (result.isUnsuccessfulRequest()) {
|
||||
|
@ -561,7 +561,7 @@ public class FHIRToolingClient extends FHIRBaseToolingClient {
|
|||
result = client.issuePostRequest(resourceAddress.resolveOperationUri(null, "closure", new HashMap<String, String>()),
|
||||
ByteUtils.resourceToByteArray(params, false, isJson(getPreferredResourceFormat()), true),
|
||||
withVer(getPreferredResourceFormat(), "4.0"),
|
||||
generateHeaders(),
|
||||
generateHeaders(true),
|
||||
"UpdateClosure?name=" + name,
|
||||
timeoutOperation);
|
||||
if (result.isUnsuccessfulRequest()) {
|
||||
|
@ -617,7 +617,7 @@ public class FHIRToolingClient extends FHIRBaseToolingClient {
|
|||
this.headers = headers;
|
||||
}
|
||||
|
||||
private Headers generateHeaders() {
|
||||
private Headers generateHeaders(boolean hasBody) {
|
||||
Headers.Builder builder = new Headers.Builder();
|
||||
// Add basic auth header if it exists
|
||||
if (basicAuthHeaderExists()) {
|
||||
|
@ -635,7 +635,7 @@ public class FHIRToolingClient extends FHIRBaseToolingClient {
|
|||
builder.add("Accept-Language: "+acceptLang);
|
||||
}
|
||||
|
||||
if (!Utilities.noString(contentLang)) {
|
||||
if (hasBody && !Utilities.noString(contentLang)) {
|
||||
builder.add("Content-Language: "+contentLang);
|
||||
}
|
||||
|
||||
|
@ -689,7 +689,7 @@ public class FHIRToolingClient extends FHIRBaseToolingClient {
|
|||
org.hl7.fhir.r5.utils.client.network.ResourceRequest<Resource> result = null;
|
||||
try {
|
||||
result = client.issueGetResourceRequest(resourceAddress.resolveGetResource(resourceClass, id),
|
||||
withVer(getPreferredResourceFormat(), "4.0"), generateHeaders(), resourceClass.getName()+"/"+id, timeoutNormal);
|
||||
withVer(getPreferredResourceFormat(), "4.0"), generateHeaders(false), resourceClass.getName()+"/"+id, timeoutNormal);
|
||||
} catch (IOException e) {
|
||||
throw new FHIRException(e);
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import org.hl7.fhir.r5.utils.ResourceUtilities;
|
|||
import org.hl7.fhir.r5.utils.client.EFhirClientException;
|
||||
import org.hl7.fhir.r5.utils.client.ResourceFormat;
|
||||
import org.hl7.fhir.utilities.MimeType;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.settings.FhirSettings;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
@ -91,7 +92,9 @@ public class FhirRequestBuilder {
|
|||
*/
|
||||
protected static void addResourceFormatHeaders(Request.Builder request, String format) {
|
||||
request.addHeader("Accept", format);
|
||||
request.addHeader("Content-Type", format + ";charset=" + DEFAULT_CHARSET);
|
||||
if (Utilities.existsInList(request.getMethod$okhttp(), "POST", "PUT")) {
|
||||
request.addHeader("Content-Type", format + ";charset=" + DEFAULT_CHARSET);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
package org.hl7.fhir.r5.utils.validation;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
|
||||
|
||||
public interface IMessagingServices {
|
||||
ValidationMessage signpost(List<ValidationMessage> errors, String ruleDate, IssueType type, int line, int col, String path, String theMessage, Object... theMessageArguments);
|
||||
|
||||
}
|
|
@ -31,6 +31,7 @@ package org.hl7.fhir.r5.utils.validation;
|
|||
|
||||
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.r5.context.IWorkerContext;
|
||||
import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat;
|
||||
import org.hl7.fhir.r5.model.Coding;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
|
@ -53,6 +54,8 @@ import java.util.List;
|
|||
*
|
||||
*/
|
||||
public interface IResourceValidator {
|
||||
|
||||
IWorkerContext getContext();
|
||||
|
||||
/**
|
||||
* how much to check displays for coded elements
|
||||
|
|
|
@ -9,6 +9,7 @@ import org.hl7.fhir.r5.model.StructureDefinition;
|
|||
import org.hl7.fhir.r5.model.ValueSet;
|
||||
import org.hl7.fhir.r5.utils.validation.constants.ContainedReferenceValidationPolicy;
|
||||
import org.hl7.fhir.r5.utils.validation.constants.ReferenceValidationPolicy;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
import org.hl7.fhir.r5.utils.validation.constants.CodedContentValidationPolicy;
|
||||
import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor.ElementValidationAction;
|
||||
import org.hl7.fhir.r5.utils.validation.constants.BindingKind;
|
||||
|
@ -131,5 +132,42 @@ public interface IValidationPolicyAdvisor {
|
|||
ValueSet valueSet,
|
||||
List<String> systems);
|
||||
|
||||
/**
|
||||
* This is called after a resource has been validated against the base structure,
|
||||
* but before it's validated against any profiles specified in .meta.profile or in the parameters.
|
||||
* This can be used to determine what additional profiles should be applied, for instance
|
||||
* those derived from the http://hl7.org/fhir/tools/StructureDefinition/profile-mapping extension
|
||||
*
|
||||
* Note that the resource is an elementModel resource, not an IBaseResource. This is less convenient to
|
||||
* read values from, but is the way the internals of the validator works (e.g. the version of the resource
|
||||
* might be any version from R2-R6)
|
||||
*
|
||||
* The base implementation applies the mandatory vital signs to observations that have LOINC or SNOMED CT
|
||||
* codes that indicate that they are vital signs. Note that these profiles are not optional; all vital sign resources
|
||||
* are required to conform to them. For this reason, if you're providing your own policy advisor, you should
|
||||
* keep a reference to the default one, or call BasePolicyAdvisorForFullValidation directly. You can choose not to,
|
||||
* but if you do, you are allowing for resources that deviate from the FHIR specification (in a way that the
|
||||
* community considers clinically unsafe, since it means that software (probably) will miss vital signs for
|
||||
* patients).
|
||||
*
|
||||
* @param validator
|
||||
* @param appContext What was originally provided from the app for it's context
|
||||
* @param stackPath The current path for the stack. Note that the because of cross-references and FHIRPath conformsTo() statements, the stack can wind through the content unpredictably.
|
||||
* @param definition the definition being validated against (might be useful: ElementDefinition.base.path, ElementDefinition.type, ElementDefinition.binding
|
||||
* @param structure The structure definition that contains the element definition being validated against (may be from the base spec, may be from a profile)
|
||||
* @param resource The actual resource (as an element model) so that the implementation can inspect the values in order to decide what profiles to apply
|
||||
* @param valid true if the resource is so far considered valid
|
||||
* @param messages all the validation messages. Implementations can inspect this, but the real purpose is to populate the messages with information messages explaining why profiles were (or weren't) applied
|
||||
* @return
|
||||
*/
|
||||
List<StructureDefinition> getImpliedProfilesForResource(IResourceValidator validator,
|
||||
Object appContext,
|
||||
String stackPath,
|
||||
ElementDefinition definition,
|
||||
StructureDefinition structure,
|
||||
Element resource,
|
||||
boolean valid,
|
||||
IMessagingServices msgServices,
|
||||
List<ValidationMessage> messages);
|
||||
|
||||
}
|
|
@ -26,10 +26,27 @@ class FhirRequestBuilderTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Test resource format headers are added correctly.")
|
||||
void addResourceFormatHeaders() {
|
||||
@DisplayName("Test resource format headers are added correctly (GET).")
|
||||
void addResourceFormatHeadersGET() {
|
||||
String testFormat = "yaml";
|
||||
Request.Builder request = new Request.Builder().url("http://www.google.com");
|
||||
request.setMethod$okhttp("GET");
|
||||
FhirRequestBuilder.addResourceFormatHeaders(request, testFormat);
|
||||
|
||||
Map<String, List<String>> headersMap = request.build().headers().toMultimap();
|
||||
Assertions.assertNotNull(headersMap.get("Accept"), "Accept header null.");
|
||||
Assertions.assertEquals(testFormat, headersMap.get("Accept").get(0),
|
||||
"Accept header not populated with expected value " + testFormat + ".");
|
||||
|
||||
Assertions.assertNull(headersMap.get("Content-Type"), "Content-Type header not null.");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Test resource format headers are added correctly (POST).")
|
||||
void addResourceFormatHeadersPOST() {
|
||||
String testFormat = "yaml";
|
||||
Request.Builder request = new Request.Builder().url("http://www.google.com");
|
||||
request.setMethod$okhttp("POST");
|
||||
FhirRequestBuilder.addResourceFormatHeaders(request, testFormat);
|
||||
|
||||
Map<String, List<String>> headersMap = request.build().headers().toMultimap();
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
package org.hl7.fhir.utilities.filesystem;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
|
||||
public class DirectoryVisitor {
|
||||
|
||||
public interface IDirectoryVisitorImplementation {
|
||||
boolean enterDirectory(File directory) throws IOException;
|
||||
boolean visitFile(File file) throws IOException; // return true if count
|
||||
}
|
||||
|
||||
private IDirectoryVisitorImplementation worker;
|
||||
private Set<String> extensions;
|
||||
|
||||
public DirectoryVisitor(IDirectoryVisitorImplementation worker, Set<String> extensions) {
|
||||
super();
|
||||
this.worker = worker;
|
||||
this.extensions = extensions;
|
||||
if (this.extensions == null) {
|
||||
extensions = new HashSet<>();
|
||||
}
|
||||
}
|
||||
|
||||
public DirectoryVisitor(IDirectoryVisitorImplementation worker, String... extensionList) {
|
||||
super();
|
||||
this.worker = worker;
|
||||
extensions = new HashSet<>();
|
||||
for (String s : extensionList) {
|
||||
extensions.add(s);
|
||||
}
|
||||
}
|
||||
|
||||
public DirectoryVisitor(IDirectoryVisitorImplementation worker) {
|
||||
super();
|
||||
this.worker = worker;
|
||||
extensions = new HashSet<>();
|
||||
}
|
||||
|
||||
public static int visitDirectory(IDirectoryVisitorImplementation worker, String path) throws IOException {
|
||||
return new DirectoryVisitor(worker).visit(path);
|
||||
}
|
||||
|
||||
public static int visitDirectory(IDirectoryVisitorImplementation worker, String path, Set<String> extensions) throws IOException {
|
||||
return new DirectoryVisitor(worker, extensions).visit(path);
|
||||
}
|
||||
|
||||
public static int visitDirectory(IDirectoryVisitorImplementation worker, String path, String... extensionList) throws IOException {
|
||||
return new DirectoryVisitor(worker, extensionList).visit(path);
|
||||
}
|
||||
|
||||
public int visit(String path) throws IOException {
|
||||
return visit(ManagedFileAccess.file(path));
|
||||
}
|
||||
|
||||
private int visit(File file) throws IOException {
|
||||
int count = 0;
|
||||
if (file.isDirectory()) {
|
||||
if (worker.enterDirectory(file)) {
|
||||
for (File f : ManagedFileAccess.listFiles(file)) {
|
||||
count += visit(f);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
String ext = file.getName().substring(file.getName().lastIndexOf(".")+1);
|
||||
if (extensions.isEmpty() || extensions.contains(ext)) {
|
||||
if (worker.visitFile(file)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
|
@ -61,6 +61,7 @@ public class ManagedFileAccess {
|
|||
FileInputStream inStream(String pathname);
|
||||
FileOutputStream outStream(String pathname);
|
||||
CSFile csfile(String pathname);
|
||||
File[] listFiles(File file) throws IOException; // file would be returned from file() above
|
||||
}
|
||||
|
||||
public enum FileAccessPolicy {
|
||||
|
@ -222,4 +223,20 @@ public class ManagedFileAccess {
|
|||
}
|
||||
}
|
||||
|
||||
public static File[] listFiles(File f) throws IOException {
|
||||
switch (accessPolicy) {
|
||||
case DIRECT:
|
||||
if (!inAllowedPaths(f.getAbsolutePath())) {
|
||||
throw new IOException("The pathname '"+f.getAbsolutePath()+"' cannot be accessed by policy");
|
||||
}
|
||||
return f.listFiles();
|
||||
case MANAGED:
|
||||
return accessor.listFiles(f);
|
||||
case PROHIBITED:
|
||||
throw new IOException("Access to files is not allowed by local security policy");
|
||||
default:
|
||||
throw new IOException("Internal Error");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -125,7 +125,7 @@ public abstract class I18nBase {
|
|||
if (Objects.nonNull(theMessageArguments) && theMessageArguments.length > 0) {
|
||||
message = MessageFormat.format(messages.getString(theMessage).trim(), theMessageArguments);
|
||||
} else {
|
||||
message = messages.getString(theMessage).trim();
|
||||
message = MessageFormat.format(messages.getString(theMessage).trim(), null);
|
||||
}
|
||||
}
|
||||
return message;
|
||||
|
|
|
@ -1079,4 +1079,5 @@ public class I18nConstants {
|
|||
public static final String SD_TYPE_PARAMETER_INVALID = "SD_TYPE_PARAMETER_INVALID";
|
||||
public static final String SD_TYPE_PARAMETER_INVALID_REF = "SD_TYPE_PARAMETER_INVALID_REF";
|
||||
public static final String SD_TYPE_PARAM_NOT_SPECIFIED = "SD_TYPE_PARAM_NOT_SPECIFIED";
|
||||
public static final String SD_TYPE_PARAMETER_ABSTRACT_WARNING = "SD_TYPE_PARAMETER_ABSTRACT_WARNING";
|
||||
}
|
||||
|
|
|
@ -16,6 +16,8 @@ import java.util.Set;
|
|||
import org.hl7.fhir.utilities.StringPair;
|
||||
import org.hl7.fhir.utilities.TextFile;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.filesystem.DirectoryVisitor;
|
||||
import org.hl7.fhir.utilities.filesystem.DirectoryVisitor.IDirectoryVisitorImplementation;
|
||||
import org.hl7.fhir.utilities.filesystem.ManagedFileAccess;
|
||||
|
||||
/**
|
||||
|
@ -123,9 +125,9 @@ public class POGenerator {
|
|||
}
|
||||
cd.defined = found;
|
||||
}
|
||||
scanJavaSource(new File(core), consts, "RenderingI18nContext", "RenderingContext");
|
||||
scanJavaSource(new File(igpub), consts, "RenderingI18nContext", "RenderingContext");
|
||||
scanPascalSource(new File(pascal), props);
|
||||
scanJavaSource(core, consts, "RenderingI18nContext", "RenderingContext");
|
||||
scanJavaSource(igpub, consts, "RenderingI18nContext", "RenderingContext");
|
||||
scanPascalSource(pascal, props);
|
||||
|
||||
Set<String> pns = new HashSet<>();
|
||||
for (PropertyValue p : props) {
|
||||
|
@ -170,9 +172,9 @@ public class POGenerator {
|
|||
cd.defined = found;
|
||||
}
|
||||
|
||||
scanJavaSource(new File(core), consts, "I18nConstants");
|
||||
scanJavaSource(new File(igpub), consts, "I18nConstants");
|
||||
scanPascalSource(new File(pascal), props);
|
||||
scanJavaSource(core, consts, "I18nConstants");
|
||||
scanJavaSource(igpub, consts, "I18nConstants");
|
||||
scanPascalSource(pascal, props);
|
||||
|
||||
pns = new HashSet<>();
|
||||
for (PropertyValue p : props) {
|
||||
|
@ -212,73 +214,86 @@ public class POGenerator {
|
|||
return ok;
|
||||
}
|
||||
|
||||
private boolean scanJavaSource(File file, List<ConstantDefinition> consts, String... names) throws FileNotFoundException, IOException {
|
||||
if (file.isDirectory()) {
|
||||
boolean found = true;
|
||||
for (File f : file.listFiles()) {
|
||||
if (!Utilities.existsInList(f.getName(), "model", "formats")) {
|
||||
found = scanJavaSource(f, consts, names) && found;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
String ext = file.getName().substring(file.getName().lastIndexOf(".")+1);
|
||||
if ("java".equals(ext)) {
|
||||
String source = TextFile.fileToString(file);
|
||||
for (ConstantDefinition cd : consts) {
|
||||
if (!cd.used) {
|
||||
boolean found = false;
|
||||
for (String n : names) {
|
||||
if (source.contains(n+"."+cd.name+",")) {
|
||||
found = true;
|
||||
}
|
||||
if (source.contains(n+"."+cd.name+")")) {
|
||||
found = true;
|
||||
}
|
||||
if (source.contains(n+"."+cd.name+" :")) {
|
||||
found = true;
|
||||
}
|
||||
if (source.contains(n+"."+cd.name+";")) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
cd.used = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
private class JavaScanner implements IDirectoryVisitorImplementation {
|
||||
List<ConstantDefinition> consts;
|
||||
List<String> names;
|
||||
|
||||
@Override
|
||||
public boolean enterDirectory(File f) throws IOException {
|
||||
return !Utilities.existsInList(f.getName(), "model", "formats");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void scanPascalSource(File file, List<PropertyValue> defs) throws FileNotFoundException, IOException {
|
||||
if (file.isDirectory()) {
|
||||
for (File f : file.listFiles()) {
|
||||
scanPascalSource(f, defs);
|
||||
}
|
||||
} else {
|
||||
String ext = file.getName().substring(file.getName().lastIndexOf(".")+1);
|
||||
if ("pas".equals(ext)) {
|
||||
String source = TextFile.fileToString(file);
|
||||
for (PropertyValue pv : defs) {
|
||||
if (!pv.used) {
|
||||
boolean found = false;
|
||||
String pn = pv.getBaseName();
|
||||
if (source.contains("'"+pn+"'")) {
|
||||
@Override
|
||||
public boolean visitFile(File file) throws IOException {
|
||||
String source = TextFile.fileToString(file);
|
||||
for (ConstantDefinition cd : consts) {
|
||||
if (!cd.used) {
|
||||
boolean found = false;
|
||||
for (String n : names) {
|
||||
if (source.contains(n+"."+cd.name+",")) {
|
||||
found = true;
|
||||
}
|
||||
if (found) {
|
||||
pv.used = true;
|
||||
}
|
||||
if (source.contains(n+"."+cd.name+")")) {
|
||||
found = true;
|
||||
}
|
||||
if (source.contains(n+"."+cd.name+" :")) {
|
||||
found = true;
|
||||
}
|
||||
if (source.contains(n+"."+cd.name+";")) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
cd.used = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private void scanJavaSource(String path, List<ConstantDefinition> consts, String... names) throws FileNotFoundException, IOException {
|
||||
JavaScanner scanner = new JavaScanner();
|
||||
scanner.consts = consts;
|
||||
scanner.names = new ArrayList<String>();
|
||||
for (String s : names) {
|
||||
scanner.names.add(s);
|
||||
}
|
||||
DirectoryVisitor.visitDirectory(scanner, path, "java");
|
||||
}
|
||||
|
||||
private class PascalScanner implements IDirectoryVisitorImplementation {
|
||||
private List<PropertyValue> defs;
|
||||
|
||||
@Override
|
||||
public boolean enterDirectory(File directory) throws IOException {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visitFile(File file) throws IOException {
|
||||
String source = TextFile.fileToString(file);
|
||||
for (PropertyValue pv : defs) {
|
||||
if (!pv.used) {
|
||||
boolean found = false;
|
||||
String pn = pv.getBaseName();
|
||||
if (source.contains("'"+pn+"'")) {
|
||||
found = true;
|
||||
}
|
||||
if (found) {
|
||||
pv.used = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private void scanPascalSource(String path, List<PropertyValue> defs) throws FileNotFoundException, IOException {
|
||||
PascalScanner scanner = new PascalScanner();
|
||||
scanner.defs = defs;
|
||||
DirectoryVisitor.visitDirectory(scanner, path, "pas");
|
||||
}
|
||||
|
||||
|
||||
private List<ConstantDefinition> loadConstants(String path) throws FileNotFoundException, IOException {
|
||||
|
@ -438,7 +453,7 @@ public class POGenerator {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
// we don't care; nothing to do
|
||||
o.oldMsgId = null;
|
||||
}
|
||||
} else if (mode == 1) {
|
||||
if (!value.equals(o.msgid)) {
|
||||
|
@ -451,7 +466,7 @@ public class POGenerator {
|
|||
o.msgstr.set(0, "!!"+o.msgstr.get(0));
|
||||
}
|
||||
} else {
|
||||
// we don't care; nothing to do
|
||||
o.oldMsgId = null;
|
||||
}
|
||||
} else if (mode == 2) {
|
||||
if (!value.equals(o.msgidPlural)) {
|
||||
|
@ -464,7 +479,7 @@ public class POGenerator {
|
|||
o.msgstr.set(1, "!!"+o.msgstr.get(1));
|
||||
}
|
||||
} else {
|
||||
// we don't care; nothing to do
|
||||
o.oldMsgId = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ BUNDLE_BUNDLE_ENTRY_FOUND_MULTIPLE_FRAGMENT = Found {0} matches for fragment {2}
|
|||
BUNDLE_BUNDLE_ENTRY_FULLURL_REQUIRED = Except for transactions and batches, each entry in a Bundle must have a fullUrl which is the identity of the resource in the entry
|
||||
BUNDLE_BUNDLE_ENTRY_MULTIPLE_PROFILES_MULTIPLE_MATCHES = The {1} resource matched more than one of the allowed profiles ({3})
|
||||
BUNDLE_BUNDLE_ENTRY_MULTIPLE_PROFILES_NO_MATCH = The {1} resource did not match any of the allowed profiles (Type {2}: {3})
|
||||
BUNDLE_BUNDLE_ENTRY_MULTIPLE_PROFILES_NO_MATCH_REASON = The {1} resource did not math the profile {2} because: {3}
|
||||
BUNDLE_BUNDLE_ENTRY_MULTIPLE_PROFILES_NO_MATCH_REASON = The {1} resource did not match the profile {2} because: {3}
|
||||
BUNDLE_BUNDLE_ENTRY_NOTFOUND_APPARENT_one = Can''t find ''{1}'' in the bundle ({2}). Note that there is a resource in the bundle with the same type and id, but it does not match because of the fullUrl based rules around matching relative references (must be ``{3}``)
|
||||
BUNDLE_BUNDLE_ENTRY_NOTFOUND_APPARENT_other = Can''t find ''{1}'' in the bundle ({2}). Note that there are {0} resources in the bundle with the same type and id, but they do not match because of the fullUrl based rules around matching relative references (one of ``{3}``)
|
||||
BUNDLE_BUNDLE_ENTRY_NOTFOUND_FRAGMENT = Can''t find ''{0}'' in the bundle ({1})
|
||||
|
@ -1107,3 +1107,4 @@ SD_TYPE_PARAMETER_UNKNOWN = The type definition ''{0}'' has the type parameter '
|
|||
SD_TYPE_PARAMETER_INVALID = The type definition ''{2}'' has a type parameter ''{3}'', which is not consistent with it''s ancestor type definition ''{0}'' which has the type parameter ''{1}''
|
||||
SD_TYPE_PARAMETER_INVALID_REF = The type ''{0}'' is a reference to ''{1}'' which has a type parameter ''{2}'' with a base type of {3} but the type parameter provided is ''{4}'' which is not the right type
|
||||
SD_TYPE_PARAM_NOT_SPECIFIED = The type ''{0}'' at {3} is a reference to ''{1}'' which needs a type parameter ''{2}'' but a type parameter is not provided for ''{2}''
|
||||
SD_TYPE_PARAMETER_ABSTRACT_WARNING = The type ''{0}'' at {3} refers to the abstract type ''{1}'' but the context is not an abstract type - this is usually an error
|
||||
|
|
|
@ -132,7 +132,7 @@ CAPABILITY_TYPS = Types
|
|||
CAPABILITY_TYP_PRES = ype are only present if at least one of the resources has support for them.
|
||||
CAPABILITY_UPDATE_INT = PUT a new resource version (update interaction)
|
||||
CAPABILITY_VREAD_INT = GET past versions of resources (vread interaction)
|
||||
CAPABILTY_ALLOW_CAP = Any FHIR capability may be 'allowed' by the system unless explicitly marked as 'SHALL NOT'. A few items are marked as MAY in the Implementation Guide to highlight their potential relevance to the use case.
|
||||
CAPABILTY_ALLOW_CAP = Any FHIR capability may be ''allowed'' by the system unless explicitly marked as ''SHALL NOT''. A few items are marked as MAY in the Implementation Guide to highlight their potential relevance to the use case.
|
||||
CAPABILTY_SHALL_SUPP = SHALL Support the Following Implementation Guides
|
||||
CODESYSTEM_CONCEPTS = Concepts
|
||||
CODESYSTEM_CONTENT_COMPLETE = This <param name="cased"/> code system <param name="cs"/> defines the following code<if test="code-count != 1">s</if><param name="h"/>:
|
||||
|
@ -537,10 +537,10 @@ GENERAL_MODIFIERS = Modifiers
|
|||
SEARCH_PAR_MULTIPLES = Multiples
|
||||
SEARCH_PAR_MULTIPLE_AND_APPEAR = multipleAnd: The parameter may only appear once
|
||||
SEARCH_PAR_MULTIPLE_AND_REPEAT = multipleAnd: The parameter may repeat in order to specify multiple values that must all be true
|
||||
SEARCH_PAR_MULTIPLE_AND_SERVER = multipleAnd: It's up to the server whether the parameter may repeat in order to specify multiple values that must all be true
|
||||
SEARCH_PAR_MULTIPLE_AND_SERVER = multipleAnd: It''s up to the server whether the parameter may repeat in order to specify multiple values that must all be true
|
||||
SEARCH_PAR_MULTIPLE_OR_MULTIPLE = multipleOr: The parameter may have multiple values (separated by comma) where at least one must be true
|
||||
SEARCH_PAR_MULTIPLE_OR_ONE = multipleOr: The parameter may only have one value (no comma separators)
|
||||
SEARCH_PAR_MULTIPLE_OR_SERVER = multipleOr: It's up to the server whether the parameter can have multiple values (separated by comma) where at least one must be true
|
||||
SEARCH_PAR_MULTIPLE_OR_SERVER = multipleOr: It''s up to the server whether the parameter can have multiple values (separated by comma) where at least one must be true
|
||||
SEARCH_PAR_NONE = (none)
|
||||
SEARCH_PAR_PROC = Processing Mode
|
||||
SEARCH_PAR_REND_TARGET = Target Resources
|
||||
|
|
|
@ -109,6 +109,20 @@ class I18nBaseTest {
|
|||
assertEquals("Documents oder Messages müssen mindestens einen Eintrag enthalten", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Test double single quotes behaviour.")
|
||||
void testDoubleSingleQuotes() {
|
||||
I18nTestClass testClass = new I18nTestClass();
|
||||
testClass.setLocale(Locale.US);
|
||||
String actualMessageA = testClass.formatMessage(I18nConstants.VALUESET_EXAMPLE_SYSTEM_HINT, "Mazooma");
|
||||
assertEquals("Example System 'Mazooma' specified, so Concepts and Filters can't be checked", actualMessageA);
|
||||
|
||||
String actualMessageB = testClass.formatMessage(I18nConstants.VALUESET_NO_SYSTEM_WARNING);
|
||||
System.out.println(actualMessageB);
|
||||
assertEquals("No System specified, so Concepts and Filters can't be checked", actualMessageB);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@DisplayName("Test German localization file contains no umlauts.")
|
||||
void testThatNoOneHasMessedWithTheGermans() {
|
||||
|
|
|
@ -67,6 +67,7 @@ import org.hl7.fhir.r5.terminologies.ValueSetUtilities;
|
|||
import org.hl7.fhir.r5.utils.ToolingExtensions;
|
||||
import org.hl7.fhir.r5.utils.XVerExtensionManager;
|
||||
import org.hl7.fhir.r5.utils.XVerExtensionManager.XVerExtensionStatus;
|
||||
import org.hl7.fhir.r5.utils.validation.IMessagingServices;
|
||||
import org.hl7.fhir.r5.utils.validation.IResourceValidator;
|
||||
import org.hl7.fhir.r5.utils.validation.IValidatorResourceFetcher;
|
||||
import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier.IValidationContextResourceLoader;
|
||||
|
@ -87,7 +88,7 @@ import org.hl7.fhir.validation.cli.utils.ValidationLevel;
|
|||
import org.hl7.fhir.validation.instance.utils.IndexedElement;
|
||||
import org.hl7.fhir.validation.instance.utils.NodeStack;
|
||||
|
||||
public class BaseValidator implements IValidationContextResourceLoader {
|
||||
public class BaseValidator implements IValidationContextResourceLoader, IMessagingServices {
|
||||
|
||||
public static class BooleanHolder {
|
||||
private boolean value = true;
|
||||
|
@ -411,7 +412,7 @@ public class BaseValidator implements IValidationContextResourceLoader {
|
|||
return thePass;
|
||||
}
|
||||
|
||||
protected ValidationMessage signpost(List<ValidationMessage> errors, String ruleDate, IssueType type, int line, int col, String path, String theMessage, Object... theMessageArguments) {
|
||||
public ValidationMessage signpost(List<ValidationMessage> errors, String ruleDate, IssueType type, int line, int col, String path, String theMessage, Object... theMessageArguments) {
|
||||
String message = context.formatMessage(theMessage, theMessageArguments);
|
||||
return addValidationMessage(errors, ruleDate, type, line, col, path, message, IssueSeverity.INFORMATION, theMessage).setSignpost(true);
|
||||
}
|
||||
|
|
|
@ -67,6 +67,7 @@ import org.hl7.fhir.r5.utils.EOperationOutcome;
|
|||
import org.hl7.fhir.r5.utils.ToolingExtensions;
|
||||
import org.hl7.fhir.r5.utils.structuremap.StructureMapUtilities;
|
||||
import org.hl7.fhir.r5.utils.validation.BundleValidationRule;
|
||||
import org.hl7.fhir.r5.utils.validation.IMessagingServices;
|
||||
import org.hl7.fhir.r5.utils.validation.IResourceValidator;
|
||||
import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor;
|
||||
import org.hl7.fhir.r5.utils.validation.IValidatorResourceFetcher;
|
||||
|
@ -104,6 +105,7 @@ import org.hl7.fhir.validation.cli.utils.ProfileLoader;
|
|||
import org.hl7.fhir.validation.cli.utils.QuestionnaireMode;
|
||||
import org.hl7.fhir.validation.cli.utils.SchemaValidator;
|
||||
import org.hl7.fhir.validation.cli.utils.ValidationLevel;
|
||||
import org.hl7.fhir.validation.instance.BasePolicyAdvisorForFullValidation;
|
||||
import org.hl7.fhir.validation.instance.InstanceValidator;
|
||||
import org.hl7.fhir.validation.instance.utils.ValidationContext;
|
||||
import org.hl7.fhir.utilities.ByteProvider;
|
||||
|
@ -1253,4 +1255,12 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
|
|||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StructureDefinition> getImpliedProfilesForResource(IResourceValidator validator, Object appContext,
|
||||
String stackPath, ElementDefinition definition, StructureDefinition structure, Element resource, boolean valid,
|
||||
IMessagingServices msgServices, List<ValidationMessage> messages) {
|
||||
return new BasePolicyAdvisorForFullValidation().getImpliedProfilesForResource(validator, appContext, stackPath,
|
||||
definition, structure, resource, valid, msgServices, messages);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -42,11 +42,12 @@ import org.hl7.fhir.utilities.json.parser.JsonParser;
|
|||
import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager;
|
||||
import org.hl7.fhir.utilities.npm.NpmPackage;
|
||||
import org.hl7.fhir.validation.cli.utils.Common;
|
||||
import org.hl7.fhir.validation.instance.BasePolicyAdvisorForFullValidation;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
|
||||
public class StandAloneValidatorFetcher implements IValidatorResourceFetcher, IValidationPolicyAdvisor, IWorkerContextManager.ICanonicalResourceLocator {
|
||||
public class StandAloneValidatorFetcher extends BasePolicyAdvisorForFullValidation implements IValidatorResourceFetcher, IValidationPolicyAdvisor, IWorkerContextManager.ICanonicalResourceLocator {
|
||||
|
||||
List<String> mappingsUris = new ArrayList<>();
|
||||
private FilesystemPackageCacheManager pcm;
|
||||
|
@ -75,31 +76,6 @@ public class StandAloneValidatorFetcher implements IValidatorResourceFetcher, IV
|
|||
String url) {
|
||||
return ReferenceValidationPolicy.CHECK_TYPE_IF_EXISTS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContainedReferenceValidationPolicy policyForContained(IResourceValidator validator,
|
||||
Object appContext,
|
||||
StructureDefinition structure,
|
||||
ElementDefinition element,
|
||||
String containerType,
|
||||
String containerId,
|
||||
Element.SpecialElement containingResourceType,
|
||||
String path,
|
||||
String url) {
|
||||
return ContainedReferenceValidationPolicy.CHECK_VALID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<ResourceValidationAction> policyForResource(IResourceValidator validator, Object appContext,
|
||||
StructureDefinition type, String path) {
|
||||
return EnumSet.allOf(ResourceValidationAction.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<ElementValidationAction> policyForElement(IResourceValidator validator, Object appContext,
|
||||
StructureDefinition structure, ElementDefinition element, String path) {
|
||||
return EnumSet.allOf(ElementValidationAction.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean resolveURL(IResourceValidator validator, Object appContext, String path, String url, String type, boolean canonical) throws IOException, FHIRException {
|
||||
|
@ -316,19 +292,6 @@ public class StandAloneValidatorFetcher implements IValidatorResourceFetcher, IV
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<CodedContentValidationAction> policyForCodedContent(IResourceValidator validator,
|
||||
Object appContext,
|
||||
String stackPath,
|
||||
ElementDefinition definition,
|
||||
StructureDefinition structure,
|
||||
BindingKind kind,
|
||||
AdditionalBindingPurpose purpose,
|
||||
ValueSet valueSet,
|
||||
List<String> systems) {
|
||||
return EnumSet.allOf(CodedContentValidationAction.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> fetchCanonicalResourceVersions(IResourceValidator validator, Object appContext, String url) {
|
||||
return new HashSet<>();
|
||||
|
|
|
@ -0,0 +1,166 @@
|
|||
package org.hl7.fhir.validation.instance;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.r5.context.IWorkerContext;
|
||||
import org.hl7.fhir.r5.elementmodel.Element;
|
||||
import org.hl7.fhir.r5.elementmodel.Element.SpecialElement;
|
||||
import org.hl7.fhir.r5.model.ElementDefinition;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
import org.hl7.fhir.r5.model.ValueSet;
|
||||
import org.hl7.fhir.r5.utils.validation.IMessagingServices;
|
||||
import org.hl7.fhir.r5.utils.validation.IResourceValidator;
|
||||
import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor;
|
||||
import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor.AdditionalBindingPurpose;
|
||||
import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor.CodedContentValidationAction;
|
||||
import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor.ElementValidationAction;
|
||||
import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor.ResourceValidationAction;
|
||||
import org.hl7.fhir.r5.utils.validation.constants.BindingKind;
|
||||
import org.hl7.fhir.r5.utils.validation.constants.ContainedReferenceValidationPolicy;
|
||||
import org.hl7.fhir.r5.utils.validation.constants.ReferenceValidationPolicy;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.VersionUtilities;
|
||||
import org.hl7.fhir.utilities.i18n.I18nConstants;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
|
||||
|
||||
public class BasePolicyAdvisorForFullValidation implements IValidationPolicyAdvisor {
|
||||
|
||||
@Override
|
||||
public ReferenceValidationPolicy policyForReference(IResourceValidator validator, Object appContext, String path, String url) {
|
||||
return ReferenceValidationPolicy.CHECK_TYPE_IF_EXISTS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContainedReferenceValidationPolicy policyForContained(IResourceValidator validator, Object appContext,
|
||||
StructureDefinition structure, ElementDefinition element, String containerType, String containerId,
|
||||
SpecialElement containingResourceType, String path, String url) {
|
||||
|
||||
return ContainedReferenceValidationPolicy.CHECK_VALID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<ResourceValidationAction> policyForResource(IResourceValidator validator, Object appContext,
|
||||
StructureDefinition type, String path) {
|
||||
return EnumSet.allOf(ResourceValidationAction.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<ElementValidationAction> policyForElement(IResourceValidator validator, Object appContext,
|
||||
StructureDefinition structure, ElementDefinition element, String path) {
|
||||
return EnumSet.allOf(ElementValidationAction.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<CodedContentValidationAction> policyForCodedContent(IResourceValidator validator,
|
||||
Object appContext,
|
||||
String stackPath,
|
||||
ElementDefinition definition,
|
||||
StructureDefinition structure,
|
||||
BindingKind kind,
|
||||
AdditionalBindingPurpose purpose,
|
||||
ValueSet valueSet,
|
||||
List<String> systems) {
|
||||
return EnumSet.allOf(CodedContentValidationAction.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StructureDefinition> getImpliedProfilesForResource(IResourceValidator validator, Object appContext,
|
||||
String stackPath, ElementDefinition definition, StructureDefinition structure, Element resource, boolean valid,
|
||||
IMessagingServices msgServices, List<ValidationMessage> messages) {
|
||||
List<StructureDefinition> profiles = new ArrayList<StructureDefinition>();
|
||||
if ("Observation".equals(resource.fhirType()) && VersionUtilities.isR4Plus(validator.getContext().getVersion())) {
|
||||
getImpliedProfilesForObservation(profiles, msgServices, messages, validator.getContext(), stackPath, resource);
|
||||
}
|
||||
return profiles;
|
||||
}
|
||||
|
||||
|
||||
private void getImpliedProfilesForObservation(List<StructureDefinition> profiles, IMessagingServices msgServices, List<ValidationMessage> messages, IWorkerContext context, String stackPath, Element resource) {
|
||||
Element code = resource.getNamedChild("code", false);
|
||||
List<String> codes = new ArrayList<>();
|
||||
if (hasLoincCode(code, codes, "85353-1")) {
|
||||
addProfile(profiles, msgServices, messages, context, stackPath, resource, "http://hl7.org/fhir/StructureDefinition/vitalspanel", "Vital Signs Panel", "LOINC", codes);
|
||||
} else if (hasLoincCode(code, codes, "9279-1", "76170-0", "76172-6", "76171-8", "19840-8", "33438-3", "76270-8", "11291-2")) {
|
||||
addProfile(profiles, msgServices, messages, context, stackPath, resource, "http://hl7.org/fhir/StructureDefinition/resprate", "Respiratory Rate", "LOINC", codes);
|
||||
} else if (hasLoincCode(code, codes, "60978-4", "73795-7", "73799-9", "76476-1", "76477-9", "8867-4", "8889-8", "8890-6", "8891-4", "8892-2", "8893-0", "40443-4", "55425-3", "68999-2", "11328-2", "69000-8", "69000-8", "60978-4", "60978-4", "8890-6", "8886-4", "68999-2", "68999-2")) {
|
||||
addProfile(profiles, msgServices, messages, context, stackPath, resource, "http://hl7.org/fhir/StructureDefinition/heartrate", "Heart rate", "LOINC", codes);
|
||||
} else if (hasLoincCode(code, codes, "2708-6", "19224-5", "20564-1", "2709-4", "2710-2", "2713-6", "51733-4", "59408-5", "59417-6", "89276-0", "97549-0")) {
|
||||
addProfile(profiles, msgServices, messages, context, stackPath, resource, "http://hl7.org/fhir/StructureDefinition/oxygensat", "Oxygen saturation", "LOINC", codes);
|
||||
} else if (hasLoincCode(code, codes, "8310-5", "60834-9", "60835-6", "60836-4", "60838-0", "60955-2", "61009-7", "75539-7", "75987-8", "76010-8", "76011-6", "76278-1", "8309-7", "8310-5", "8328-7", "8329-5", "8330-3", "8331-1", "8332-9", "8333-7", "8334-5", "91371-5", "98657-0", "98663-8")) {
|
||||
addProfile(profiles, msgServices, messages, context, stackPath, resource, "http://hl7.org/fhir/StructureDefinition/bodytemp", "Body temperature", "LOINC", codes);
|
||||
} else if (hasLoincCode(code, codes, "8302-2", "3137-7", "3138-5", "8302-2", "8306-3", "8308-9")) {
|
||||
addProfile(profiles, msgServices, messages, context, stackPath, resource, "http://hl7.org/fhir/StructureDefinition/bodyheight", "Body height", "LOINC", codes);
|
||||
} else if (hasLoincCode(code, codes, "9843-4", "8287-5", "9843-4")) {
|
||||
addProfile(profiles, msgServices, messages, context, stackPath, resource, "http://hl7.org/fhir/StructureDefinition/headcircum", "Head circumference", "LOINC", codes);
|
||||
} else if (hasLoincCode(code, codes, "29463-7", "29463-7", "3141-9", "3142-7", "75292-3", "79348-9", "8350-1", "8351-9")) {
|
||||
addProfile(profiles, msgServices, messages, context, stackPath, resource, "http://hl7.org/fhir/StructureDefinition/bodyweight", "Body weight", "LOINC", codes);
|
||||
} else if (hasLoincCode(code, codes, "39156-5", "39156-5", "59574-4", "89270-3")) {
|
||||
addProfile(profiles, msgServices, messages, context, stackPath, resource, "http://hl7.org/fhir/StructureDefinition/bmi", "Body mass index", "LOINC", codes);
|
||||
} else if (hasLoincCode(code, codes, "85354-9", "35094-2", "8459-0", "85354-9", "76534-7", "55284-4", "8480-6")) {
|
||||
addProfile(profiles, msgServices, messages, context, stackPath, resource, "http://hl7.org/fhir/StructureDefinition/bp", "Blood pressure systolic and diastolic", "LOINC", codes);
|
||||
|
||||
} else if (hasSctCode(code, codes, "46680005")) {
|
||||
addProfile(profiles, msgServices, messages, context, stackPath, resource, "http://hl7.org/fhir/StructureDefinition/vitalspanel", "Vital Signs Panel", "SNOMED CT", codes);
|
||||
} else if (hasSctCode(code, codes, "86290005", "271625008", "271306003")) {
|
||||
addProfile(profiles, msgServices, messages, context, stackPath, resource, "http://hl7.org/fhir/StructureDefinition/bp", "Blood pressure systolic and diastolic", "SNOMED CT", codes);
|
||||
} else if (hasSctCode(code, codes, "271306003", "249043002", "444981005", "399017001", "251670001", "429525003", "429614003")) {
|
||||
addProfile(profiles, msgServices, messages, context, stackPath, resource, "http://hl7.org/fhir/StructureDefinition/heartrate", "Heart rate", "SNOMED CT", codes);
|
||||
} else if (hasSctCode(code, codes, "103228002", "103228002", "442349007", "442476006", "442440005", "431314004", "442734002", "713194001")) {
|
||||
addProfile(profiles, msgServices, messages, context, stackPath, resource, "http://hl7.org/fhir/StructureDefinition/oxygensat", "Oxygen saturation", "SNOMED CT", codes);
|
||||
} else if (hasSctCode(code, codes, "386725007", "276885007", "300076005", "1222808002", "364246006", "307047009", "708499008", "708499008", "431598003", "698831002", "698832009", "415882003", "415974002", "415929009", "415945006")) {
|
||||
addProfile(profiles, msgServices, messages, context, stackPath, resource, "http://hl7.org/fhir/StructureDefinition/bodytemp", "Body temperature", "SNOMED CT", codes);
|
||||
} else if (hasSctCode(code, codes, "1153637007", "1162419008", "50373000", "1162418000", "1230278008", "1162392001", "1162417005")) {
|
||||
addProfile(profiles, msgServices, messages, context, stackPath, resource, "http://hl7.org/fhir/StructureDefinition/bodyheight", "Body height", "SNOMED CT", codes);
|
||||
} else if (hasSctCode(code, codes, "363812007", "169876006", "1269262007", "363811000")) {
|
||||
addProfile(profiles, msgServices, messages, context, stackPath, resource, "http://hl7.org/fhir/StructureDefinition/headcircum", "Head circumference", "SNOMED CT", codes);
|
||||
} else if (hasSctCode(code, codes, "363811000", "60621009", "735395000", "425024002", "424927000", "784399000", "1162416001", "1162415002")) {
|
||||
addProfile(profiles, msgServices, messages, context, stackPath, resource, "http://hl7.org/fhir/StructureDefinition/bodyweight", "Body weight", "SNOMED CT", codes);
|
||||
} else if (hasSctCode(code, codes, "60621009")) {
|
||||
addProfile(profiles, msgServices, messages, context, stackPath, resource, "http://hl7.org/fhir/StructureDefinition/bmi", "Body mass index", "SNOMED CT", codes);
|
||||
} else if (hasSctCode(code, codes, "75367002", "251076008", "163033001", "163035008", "386534000", "386536003", "271649006", "271649006", "271650006", "407556006", "407554009", "716579001", "399304008")) {
|
||||
addProfile(profiles, msgServices, messages, context, stackPath, resource, "http://hl7.org/fhir/StructureDefinition/bp", "Blood pressure systolic and diastolic", "SNOMED CT", codes);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void addProfile(List<StructureDefinition> profiles, IMessagingServices msgServices, List<ValidationMessage> messages, IWorkerContext context, String stackPath, Element resource, String url, String name, String systemName, List<String> codes) {
|
||||
resource.addMessage(msgServices.signpost(messages, null, IssueType.INFORMATIONAL, resource.line(), resource.col(), stackPath, I18nConstants.VALIDATION_VAL_PROFILE_SIGNPOST_OBS, url, name, systemName, codes.get(0)));
|
||||
StructureDefinition sd = context.fetchResource(StructureDefinition.class, url);
|
||||
if (sd != null) {
|
||||
profiles.add(sd);
|
||||
} else {
|
||||
// complain?
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean hasLoincCode(Element code, List<String> codes, String... values) {
|
||||
if (code != null) {
|
||||
List<Element> codings = code.getChildren("coding");
|
||||
for (Element coding : codings) {
|
||||
if ("http://loinc.org".equals(coding.getNamedChildValue("system", false)) && Utilities.existsInList(coding.getNamedChildValue("code", false), values)) {
|
||||
codes.add(coding.getNamedChildValue("code", false));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean hasSctCode(Element code, List<String> codes, String... values) {
|
||||
if (code != null) {
|
||||
List<Element> codings = code.getChildren("coding");
|
||||
for (Element coding : codings) {
|
||||
if ("http://snomed.info/sct".equals(coding.getNamedChildValue("system", false)) && Utilities.existsInList(coding.getNamedChildValue("code", false), values)) {
|
||||
codes.add(coding.getNamedChildValue("code", false));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -173,6 +173,7 @@ import org.hl7.fhir.r5.utils.XVerExtensionManager;
|
|||
import org.hl7.fhir.r5.utils.XVerExtensionManager.XVerExtensionStatus;
|
||||
import org.hl7.fhir.r5.utils.sql.Validator;
|
||||
import org.hl7.fhir.r5.utils.validation.BundleValidationRule;
|
||||
import org.hl7.fhir.r5.utils.validation.IMessagingServices;
|
||||
import org.hl7.fhir.r5.utils.validation.IResourceValidator;
|
||||
import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor;
|
||||
import org.hl7.fhir.r5.utils.validation.IValidationProfileUsageTracker;
|
||||
|
@ -595,7 +596,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
private boolean noBindingMsgSuppressed;
|
||||
private Map<String, Element> fetchCache = new HashMap<>();
|
||||
private HashMap<Element, ResourceValidationTracker> resourceTracker = new HashMap<>();
|
||||
private IValidationPolicyAdvisor policyAdvisor;
|
||||
private IValidationPolicyAdvisor policyAdvisor = new BasePolicyAdvisorForFullValidation();
|
||||
long time = 0;
|
||||
long start = 0;
|
||||
long lastlog = 0;
|
||||
|
@ -691,6 +692,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
|
||||
@Override
|
||||
public IResourceValidator setPolicyAdvisor(IValidationPolicyAdvisor advisor) {
|
||||
if (advisor == null) {
|
||||
throw new Error("Cannot set advisor to null");
|
||||
}
|
||||
this.policyAdvisor = advisor;
|
||||
return this;
|
||||
}
|
||||
|
@ -3111,7 +3115,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
}
|
||||
if (!found) {
|
||||
if (type.equals("canonical")) {
|
||||
ReferenceValidationPolicy rp = policyAdvisor == null ? ReferenceValidationPolicy.CHECK_VALID : policyAdvisor.policyForReference(this, valContext, path, url);
|
||||
ReferenceValidationPolicy rp = policyAdvisor.policyForReference(this, valContext, path, url);
|
||||
if (rp == ReferenceValidationPolicy.CHECK_EXISTS || rp == ReferenceValidationPolicy.CHECK_EXISTS_AND_TYPE) {
|
||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_CANONICAL_RESOLVE, url) && ok;
|
||||
} else {
|
||||
|
@ -3128,7 +3132,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
}
|
||||
} else {
|
||||
if (type.equals("canonical")) {
|
||||
ReferenceValidationPolicy rp = policyAdvisor == null ? ReferenceValidationPolicy.CHECK_VALID : policyAdvisor.policyForReference(this, valContext, path, url);
|
||||
ReferenceValidationPolicy rp = policyAdvisor.policyForReference(this, valContext, path, url);
|
||||
if (rp == ReferenceValidationPolicy.CHECK_EXISTS_AND_TYPE || rp == ReferenceValidationPolicy.CHECK_TYPE_IF_EXISTS || rp == ReferenceValidationPolicy.CHECK_VALID) {
|
||||
try {
|
||||
Resource r = null;
|
||||
|
@ -3581,8 +3585,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
ok = false;
|
||||
}
|
||||
} else {
|
||||
EnumSet<CodedContentValidationAction> validationPolicy = getPolicyAdvisor() == null ?
|
||||
EnumSet.allOf(CodedContentValidationAction.class) : getPolicyAdvisor().policyForCodedContent(this, valContext, stack.getLiteralPath(), elementContext, profile, BindingKind.PRIMARY, null, vs, new ArrayList<>());
|
||||
EnumSet<CodedContentValidationAction> validationPolicy = policyAdvisor.policyForCodedContent(this, valContext, stack.getLiteralPath(), elementContext, profile, BindingKind.PRIMARY, null, vs, new ArrayList<>());
|
||||
|
||||
if (!validationPolicy.isEmpty()) {
|
||||
long t = System.nanoTime();
|
||||
|
@ -3918,11 +3921,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
if (refType.equals("contained") || refType.equals("bundled")) {
|
||||
pol = ReferenceValidationPolicy.CHECK_VALID;
|
||||
} else {
|
||||
if (policyAdvisor == null) {
|
||||
pol = ReferenceValidationPolicy.IGNORE;
|
||||
} else {
|
||||
pol = policyAdvisor.policyForReference(this, valContext.getAppContext(), path, ref);
|
||||
}
|
||||
pol = policyAdvisor.policyForReference(this, valContext.getAppContext(), path, ref);
|
||||
}
|
||||
|
||||
if (conditional) {
|
||||
|
@ -5705,15 +5704,22 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
ok = false;
|
||||
}
|
||||
if (checkSpecials) {
|
||||
ok = checkSpecials(valContext, errors, element, stack, checkSpecials, pct, mode, fromContained) && ok;
|
||||
ok = checkSpecials(valContext, errors, element, stack, checkSpecials, pct, mode, fromContained, ok) && ok;
|
||||
ok = validateResourceRules(errors, element, stack) && ok;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
public boolean checkSpecials(ValidationContext valContext, List<ValidationMessage> errors, Element element, NodeStack stack, boolean checkSpecials, PercentageTracker pct, ValidationMode mode, boolean contained) {
|
||||
public boolean checkSpecials(ValidationContext valContext, List<ValidationMessage> errors, Element element, NodeStack stack, boolean checkSpecials, PercentageTracker pct, ValidationMode mode, boolean contained, boolean isOk) {
|
||||
boolean ok = true;
|
||||
|
||||
// first, does the policy advisor have profiles it wants us to check?
|
||||
List<StructureDefinition> profiles = policyAdvisor.getImpliedProfilesForResource(this, valContext.getAppContext(), stack.getLiteralPath(),
|
||||
element.getProperty().getDefinition(), element.getProperty().getStructure(), element, isOk, this, errors);
|
||||
for (StructureDefinition sd : profiles) {
|
||||
ok = startInner(valContext, errors, element, element, sd, stack, false, pct, mode, false) && ok;
|
||||
}
|
||||
|
||||
long t = System.nanoTime();
|
||||
try {
|
||||
if (VersionUtilities.getCanonicalResourceNames(context.getVersion()).contains(element.getType())) {
|
||||
|
@ -5966,8 +5972,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
} else {
|
||||
SpecialElement special = element.getSpecial();
|
||||
|
||||
ContainedReferenceValidationPolicy containedValidationPolicy = getPolicyAdvisor() == null ?
|
||||
ContainedReferenceValidationPolicy.CHECK_VALID : getPolicyAdvisor().policyForContained(this,
|
||||
ContainedReferenceValidationPolicy containedValidationPolicy = policyAdvisor.policyForContained(this,
|
||||
valContext, parentProfile, child, context.fhirType(), context.getId(), special, path, parentProfile.getUrl());
|
||||
|
||||
if (containedValidationPolicy.ignore()) {
|
||||
|
@ -6021,7 +6026,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
}
|
||||
}
|
||||
|
||||
checkSpecials(valContext, errors, element, stack, ok, pct, mode, true);
|
||||
checkSpecials(valContext, errors, element, stack, ok, pct, mode, true, ok);
|
||||
|
||||
if (typeForResource.getProfile().size() == 1) {
|
||||
long t = System.nanoTime();
|
||||
|
@ -6427,8 +6432,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
if (debug) {
|
||||
System.out.println(" check " + localStack.getLiteralPath()+" against "+ei.getDefinition().getId()+" in profile "+profile.getVersionedUrl()+time());
|
||||
}
|
||||
EnumSet<ElementValidationAction> actionSet = policyAdvisor == null ? EnumSet.allOf(ElementValidationAction.class) :
|
||||
policyAdvisor.policyForElement(this, valContext.getAppContext(), profile, ei.getDefinition(), localStack.getLiteralPath());
|
||||
EnumSet<ElementValidationAction> actionSet = policyAdvisor.policyForElement(this, valContext.getAppContext(), profile, ei.getDefinition(), localStack.getLiteralPath());
|
||||
|
||||
String localStackLiteralPath = localStack.getLiteralPath();
|
||||
String eiPath = ei.getPath();
|
||||
|
|
|
@ -181,7 +181,7 @@ public class BundleValidator extends BaseValidator {
|
|||
}
|
||||
}
|
||||
// also, while we're here, check the specials, since this doesn't happen anywhere else
|
||||
((InstanceValidator) parent).checkSpecials(hostContext, errors, res, rstack, true, pct, mode, true);
|
||||
((InstanceValidator) parent).checkSpecials(hostContext, errors, res, rstack, true, pct, mode, true, ok);
|
||||
}
|
||||
|
||||
// todo: check specials
|
||||
|
|
|
@ -38,92 +38,8 @@ public class ObservationValidator extends BaseValidator {
|
|||
element.getNamedChild("effectiveTiming", false) != null || element.getNamedChild("effectiveInstant", false) != null,
|
||||
I18nConstants.ALL_OBSERVATIONS_SHOULD_HAVE_AN_EFFECTIVEDATETIME_OR_AN_EFFECTIVEPERIOD, element.getProperty().typeSummary()) && ok;
|
||||
|
||||
// hook in the vital signs
|
||||
if (VersionUtilities.isR4Plus(context.getVersion())) {
|
||||
Element code = element.getNamedChild("code", false);
|
||||
List<String> codes = new ArrayList<>();
|
||||
if (hasLoincCode(code, codes, "85353-1")) {
|
||||
ok = checkObservationAgainstProfile(valContext, errors, element, stack, "http://hl7.org/fhir/StructureDefinition/vitalspanel", "Vital Signs Panel", "LOINC", codes, pct, mode) && ok;
|
||||
} else if (hasLoincCode(code, codes, "9279-1", "76170-0", "76172-6", "76171-8", "19840-8", "33438-3", "76270-8", "11291-2")) {
|
||||
ok = checkObservationAgainstProfile(valContext,errors, element, stack, "http://hl7.org/fhir/StructureDefinition/resprate", "Respiratory Rate", "LOINC", codes, pct, mode) && ok;
|
||||
} else if (hasLoincCode(code, codes, "60978-4", "73795-7", "73799-9", "76476-1", "76477-9", "8867-4", "8889-8", "8890-6", "8891-4", "8892-2", "8893-0", "40443-4", "55425-3", "68999-2", "11328-2", "69000-8", "69000-8", "60978-4", "60978-4", "8890-6", "8886-4", "68999-2", "68999-2")) {
|
||||
ok = checkObservationAgainstProfile(valContext,errors, element, stack, "http://hl7.org/fhir/StructureDefinition/heartrate", "Heart rate", "LOINC", codes, pct, mode) && ok;
|
||||
} else if (hasLoincCode(code, codes, "2708-6", "19224-5", "20564-1", "2709-4", "2710-2", "2713-6", "51733-4", "59408-5", "59417-6", "89276-0", "97549-0")) {
|
||||
ok = checkObservationAgainstProfile(valContext,errors, element, stack, "http://hl7.org/fhir/StructureDefinition/oxygensat", "Oxygen saturation", "LOINC", codes, pct, mode) && ok;
|
||||
} else if (hasLoincCode(code, codes, "8310-5", "60834-9", "60835-6", "60836-4", "60838-0", "60955-2", "61009-7", "75539-7", "75987-8", "76010-8", "76011-6", "76278-1", "8309-7", "8310-5", "8328-7", "8329-5", "8330-3", "8331-1", "8332-9", "8333-7", "8334-5", "91371-5", "98657-0", "98663-8")) {
|
||||
ok = checkObservationAgainstProfile(valContext,errors, element, stack, "http://hl7.org/fhir/StructureDefinition/bodytemp", "Body temperature", "LOINC", codes, pct, mode) && ok;
|
||||
} else if (hasLoincCode(code, codes, "8302-2", "3137-7", "3138-5", "8302-2", "8306-3", "8308-9")) {
|
||||
ok = checkObservationAgainstProfile(valContext,errors, element, stack, "http://hl7.org/fhir/StructureDefinition/bodyheight", "Body height", "LOINC", codes, pct, mode) && ok;
|
||||
} else if (hasLoincCode(code, codes, "9843-4", "8287-5", "9843-4")) {
|
||||
ok = checkObservationAgainstProfile(valContext,errors, element, stack, "http://hl7.org/fhir/StructureDefinition/headcircum", "Head circumference", "LOINC", codes, pct, mode) && ok;
|
||||
} else if (hasLoincCode(code, codes, "29463-7", "29463-7", "3141-9", "3142-7", "75292-3", "79348-9", "8350-1", "8351-9")) {
|
||||
ok = checkObservationAgainstProfile(valContext,errors, element, stack, "http://hl7.org/fhir/StructureDefinition/bodyweight", "Body weight", "LOINC", codes, pct, mode) && ok;
|
||||
} else if (hasLoincCode(code, codes, "39156-5", "39156-5", "59574-4", "89270-3")) {
|
||||
ok = checkObservationAgainstProfile(valContext,errors, element, stack, "http://hl7.org/fhir/StructureDefinition/bmi", "Body mass index", "LOINC", codes, pct, mode) && ok;
|
||||
} else if (hasLoincCode(code, codes, "85354-9", "35094-2", "8459-0", "85354-9", "76534-7", "55284-4", "8480-6")) {
|
||||
ok = checkObservationAgainstProfile(valContext,errors, element, stack, "http://hl7.org/fhir/StructureDefinition/bp", "Blood pressure systolic and diastolic", "LOINC", codes, pct, mode) && ok;
|
||||
|
||||
} else if (hasSctCode(code, codes, "46680005")) {
|
||||
ok = checkObservationAgainstProfile(valContext, errors, element, stack, "http://hl7.org/fhir/StructureDefinition/vitalspanel", "Vital Signs Panel", "SNOMED CT", codes, pct, mode) && ok;
|
||||
} else if (hasSctCode(code, codes, "86290005", "271625008", "271306003")) {
|
||||
ok = checkObservationAgainstProfile(valContext,errors, element, stack, "Blood pressure systolic and diastolic", "Respiratory Rate", "SNOMED CT", codes, pct, mode) && ok;
|
||||
} else if (hasSctCode(code, codes, "271306003", "249043002", "444981005", "399017001", "251670001", "429525003", "429614003")) {
|
||||
ok = checkObservationAgainstProfile(valContext,errors, element, stack, "http://hl7.org/fhir/StructureDefinition/heartrate", "Heart rate", "SNOMED CT", codes, pct, mode) && ok;
|
||||
} else if (hasSctCode(code, codes, "103228002", "103228002", "442349007", "442476006", "442440005", "431314004", "442734002", "713194001")) {
|
||||
ok = checkObservationAgainstProfile(valContext,errors, element, stack, "http://hl7.org/fhir/StructureDefinition/oxygensat", "Oxygen saturation", "SNOMED CT", codes, pct, mode) && ok;
|
||||
} else if (hasSctCode(code, codes, "386725007", "276885007", "300076005", "1222808002", "364246006", "307047009", "708499008", "708499008", "431598003", "698831002", "698832009", "415882003", "415974002", "415929009", "415945006")) {
|
||||
ok = checkObservationAgainstProfile(valContext,errors, element, stack, "http://hl7.org/fhir/StructureDefinition/bodytemp", "Body temperature", "SNOMED CT", codes, pct, mode) && ok;
|
||||
} else if (hasSctCode(code, codes, "1153637007", "1162419008", "50373000", "1162418000", "1230278008", "1162392001", "1162417005")) {
|
||||
ok = checkObservationAgainstProfile(valContext,errors, element, stack, "http://hl7.org/fhir/StructureDefinition/bodyheight", "Body height", "SNOMED CT", codes, pct, mode) && ok;
|
||||
} else if (hasSctCode(code, codes, "363812007", "169876006", "1269262007", "363811000")) {
|
||||
ok = checkObservationAgainstProfile(valContext,errors, element, stack, "http://hl7.org/fhir/StructureDefinition/headcircum", "Head circumference", "SNOMED CT", codes, pct, mode) && ok;
|
||||
} else if (hasSctCode(code, codes, "363811000", "60621009", "735395000", "425024002", "424927000", "784399000", "1162416001", "1162415002")) {
|
||||
ok = checkObservationAgainstProfile(valContext,errors, element, stack, "http://hl7.org/fhir/StructureDefinition/bodyweight", "Body weight", "SNOMED CT", codes, pct, mode) && ok;
|
||||
} else if (hasSctCode(code, codes, "60621009")) {
|
||||
ok = checkObservationAgainstProfile(valContext,errors, element, stack, "http://hl7.org/fhir/StructureDefinition/bmi", "Body mass index", "SNOMED CT", codes, pct, mode) && ok;
|
||||
} else if (hasSctCode(code, codes, "75367002", "251076008", "163033001", "163035008", "386534000", "386536003", "271649006", "271649006", "271650006", "407556006", "407554009", "716579001", "399304008")) {
|
||||
ok = checkObservationAgainstProfile(valContext,errors, element, stack, "http://hl7.org/fhir/StructureDefinition/bp", "Blood pressure systolic and diastolic", "SNOMED CT", codes, pct, mode) && ok;
|
||||
}
|
||||
}
|
||||
// Looking for the vital signs code? It's moved to BasePolicyAdvisorForFullValidation.getImpliedProfilesForObservation
|
||||
return ok;
|
||||
}
|
||||
|
||||
private boolean checkObservationAgainstProfile(ValidationContext valContext, List<ValidationMessage> errors, Element element, NodeStack stack, String url, String name, String sys, List<String> loinc, PercentageTracker pct, ValidationMode mode) {
|
||||
element.addMessage(signpost(errors, NO_RULE_DATE, IssueType.INFORMATIONAL, element.line(), element.col(), stack.getLiteralPath(), I18nConstants.VALIDATION_VAL_PROFILE_SIGNPOST_OBS, url, name, sys, loinc.get(0)));
|
||||
StructureDefinition sd = context.fetchResource(StructureDefinition.class, url);
|
||||
if (sd == null) {
|
||||
return false;
|
||||
} else {
|
||||
return ((InstanceValidator) parent).startInner(valContext, errors, element, element, sd, stack, false, pct, mode, false);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasLoincCode(Element code, List<String> codes, String... values) {
|
||||
if (code != null) {
|
||||
List<Element> codings = code.getChildren("coding");
|
||||
for (Element coding : codings) {
|
||||
if ("http://loinc.org".equals(coding.getNamedChildValue("system", false)) && Utilities.existsInList(coding.getNamedChildValue("code", false), values)) {
|
||||
codes.add(coding.getNamedChildValue("code", false));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean hasSctCode(Element code, List<String> codes, String... values) {
|
||||
if (code != null) {
|
||||
List<Element> codings = code.getChildren("coding");
|
||||
for (Element coding : codings) {
|
||||
if ("http://snomed.info/sct".equals(coding.getNamedChildValue("system", false)) && Utilities.existsInList(coding.getNamedChildValue("code", false), values)) {
|
||||
codes.add(coding.getNamedChildValue("code", false));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import org.hl7.fhir.convertors.factory.VersionConvertorFactory_10_50;
|
|||
import org.hl7.fhir.convertors.factory.VersionConvertorFactory_14_50;
|
||||
import org.hl7.fhir.convertors.factory.VersionConvertorFactory_30_50;
|
||||
import org.hl7.fhir.convertors.factory.VersionConvertorFactory_40_50;
|
||||
import org.hl7.fhir.exceptions.DefinitionException;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities;
|
||||
import org.hl7.fhir.r5.elementmodel.Element;
|
||||
|
@ -87,6 +88,7 @@ public class StructureDefinitionValidator extends BaseValidator {
|
|||
StructureDefinition base = context.fetchResource(StructureDefinition.class, sd.getBaseDefinition());
|
||||
if (warning(errors, NO_RULE_DATE, IssueType.NOTFOUND, stack.getLiteralPath(), base != null, I18nConstants.UNABLE_TO_FIND_BASE__FOR_, sd.getBaseDefinition(), "StructureDefinition, so can't check the differential")) {
|
||||
if (rule(errors, NO_RULE_DATE, IssueType.NOTFOUND, stack.getLiteralPath(), sd.hasDerivation(), I18nConstants.SD_MUST_HAVE_DERIVATION, sd.getUrl())) {
|
||||
checkTypeParameters(errors, stack, base, sd);
|
||||
boolean bok = base.getAbstract() || sd.hasKind() && sd.getKind() == base.getKind();
|
||||
ok = rule(errors, "2022-11-02", IssueType.NOTFOUND, stack.getLiteralPath(), bok, I18nConstants.SD_CONSTRAINED_KIND_NO_MATCH, sd.getKind().toCode(), base.getKind().toCode(), base.getType(), base.getUrl()) && ok;
|
||||
if (sd.getDerivation() == TypeDerivationRule.CONSTRAINT) {
|
||||
|
@ -193,6 +195,27 @@ public class StructureDefinitionValidator extends BaseValidator {
|
|||
return ok;
|
||||
}
|
||||
|
||||
private boolean checkTypeParameters(List<ValidationMessage> errors, NodeStack stack, StructureDefinition base, StructureDefinition derived) {
|
||||
String bt = ToolingExtensions.readStringExtension(base, ToolingExtensions.EXT_TYPE_PARAMETER);
|
||||
if (bt == null) {
|
||||
return true;
|
||||
} else {
|
||||
if (rule(errors, "2024-05-29", IssueType.INVALID, stack.getLiteralPath(), derived.hasExtension(ToolingExtensions.EXT_TYPE_PARAMETER), I18nConstants.SD_TYPE_PARAMETER_MISSING, base.getVersionedUrl(), bt, derived.getVersionedUrl())) {
|
||||
String dt = ToolingExtensions.readStringExtension(derived, ToolingExtensions.EXT_TYPE_PARAMETER);
|
||||
StructureDefinition bsd = context.fetchTypeDefinition(bt);
|
||||
StructureDefinition dsd = context.fetchTypeDefinition(dt);
|
||||
if (rule(errors, "2024-05-29", IssueType.INVALID, stack.getLiteralPath(), bsd != null, I18nConstants.SD_TYPE_PARAMETER_UNKNOWN, base.getVersionedUrl(), bt) &&
|
||||
rule(errors, "2024-05-29", IssueType.INVALID, stack.getLiteralPath(), dsd != null, I18nConstants.SD_TYPE_PARAMETER_UNKNOWN, derived.getVersionedUrl(), dt)) {
|
||||
StructureDefinition t = dsd;
|
||||
while (t != bsd && t != null) {
|
||||
t = context.fetchResource(StructureDefinition.class, t.getBaseDefinition());
|
||||
}
|
||||
return rule(errors, "2024-05-29", IssueType.INVALID, stack.getLiteralPath(), t != null, I18nConstants.SD_TYPE_PARAMETER_INVALID, base.getVersionedUrl(), bt, derived.getVersionedUrl(), dt);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private String getFixedValue(Element src) {
|
||||
Element diff = src.getNamedChild("differential", false);
|
||||
|
@ -465,7 +488,8 @@ public class StructureDefinitionValidator extends BaseValidator {
|
|||
typeCodes.add(tc);
|
||||
Set<String> tcharacteristics = new HashSet<>();
|
||||
StructureDefinition tsd = context.fetchTypeDefinition(tc);
|
||||
if (tsd != null) {
|
||||
if (tsd != null) {
|
||||
checkTypeParameters(errors, stack, type, tc, tsd, path, sd);
|
||||
characteristicsValid = true;
|
||||
if (tsd.hasExtension(ToolingExtensions.EXT_TYPE_CHARACTERISTICS)) {
|
||||
for (Extension ext : tsd.getExtensionsByUrl(ToolingExtensions.EXT_TYPE_CHARACTERISTICS)) {
|
||||
|
@ -566,6 +590,54 @@ public class StructureDefinitionValidator extends BaseValidator {
|
|||
return ok;
|
||||
}
|
||||
|
||||
private boolean checkTypeParameters(List<ValidationMessage> errors, NodeStack stack, Element typeE, String tc, StructureDefinition tsd, String path, StructureDefinition sd) {
|
||||
boolean ok = true;
|
||||
if (tsd.hasExtension(ToolingExtensions.EXT_TYPE_PARAMETER)) {
|
||||
List<Element> extensions = typeE.getChildrenByName("extension");
|
||||
for (Extension ext : tsd.getExtensionsByUrl(ToolingExtensions.EXT_TYPE_PARAMETER)) {
|
||||
String name = ext.getExtensionString("name");
|
||||
String type = ext.getExtensionString("type");
|
||||
StructureDefinition psd = context.fetchTypeDefinition(type);
|
||||
if (psd != null && name != null) {
|
||||
boolean found = false;
|
||||
for (Element e : extensions) {
|
||||
if (ToolingExtensions.EXT_TYPE_PARAMETER.equals(e.getNamedChildValue("url"))) {
|
||||
String ename = e.getExtensionValue("name").primitiveValue();
|
||||
if (name.equals(ename)) {
|
||||
found = true;
|
||||
String etype = e.getExtensionValue("type").primitiveValue();
|
||||
for (Extension ex : sd.getExtensionsByUrl(ToolingExtensions.EXT_TYPE_PARAMETER)) {
|
||||
String tn = ex.getExtensionString("name");
|
||||
if (tn != null && tn.equals(etype)) {
|
||||
etype = ex.getExtensionString("type");
|
||||
break;
|
||||
}
|
||||
}
|
||||
StructureDefinition esd = context.fetchTypeDefinition(etype);
|
||||
if (rule(errors, "2024-05-29", IssueType.BUSINESSRULE, stack.getLiteralPath(), esd != null, I18nConstants.SD_TYPE_PARAMETER_UNKNOWN, tc, etype)) {
|
||||
StructureDefinition t = esd;
|
||||
while (t != null && t != psd) {
|
||||
t = context.fetchResource(StructureDefinition.class, t.getBaseDefinition());
|
||||
}
|
||||
ok = rule(errors, "2024-05-29", IssueType.BUSINESSRULE, stack.getLiteralPath(), t != null, I18nConstants.SD_TYPE_PARAMETER_INVALID_REF, tc, etype, tsd.getVersionedUrl(), name, type) & ok;
|
||||
if (t != null) {
|
||||
if (!sd.getAbstract() && esd.getAbstract()) {
|
||||
warning(errors, "2024-05-29", IssueType.BUSINESSRULE, stack.getLiteralPath(), t != null, I18nConstants.SD_TYPE_PARAMETER_ABSTRACT_WARNING, tc, etype, tsd.getVersionedUrl(), name, type);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ok = rule(errors, "2024-05-29", IssueType.BUSINESSRULE, stack.getLiteralPath(), found, I18nConstants.SD_TYPE_PARAM_NOT_SPECIFIED, tc, tsd.getVersionedUrl(), name, path) && ok;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
private ElementDefinition getDefinitionFromBase(StructureDefinition base, String id, String path) {
|
||||
ElementDefinition ed = null;
|
||||
if (id != null) {
|
||||
|
|
|
@ -59,6 +59,7 @@ import org.hl7.fhir.r5.test.utils.TestingUtilities;
|
|||
import org.hl7.fhir.r5.utils.OperationOutcomeUtilities;
|
||||
import org.hl7.fhir.r5.utils.ToolingExtensions;
|
||||
import org.hl7.fhir.r5.utils.validation.BundleValidationRule;
|
||||
import org.hl7.fhir.r5.utils.validation.IMessagingServices;
|
||||
import org.hl7.fhir.r5.utils.validation.IResourceValidator;
|
||||
import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor;
|
||||
import org.hl7.fhir.r5.utils.validation.IValidatorResourceFetcher;
|
||||
|
@ -90,6 +91,7 @@ import org.hl7.fhir.validation.ValidationEngine;
|
|||
import org.hl7.fhir.validation.ValidatorUtils;
|
||||
import org.hl7.fhir.validation.cli.model.HtmlInMarkdownCheck;
|
||||
import org.hl7.fhir.validation.cli.services.StandAloneValidatorFetcher;
|
||||
import org.hl7.fhir.validation.instance.BasePolicyAdvisorForFullValidation;
|
||||
import org.hl7.fhir.validation.instance.InstanceValidator;
|
||||
import org.hl7.fhir.validation.tests.utilities.TestUtilities;
|
||||
import org.junit.AfterClass;
|
||||
|
@ -469,7 +471,7 @@ public class ValidationTests implements IEvaluationContext, IValidatorResourceFe
|
|||
}
|
||||
|
||||
private ValidationEngine buildVersionEngine(String ver, String txLog) throws Exception {
|
||||
String server = FhirSettings.getTxFhirLocal();
|
||||
String server = FhirSettings.getTxFhirDevelopment();
|
||||
switch (ver) {
|
||||
case "1.0": return TestUtilities.getValidationEngine("hl7.fhir.r2.core#1.0.2", server, txLog, FhirPublication.DSTU2, true, "1.0.2");
|
||||
case "1.4": return TestUtilities.getValidationEngine("hl7.fhir.r2b.core#1.4.0", server, txLog, FhirPublication.DSTU2016May, true, "1.4.0");
|
||||
|
@ -887,4 +889,12 @@ public class ValidationTests implements IEvaluationContext, IValidatorResourceFe
|
|||
public Set<String> fetchCanonicalResourceVersions(IResourceValidator validator, Object appContext, String url) {
|
||||
return new HashSet<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StructureDefinition> getImpliedProfilesForResource(IResourceValidator validator, Object appContext,
|
||||
String stackPath, ElementDefinition definition, StructureDefinition structure, Element resource, boolean valid,
|
||||
IMessagingServices msgServices, List<ValidationMessage> messages) {
|
||||
return new BasePolicyAdvisorForFullValidation().getImpliedProfilesForResource(validator, appContext, stackPath,
|
||||
definition, structure, resource, valid, msgServices, messages);
|
||||
}
|
||||
}
|
2
pom.xml
2
pom.xml
|
@ -21,7 +21,7 @@
|
|||
<commons_compress_version>1.26.0</commons_compress_version>
|
||||
<guava_version>32.0.1-jre</guava_version>
|
||||
<hapi_fhir_version>6.4.1</hapi_fhir_version>
|
||||
<validator_test_case_version>1.5.10</validator_test_case_version>
|
||||
<validator_test_case_version>1.5.11-SNAPSHOT</validator_test_case_version>
|
||||
<jackson_version>2.17.0</jackson_version>
|
||||
<junit_jupiter_version>5.9.2</junit_jupiter_version>
|
||||
<junit_platform_launcher_version>1.8.2</junit_platform_launcher_version>
|
||||
|
|
Loading…
Reference in New Issue