rework type checking on target profiles to support imposesProfile

This commit is contained in:
Grahame Grieve 2023-09-05 23:09:18 +10:00
parent cdda99c290
commit beb89b575a
6 changed files with 90 additions and 21 deletions

View File

@ -1,5 +1,8 @@
package org.hl7.fhir.convertors.analytics;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
@ -42,7 +45,8 @@ public class PackageVisitor {
private boolean current;
private IPackageVisitorProcessor processor;
private FilesystemPackageCacheManager pcm;
private PackageClient pc;
private PackageClient pc;
private String cache;
public List<String> getResourceTypes() {
return resourceTypes;
@ -76,6 +80,14 @@ public class PackageVisitor {
public String getCache() {
return cache;
}
public void setCache(String cache) {
this.cache = cache;
}
public void setCorePackages(boolean corePackages) {
this.corePackages = corePackages;
}
@ -109,6 +121,8 @@ public class PackageVisitor {
System.out.println("Finding packages");
pc = new PackageClient(PackageServer.primaryServer());
pcm = new FilesystemPackageCacheManager(org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager.FilesystemPackageCacheMode.USER);
Set<String> pidList = getAllPackages();
Map<String, String> cpidMap = getAllCIPackages();
Set<String> cpidSet = new HashSet<>();
@ -118,7 +132,7 @@ public class PackageVisitor {
processCurrentPackage(s, cpidMap.get(s), cpidSet, i, cpidMap.size());
i++;
}
Set<String> pidList = getAllPackages();
System.out.println("Go: "+pidList.size()+" published packages");
i = 0;
for (String pid : pidList) {
@ -161,11 +175,21 @@ public class PackageVisitor {
private void processCurrentPackage(String url, String pid, Set<String> cpidSet, int i, int t) {
try {
long ms1 = System.currentTimeMillis();
String[] p = url.split("\\/");
String repo = "https://build.fhir.org/ig/"+p[0]+"/"+p[1];
NpmPackage npm = NpmPackage.fromUrl(repo+"/package.tgz");
JsonObject manifest = JsonParser.parseObjectFromUrl(repo+"/package.manifest.json");
File co = new File(Utilities.path(cache, pid+"."+manifest.asString("date")+".tgz"));
if (!co.exists()) {
SimpleHTTPClient fetcher = new SimpleHTTPClient();
HTTPResult res = fetcher.get(repo+"/package.tgz?nocache=" + System.currentTimeMillis());
res.checkThrowException();
TextFile.bytesToFile(res.getContent(), co);
}
NpmPackage npm = NpmPackage.fromPackage(new FileInputStream(co));
String fv = npm.fhirVersion();
cpidSet.add(pid);
long ms2 = System.currentTimeMillis();
if (corePackages || !corePackage(npm)) {
int c = 0;
@ -182,7 +206,7 @@ public class PackageVisitor {
}
}
}
System.out.println("Processed: "+pid+"#current: "+c+" resources ("+i+" of "+t+")");
System.out.println("Processed: "+pid+"#current: "+c+" resources ("+i+" of "+t+", "+(ms2-ms1)+"/"+(System.currentTimeMillis()-ms2)+"ms)");
}
} catch (Exception e) {
System.out.println("Unable to process: "+pid+"#current: "+e.getMessage());

View File

@ -2839,10 +2839,11 @@ public class ProfileUtilities extends TranslatingUtilities {
boolean ok = false;
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder();
String t = ts.getWorkingCode();
String tDesc = ts.toString();
for (TypeRefComponent td : base.getType()) {;
boolean matchType = false;
String tt = td.getWorkingCode();
b.append(tt);
b.append(td.toString());
if (td.hasCode() && (tt.equals(t))) {
matchType = true;
}
@ -2869,20 +2870,7 @@ public class ProfileUtilities extends TranslatingUtilities {
// check that any derived target has a reference chain back to one of the base target profiles
for (UriType u : ts.getTargetProfile()) {
String url = u.getValue();
boolean tgtOk = !td.hasTargetProfile() || td.hasTargetProfile(url);
while (url != null && !tgtOk) {
StructureDefinition sd = context.fetchResource(StructureDefinition.class, url);
if (sd == null) {
if (messages != null) {
messages.add(new ValidationMessage(Source.InstanceValidator, IssueType.BUSINESSRULE, path, "Cannot check whether the target profile " + url + " on "+derived.getPath()+" is valid constraint on the base because it is not known", IssueSeverity.WARNING));
}
url = null;
tgtOk = true; // suppress error message
} else {
url = sd.getBaseDefinition();
tgtOk = td.hasTargetProfile(url);
}
}
boolean tgtOk = !td.hasTargetProfile() || sdConformsToTargets(path, derived.getPath(), url, td);
if (tgtOk) {
ok = true;
} else {
@ -2899,11 +2887,34 @@ public class ProfileUtilities extends TranslatingUtilities {
}
}
if (!ok) {
throw new DefinitionException(context.formatMessage(I18nConstants.STRUCTUREDEFINITION__AT__ILLEGAL_CONSTRAINED_TYPE__FROM__IN_, purl, derived.getPath(), t, b.toString(), srcSD.getUrl()));
throw new DefinitionException(context.formatMessage(I18nConstants.STRUCTUREDEFINITION__AT__ILLEGAL_CONSTRAINED_TYPE__FROM__IN_, purl, derived.getPath(), tDesc, b.toString(), srcSD.getUrl()));
}
}
private boolean sdConformsToTargets(String path, String dPath, String url, TypeRefComponent td) {
if (td.hasTargetProfile(url)) {
return true;
}
StructureDefinition sd = context.fetchResource(StructureDefinition.class, url);
if (sd == null) {
if (messages != null) {
messages.add(new ValidationMessage(Source.InstanceValidator, IssueType.BUSINESSRULE, path, "Cannot check whether the target profile " + url + " on "+dPath+" is valid constraint on the base because it is not known", IssueSeverity.WARNING));
}
return true;
} else {
if (sd.hasBaseDefinition() && sdConformsToTargets(path, dPath, sd.getBaseDefinition(), td)) {
return true;
}
for (Extension ext : sd.getExtensionsByUrl(ToolingExtensions.EXT_SD_IMPOSE_PROFILE)) {
if (sdConformsToTargets(path, dPath, ext.getValueCanonicalType().asStringValue(), td)) {
return true;
}
}
}
return false;
}
private void checkTypeOk(ElementDefinition dest, String ft, StructureDefinition sd, String fieldName) {
boolean ok = false;
Set<String> types = new HashSet<>();

View File

@ -2587,7 +2587,7 @@ public boolean hasTarget() {
res = res + "}";
}
if (hasTargetProfile()) {
res = res + "->(";
res = res + "(";
boolean first = true;
for (CanonicalType s : getTargetProfile()) {
if (first) first = false; else res = res + "|";

View File

@ -647,6 +647,10 @@ public class Utilities {
return PathBuilder.getPathBuilder().buildPath(args);
}
public static File pathFile(String... args) throws IOException {
return new File(PathBuilder.getPathBuilder().buildPath(args));
}
public static String path(File f, String... args) throws IOException {
String[] a = new String[args.length+1];
a[0] = f.getAbsolutePath();

View File

@ -1,6 +1,7 @@
package org.hl7.fhir.utilities.json.parser;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@ -167,6 +168,12 @@ public class JsonParser {
compose(element, stream, false);
}
public static void compose(JsonElement element, File file) throws IOException {
FileOutputStream fo = new FileOutputStream(file);
compose(element, fo, false);
fo.close();
}
public static byte[] composeBytes(JsonElement element) {
return composeBytes(element, false);
}
@ -179,6 +186,12 @@ public class JsonParser {
byte[] cnt = composeBytes(element, pretty);
stream.write(cnt);
}
public static void compose(JsonElement element, File file, boolean pretty) throws IOException {
byte[] cnt = composeBytes(element, pretty);
FileOutputStream fo = new FileOutputStream(file);
fo.write(cnt);
fo.close();
}
public static byte[] composeBytes(JsonElement element, boolean pretty) {
String s = compose(element, pretty);

View File

@ -5,7 +5,9 @@ import java.io.IOException;
import java.text.ParseException;
import java.time.Instant;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.hl7.fhir.utilities.FhirPublication;
import org.hl7.fhir.utilities.TextFile;
@ -67,6 +69,10 @@ public class PackageList {
json.set("date", date);
}
public String name() {
return json.asString("name");
}
public List<String> subPackages() {
List<String> list = new ArrayList<>();
if (json.has("sub-packages")) {
@ -169,6 +175,7 @@ public class PackageList {
}
setDate(date);
}
}
private String source;
@ -334,5 +341,15 @@ public class PackageList {
return json.asString("introduction");
}
public List<PackageListEntry> milestones() {
List<PackageListEntry> list = new ArrayList<>();
for (PackageListEntry t : versions) {
if (t.name() != null) {
list.add(t);
}
}
return list;
}
}