Skip to content

Commit

Permalink
Issue #2582, #2583 - general refactoring / clean-up
Browse files Browse the repository at this point in the history
Signed-off-by: John T.E. Timm <johntimm@us.ibm.com>
  • Loading branch information
JohnTimm committed Jul 12, 2021
1 parent 73881f4 commit 566fddc
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 82 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -202,13 +202,7 @@ public List<Issue> validate(EvaluationContext evaluationContext, boolean include
}
try {
evaluationContext.setResolveRelativeReferences(true);
List<Issue> issues = new ArrayList<>();
validateProfileReferences(evaluationContext.getTree().getRoot().asResourceNode(), Arrays.asList(profiles), false, issues, failFast);
if (!(failFast && hasErrors(issues))) {
issues.addAll(visitor.validate(evaluationContext, includeResourceAssertedProfiles, profiles));
}
Collections.sort(issues, ISSUE_COMPARATOR);
return Collections.unmodifiableList(issues);
return visitor.validate(evaluationContext, includeResourceAssertedProfiles, profiles);
} catch (Exception e) {
throw new FHIRValidationException("An error occurred during validation", e);
}
Expand All @@ -222,45 +216,6 @@ public static FHIRValidator validator(boolean failFast) {
return new FHIRValidator(failFast);
}

/**
* Validate a list of profile references to ensure they are supported (known by the FHIR registry) and applicable
* (the type constrained by the profile is compatible with the resource being validated).
*
* <p>Resource-asserted profile references that are not available in the FHIRRegistry result in issues with severity WARNING.
*
* <p>Unknown profile references passed as arguments to this method result in issues with severity ERROR.
*
* <p>Profiles that are incompatible with the resource type being validated result in issues with severity ERROR.
*
* @param resourceNode
* the resource node being validated by a FHIRValidator instance
* @param profiles
* the list of profile references to validate
* @param resourceAsserted
* indicates whether the profile references came from the resource or were explicitly passed in as arguments
* @param issues
* the list of issues to add to
*/
private static void validateProfileReferences(
FHIRPathResourceNode resourceNode,
List<String> profiles,
boolean resourceAsserted,
List<Issue> issues,
boolean failFast) {
Class<?> resourceType = resourceNode.resource().getClass();
for (String url : profiles) {
if (failFast && hasErrors(issues)) {
break;
}
StructureDefinition profile = ProfileSupport.getProfile(url);
if (profile == null) {
issues.add(issue(resourceAsserted ? IssueSeverity.WARNING : IssueSeverity.ERROR, IssueType.NOT_SUPPORTED, "Profile '" + url + "' is not supported", resourceNode));
} else if (!ProfileSupport.isApplicable(profile, resourceType)) {
issues.add(issue(IssueSeverity.ERROR, IssueType.INVALID, "Profile '" + url + "' is not applicable to resource type: " + resourceType.getSimpleName(), resourceNode));
}
}
}

private static Issue issue(IssueSeverity severity, IssueType code, String description, FHIRPathNode node) {
return issue(severity, code, description, null, node.path());
}
Expand Down Expand Up @@ -298,7 +253,8 @@ private List<Issue> validate(EvaluationContext evaluationContext, boolean includ
this.includeResourceAssertedProfiles = includeResourceAssertedProfiles;
this.profiles = Arrays.asList(profiles);
this.evaluationContext.getTree().getRoot().accept(this);
return issues;
Collections.sort(issues, ISSUE_COMPARATOR);
return Collections.unmodifiableList(issues);
}

