Skip to content

Commit

Permalink
issue #3661 - cleanup and fixes
Browse files Browse the repository at this point in the history
Removed comments, split some logic into private helpers (for
readability), and fixed logic error in
ConstraintGenerator.generateExtensionConstraint

Signed-off-by: Lee Surprenant <[email protected]>
  • Loading branch information
lmsurpre committed May 25, 2022
1 parent 9180ef4 commit 6692b59
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -516,15 +516,11 @@ private String generateExtensionConstraint(Node node) {

Type type = getTypes(elementDefinition).get(0);
String profile = type.getProfile().get(0).getValue();
String profileWithoutVersion = profile.contains("|") ? profile.substring(0, profile.lastIndexOf("|")) : profile;

// if (profile.contains("|")) {
String profileWithoutVersion = profile.substring(0, profile.lastIndexOf("|"));
sb.append("extension('").append(profileWithoutVersion).append("')").append(cardinality(node, sb.toString()));
sb.append(" and ");
sb.append("extension('").append(profileWithoutVersion).append("')").append(".all(conformsTo('" + profile + "'))");
// } else {
// sb.append("extension('").append(profile).append("')").append(cardinality(node, sb.toString()));
// }
sb.append("extension('").append(profileWithoutVersion).append("')").append(cardinality(node, sb.toString()));
sb.append(" and ");
sb.append("extension('").append(profileWithoutVersion).append("')").append(".all(conformsTo('" + profile + "'))");

return sb.toString();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -330,64 +330,29 @@ private void validate(FHIRPathResourceNode resourceNode) {
constraints.addAll(ProfileSupport.getConstraints(profiles, resourceType));
}

// add instance-specific extension constraints
PathAwareCollectingVisitor<Extension> extCollector = new PathAwareCollectingVisitor<Extension>(Extension.class);
resourceNode.resource().accept(extCollector);
Map<String, Extension> pathToExtension = extCollector.getResult();

// for option A below: find all the versions of the extension in the registry
// Map<String, Set<String>> profileVersions = collectProfileVersions(pathToExtension.values());

// for option B below: gather all the constraint ids and pull out the specially-marked extension ones
Map<String, Set<String>> alreadyGeneratedExtensionConstraints = new HashMap<>();
for (Constraint c : constraints) {
int urlDelim = c.id().lastIndexOf("<");
if (urlDelim <= 0 || !c.id().endsWith(">")) {
continue;
}

String firstPart = c.id().substring(0, urlDelim);
int pathDelim = firstPart.lastIndexOf("~");
if (pathDelim <= 0 || pathDelim == firstPart.length()) {
continue;
}
String path = firstPart.substring(pathDelim + 1);
String url = c.id().substring(urlDelim + 1, c.id().length() - 1);
alreadyGeneratedExtensionConstraints.computeIfAbsent(path, t -> new HashSet<>()).add(url);
}
// path (with array indices) -> Extension instance (which never have a url version suffix)
Map<String, Extension> pathToExtension = gatherInstanceExtensions(resourceNode);
// path (with no array indices) -> Extension URLs (with no version suffix)
Map<String, Set<String>> alreadyGeneratedExtensionConstraints = gatherExtensionConstraints(constraints);

// for each extension in the resource instance
for (Entry<String, Extension> entry : pathToExtension.entrySet()) {
String path = entry.getKey();
Extension e = entry.getValue();
String url = e.getUrl();
if (isAbsolute(url)) {
// Option A: find all versions of the extension and pass validation if the instance conforms to at least one
// Option B: introspect the existing constraints and only add this one if the extension is not covered by profile constraints

// Option A: conformance to any one version of the extension is sufficient
// if (profileVersions.containsKey(url)) {
// String constraint = profileVersions.get(url).stream()
// .map(v -> "conformsTo('" + url + "|" + v + "')")
// .collect(Collectors.joining(" or "));
//
// constraints.add(Constraint.Factory.createConstraint("generated-ext-1", Constraint.LEVEL_RULE, path,
// "Extension must conform to at least one definition of '" + url + "'", constraint, SOURCE_VALIDATOR, false, true));
// } else {
// issues.add(issue(IssueSeverity.WARNING, IssueType.NOT_SUPPORTED, "Extension definition '" + url + "' is not supported", null, path));
// }

// Option B: conditionally add a conformsTo constraint for the default/latest version of this extension

// remove the array indices from the path
String reducedPath = path.replaceAll("\\[[0-9]+\\]", "");

// if the profile validation already has this covered, then move on to the next extension
if (alreadyGeneratedExtensionConstraints.containsKey(reducedPath)
&& alreadyGeneratedExtensionConstraints.get(reducedPath).contains(url)) {
continue;
}

// otherwise generate the instance-specifc conformsTo constraint (or add a warning if we don't have a definition for it)
if (FHIRRegistry.getInstance().hasResource(url, StructureDefinition.class)) {
constraints.add(Constraint.Factory.createConstraint("generated-ext-2", Constraint.LEVEL_RULE, path,
constraints.add(Constraint.Factory.createConstraint("generated-ext~" + path + "<" + url + ">", Constraint.LEVEL_RULE, path,
"Extension must conform to definition '" + url + "'",
"conformsTo('" + url + "')", SOURCE_VALIDATOR, false, true));
} else {
Expand All @@ -399,6 +364,41 @@ private void validate(FHIRPathResourceNode resourceNode) {
validate(resourceNode, constraints);
}

/**
* Collect all the extensions from the resource instance and index them by their simple FHIRPath paths
*/
private Map<String, Extension> gatherInstanceExtensions(FHIRPathResourceNode resourceNode) {
PathAwareCollectingVisitor<Extension> extCollector = new PathAwareCollectingVisitor<Extension>(Extension.class);
resourceNode.resource().accept(extCollector);
Map<String, Extension> pathToExtension = extCollector.getResult();
return pathToExtension;
}

/**
* Gather all the constraint ids and process the specially-marked extension ones into a map
* from the paths to the set of corresponding extension URLs (with no version suffix).
*/
private Map<String, Set<String>> gatherExtensionConstraints(List<Constraint> constraints) {
Map<String, Set<String>> alreadyGeneratedExtensionConstraints = new HashMap<>();
for (Constraint c : constraints) {
int urlMark = c.id().lastIndexOf("<");
if (urlMark <= 0 || !c.id().endsWith(">")) {
continue;
}

String firstPart = c.id().substring(0, urlMark);
int pathMark = firstPart.lastIndexOf("~");
if (pathMark <= 0) {
continue;
}
String path = firstPart.substring(pathMark + 1);

String url = c.id().substring(urlMark + 1, c.id().length() - 1);
alreadyGeneratedExtensionConstraints.computeIfAbsent(path, t -> new HashSet<>()).add(url);
}
return alreadyGeneratedExtensionConstraints;
}

private void validateProfileReferences(FHIRPathResourceNode resourceNode, List<String> profiles, boolean resourceAsserted) {
Class<?> resourceType = resourceNode.resource().getClass();
for (String url : profiles) {
Expand Down

0 comments on commit 6692b59

Please sign in to comment.