diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java index 79132ec52..3a0da77e7 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java @@ -4433,7 +4433,8 @@ public class FHIRPathEngine { public ElementDefinition evaluateDefinition(ExpressionNode expr, StructureDefinition profile, ElementDefinition element) throws DefinitionException { StructureDefinition sd = profile; ElementDefinition focus = null; - + boolean okToNotResolve = false; + if (expr.getKind() == Kind.Name) { if (element.hasSlicing()) { ElementDefinition slice = pickMandatorySlice(sd, element); @@ -4493,6 +4494,19 @@ public class FHIRPathEngine { } } } + } else if ("ofType".equals(expr.getName())) { + if (!element.hasType()) + throw new DefinitionException("illegal use of ofType() in discriminator - no type on element "+element.getId()); + if (element.getType().size() > 1) + throw new DefinitionException("illegal use of ofType() in discriminator - Multiple possible types on "+element.getId()); + if (!element.getType().get(0).hasCode()) + throw new DefinitionException("illegal use of ofType() in discriminator - Type has no code on "+element.getId()); + String atn = element.getType().get(0).getCode(); + String stn = expr.getParameters().get(0).getName(); + okToNotResolve = true; + if ((atn.equals(stn))) { + focus = element; + } } else throw new DefinitionException("illegal function name "+expr.getName()+"() in discriminator"); } else if (expr.getKind() == Kind.Group) { @@ -4501,9 +4515,13 @@ public class FHIRPathEngine { throw new DefinitionException("illegal expression syntax in discriminator (const)"); } - if (focus == null) - throw new DefinitionException("Unable to resolve discriminator in definitions: "+expr.toString()); - else if (expr.getInner() == null) + if (focus == null) { + if (okToNotResolve) { + return null; + } else { + throw new DefinitionException("Unable to resolve discriminator in definitions: "+expr.toString()); + } + } else if (expr.getInner() == null) return focus; else { return evaluateDefinition(expr.getInner(), sd, focus); diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/NpmPackage.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/NpmPackage.java index aa8dd1419..499dbf9a0 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/NpmPackage.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/NpmPackage.java @@ -120,7 +120,10 @@ public class NpmPackage { return name; } - public void readIndex(JsonObject index) { + public boolean readIndex(JsonObject index) { + if (!index.has("index-version") || (index.get("index-version").getAsInt() != 1)) { + return false; + } this.index = index; for (JsonElement e : index.getAsJsonArray("files")) { JsonObject file = (JsonObject) e; @@ -130,6 +133,7 @@ public class NpmPackage { types.put(type, new ArrayList<>()); types.get(type).add(name); } + return true; } public List listFiles() { @@ -210,7 +214,7 @@ public class NpmPackage { */ public static NpmPackage fromFolder(String path) throws IOException { NpmPackage res = new NpmPackage(); - loadFiles(res, path, new File(path)); + res.loadFiles(path, new File(path)); res.checkIndexed(path); return res; } @@ -228,9 +232,9 @@ public class NpmPackage { return userData; } - public static void loadFiles(NpmPackage res, String path, File source, String... exemptions) throws FileNotFoundException, IOException { - res.npm = (JsonObject) new com.google.gson.JsonParser().parse(TextFile.fileToString(Utilities.path(path, "package", "package.json"))); - res.path = path; + public void loadFiles(String path, File source, String... exemptions) throws FileNotFoundException, IOException { + this.npm = (JsonObject) new com.google.gson.JsonParser().parse(TextFile.fileToString(Utilities.path(path, "package", "package.json"))); + this.path = path; File dir = new File(path); for (File f : dir.listFiles()) { @@ -240,22 +244,24 @@ public class NpmPackage { if (!d.equals("package")) { d = Utilities.path("package", d); } - NpmPackageFolder folder = res.new NpmPackageFolder(d); + NpmPackageFolder folder = this.new NpmPackageFolder(d); folder.folder = f; - res.folders.put(d, folder); + this.folders.put(d, folder); File ij = new File(Utilities.path(f.getAbsolutePath(), ".index.json")); if (ij.exists()) { try { - folder.readIndex(JsonTrackingParser.parseJson(ij)); + if (!folder.readIndex(JsonTrackingParser.parseJson(ij))) { + indexFolder(folder.getName(), folder); + } } catch (Exception e) { throw new IOException("Error parsing "+ij.getAbsolutePath()+": "+e.getMessage(), e); } } - loadSubFolders(res, dir.getAbsolutePath(), f); + loadSubFolders(dir.getAbsolutePath(), f); } else { - NpmPackageFolder folder = res.new NpmPackageFolder(Utilities.path("package", "$root")); + NpmPackageFolder folder = this.new NpmPackageFolder(Utilities.path("package", "$root")); folder.folder = dir; - res.folders.put(Utilities.path("package", "$root"), folder); + this.folders.put(Utilities.path("package", "$root"), folder); } } } @@ -265,25 +271,27 @@ public class NpmPackage { return Utilities.existsInList(f.getName(), ".git", ".svn") || Utilities.existsInList(f.getName(), "package-list.json"); } - private static void loadSubFolders(NpmPackage res, String rootPath, File dir) throws IOException { + private void loadSubFolders(String rootPath, File dir) throws IOException { for (File f : dir.listFiles()) { if (f.isDirectory()) { String d = f.getAbsolutePath().substring(rootPath.length()+1); if (!d.startsWith("package")) { d = Utilities.path("package", d); } - NpmPackageFolder folder = res.new NpmPackageFolder(d); + NpmPackageFolder folder = this.new NpmPackageFolder(d); folder.folder = f; - res.folders.put(d, folder); + this.folders.put(d, folder); File ij = new File(Utilities.path(f.getAbsolutePath(), ".index.json")); if (ij.exists()) { try { - folder.readIndex(JsonTrackingParser.parseJson(ij)); + if (!folder.readIndex(JsonTrackingParser.parseJson(ij))) { + indexFolder(folder.getName(), folder); + } } catch (Exception e) { throw new IOException("Error parsing "+ij.getAbsolutePath()+": "+e.getMessage(), e); } } - loadSubFolders(res, rootPath, f); + loadSubFolders(rootPath, f); } } @@ -291,7 +299,7 @@ public class NpmPackage { public static NpmPackage fromFolder(String folder, PackageType defType, String... exemptions) throws IOException { NpmPackage res = new NpmPackage(); - loadFiles(res, folder, new File(folder), exemptions); + res.loadFiles(folder, new File(folder), exemptions); if (!res.folders.containsKey("package")) { res.folders.put("package", res.new NpmPackageFolder("package")); } @@ -386,29 +394,36 @@ public class NpmPackage { private void checkIndexed(String desc) throws IOException { for (NpmPackageFolder folder : folders.values()) { - List remove = new ArrayList<>(); if (folder.index == null) { - NpmPackageIndexBuilder indexer = new NpmPackageIndexBuilder(); - indexer.start(); - for (String n : folder.listFiles()) { - if (!indexer.seeFile(n, folder.fetchFile(n))) { - remove.add(n); - } - } - for (String n : remove) { - folder.removeFile(n); - } - String json = indexer.build(); - try { - folder.readIndex(JsonTrackingParser.parseJson(json)); - } catch (Exception e) { - TextFile.stringToFile(json, Utilities.path("[tmp]", ".index.json")); - throw new IOException("Error parsing "+(desc == null ? "" : desc+"#")+"package/"+folder.name+"/.index.json: "+e.getMessage(), e); - } + indexFolder(desc, folder); } } } + public void indexFolder(String desc, NpmPackageFolder folder) throws FileNotFoundException, IOException { + List remove = new ArrayList<>(); + NpmPackageIndexBuilder indexer = new NpmPackageIndexBuilder(); + indexer.start(); + for (String n : folder.listFiles()) { + if (!indexer.seeFile(n, folder.fetchFile(n))) { + remove.add(n); + } + } + for (String n : remove) { + folder.removeFile(n); + } + String json = indexer.build(); + try { + folder.readIndex(JsonTrackingParser.parseJson(json)); + if (folder.folder != null) { + TextFile.stringToFile(json, Utilities.path(folder.folder.getAbsolutePath(), ".index.json")); + } + } catch (Exception e) { + TextFile.stringToFile(json, Utilities.path("[tmp]", ".index.json")); + throw new IOException("Error parsing "+(desc == null ? "" : desc+"#")+"package/"+folder.name+"/.index.json: "+e.getMessage(), e); + } + } + public static NpmPackage fromZip(InputStream stream, boolean dropRootFolder, String desc) throws IOException { NpmPackage res = new NpmPackage(); diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java index 89c74884d..cff1e7f43 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java @@ -501,4 +501,5 @@ public class I18nConstants { public static final String _HAS_CHILDREN__AND_MULTIPLE_TYPES__IN_PROFILE_ = "_has_children__and_multiple_types__in_profile_"; public static final String _HAS_CHILDREN__FOR_TYPE__IN_PROFILE__BUT_CANT_FIND_TYPE = "_has_children__for_type__in_profile__but_cant_find_type"; public static final String _HAS_NO_CHILDREN__AND_NO_TYPES_IN_PROFILE_ = "_has_no_children__and_no_types_in_profile_"; + public static final String ALL_OK = "ALL_OK"; } \ No newline at end of file diff --git a/org.hl7.fhir.utilities/src/main/resources/Messages.properties b/org.hl7.fhir.utilities/src/main/resources/Messages.properties index f46b3554c..7dda4b9c4 100644 --- a/org.hl7.fhir.utilities/src/main/resources/Messages.properties +++ b/org.hl7.fhir.utilities/src/main/resources/Messages.properties @@ -502,3 +502,4 @@ VALIDATION_VAL_ILLEGAL_TYPE_CONSTRAINT = Illegal constraint in profile {0} at pa EXTENSION_EXT_CONTEXT_WRONG_XVER = The extension {0} from FHIR version {3} is not allowed to be used at this point (allowed = {1}; this element is [{2}; this is a warning since contexts may be renamed between FHIR versions) SECURITY_STRING_CONTENT_ERROR = The string value contains embedded HTML tags, which are not allowed for security reasons in this context SECURITY_STRING_CONTENT_WARNING = The string value contains embedded HTML tags. Note that all inputs should be escaped when rendered to HTML as a matter of course +ALL_OK = All OK \ No newline at end of file diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java index 1214f90ab..1823df8f3 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java @@ -40,6 +40,8 @@ import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.utilities.cache.NpmPackage; import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager; import org.hl7.fhir.utilities.cache.ToolsVersion; +import org.hl7.fhir.utilities.i18n.I18nBase; +import org.hl7.fhir.utilities.i18n.I18nConstants; import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; @@ -1191,6 +1193,9 @@ public class ValidationEngine implements IValidatorResourceFetcher { } op.getIssue().add(OperationOutcomeUtilities.convertToIssue(vm, op)); } + if (!op.hasIssue()) { + op.addIssue().setSeverity(OperationOutcome.IssueSeverity.INFORMATION).setCode(OperationOutcome.IssueType.INFORMATIONAL).getDetails().setText(context.formatMessage(I18nConstants.ALL_OK)); + } RenderingContext rc = new RenderingContext(context, null, null, "http://hl7.org/fhir", "", null, ResourceRendererMode.RESOURCE); RendererFactory.factory(op, rc).render(op); return op; diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationEngineTests.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationEngineTests.java index 1a83e282f..8bf699c79 100644 --- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationEngineTests.java +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationEngineTests.java @@ -38,7 +38,7 @@ public class ValidationEngineTests { } Assertions.assertEquals(0, e); Assertions.assertEquals(0, w); - Assertions.assertEquals(0, h); + Assertions.assertEquals(1, h); } @Test @@ -52,7 +52,7 @@ public class ValidationEngineTests { int h = hints(op); Assertions.assertEquals(0, e); Assertions.assertEquals(0, w); - Assertions.assertEquals(0, h); + Assertions.assertEquals(1, h); if (!TestUtilities.silent) System.out.println(" .. done: " + Integer.toString(e) + " errors, " + Integer.toString(w) + " warnings, " + Integer.toString(h) + " information messages"); }