private void reset() {
Expand Down Expand Up @@ -327,17 +283,13 @@ public void doVisit(FHIRPathResourceNode node) {
validate(node);
}

/**
* @throws RuntimeException if the registered constraints cannot be evaluated for the passed element node
*/
private void validate(FHIRPathElementNode elementNode) {
Class<?> elementType = elementNode.element().getClass();
Collection<Constraint> constraints = ModelSupport.getConstraints(elementType);
List<Constraint> constraints = new ArrayList<>(ModelSupport.getConstraints(elementType));
if (Extension.class.equals(elementType)) {
String url = elementNode.element().as(Extension.class).getUrl();
if (isAbsolute(url)) {
if (FHIRRegistry.getInstance().hasResource(url, StructureDefinition.class)) {
constraints = new ArrayList<>(constraints);
constraints.add(createConstraint("generated-ext-1", Constraint.LEVEL_RULE, Constraint.LOCATION_BASE, "Extension must conform to definition '" + url + "'", "conformsTo('" + url + "')", SOURCE_VALIDATOR, false, true));
} else {
issues.add(issue(IssueSeverity.WARNING, IssueType.NOT_SUPPORTED, "Extension definition '" + url + "' is not supported", elementNode));
Expand All @@ -347,35 +299,39 @@ private void validate(FHIRPathElementNode elementNode) {
validate(elementType, elementNode, constraints);
}

private boolean isAbsolute(String url) {
try {
return new URI(url).isAbsolute();
} catch (URISyntaxException e) {
log.warning("Invalid URI: " + url);
}
return false;
}

/**
* @throws RuntimeException if the registered constraints cannot be evaluated for the passed resource node
*/
private void validate(FHIRPathResourceNode resourceNode) {
Class<?> resourceType = resourceNode.resource().getClass();
validate(resourceType, resourceNode, ModelSupport.getConstraints(resourceType));
List<Constraint> constraints = new ArrayList<>(ModelSupport.getConstraints(resourceType));
if (!profiles.isEmpty() && !resourceNode.path().contains(".")) {
validateProfileReferences(resourceNode, profiles, false);
constraints.addAll(ProfileSupport.getConstraints(profiles, resourceType));
}
if (includeResourceAssertedProfiles) {
List<String> resourceAssertedProfiles = ProfileSupport.getResourceAssertedProfiles(resourceNode.resource());
validateProfileReferences(resourceNode, resourceAssertedProfiles, true, issues, failFast);
aborted = failFast && hasErrors(issues);
validate(resourceType, resourceNode, ProfileSupport.getConstraints(resourceAssertedProfiles, resourceType));
validateProfileReferences(resourceNode, resourceAssertedProfiles, true);
constraints.addAll(ProfileSupport.getConstraints(resourceAssertedProfiles, resourceType));
}
if (!profiles.isEmpty() && !resourceNode.path().contains(".")) {
validate(resourceType, resourceNode, ProfileSupport.getConstraints(profiles, resourceType));
validate(resourceType, resourceNode, constraints);
}

private void validateProfileReferences(FHIRPathResourceNode resourceNode, List<String> profiles, boolean resourceAsserted) {
Class<?> resourceType = resourceNode.resource().getClass();
for (String url : profiles) {
if (aborted) {
break;
}
StructureDefinition profile = ProfileSupport.getProfile(url);
if (profile == null) {
issues.add(issue(resourceAsserted ? IssueSeverity.WARNING : IssueSeverity.ERROR, IssueType.NOT_SUPPORTED, "Profile '" + url + "' is not supported", resourceNode));
} else if (!ProfileSupport.isApplicable(profile, resourceType)) {
issues.add(issue(IssueSeverity.ERROR, IssueType.INVALID, "Profile '" + url + "' is not applicable to resource type: " + resourceType.getSimpleName(), resourceNode));
}
if (failFast && hasErrors(issues)) {
aborted = true;
}
}
}

/**
* @throws RuntimeException if one of the passed constraints cannot be evaluated for the passed node
*/
private void validate(Class<?> type, FHIRPathNode node, Collection<Constraint> constraints) {
for (Constraint constraint : constraints) {
if (aborted) {
Expand All @@ -393,9 +349,6 @@ private void validate(Class<?> type, FHIRPathNode node, Collection<Constraint> c
}
}

/**
* @throws RuntimeException if the passed constraint cannot be evaluated for the passed node
*/
private void validate(Class<?> type, FHIRPathNode node, Constraint constraint) {
String path = node.path();
try {
Expand Down Expand Up @@ -446,10 +399,17 @@ private void validate(Class<?> type, FHIRPathNode node, Constraint constraint) {
evaluationContext.removeEvaluationListener(diagnosticsEvaluationListener);
}
} catch (Exception e) {
throw new RuntimeException("An error occurred while validating constraint: " + constraint.id() +
" with location: " + constraint.location() + " and expression: " + constraint.expression() +
" at path: " + path, e);
throw new RuntimeException("An error occurred while validating constraint: " + constraint.id() + " with location: " + constraint.location() + " and expression: " + constraint.expression() + " at path: " + path, e);
}
}

private boolean isAbsolute(String url) {
try {
return new URI(url).isAbsolute();
} catch (URISyntaxException e) {
log.warning("Invalid URI: " + url);
}
return false;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* (C) Copyright IBM Corp. 2019, 2020
* (C) Copyright IBM Corp. 2019, 2021
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand Down Expand Up @@ -124,8 +124,8 @@ public void testResourceAssertedProfileNotSupported() throws Exception {
.build();
List<Issue> issues = FHIRValidator.validator().validate(patient);
assertEquals(issues.size(), 2);
assertEquals(issues.get(1).getSeverity(), IssueSeverity.WARNING);
assertEquals(issues.get(1).getCode(), IssueType.NOT_SUPPORTED);
assertEquals(issues.get(0).getSeverity(), IssueSeverity.WARNING);
assertEquals(issues.get(0).getCode(), IssueType.NOT_SUPPORTED);
}

@Test
Expand Down

0 comments on commit 566fddc

Please sign in to comment.