rework type checking on target profiles to support imposesProfile
This commit is contained in:
parent
cdda99c290
commit
beb89b575a
|
@ -1,5 +1,8 @@
|
||||||
package org.hl7.fhir.convertors.analytics;
|
package org.hl7.fhir.convertors.analytics;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -42,7 +45,8 @@ public class PackageVisitor {
|
||||||
private boolean current;
|
private boolean current;
|
||||||
private IPackageVisitorProcessor processor;
|
private IPackageVisitorProcessor processor;
|
||||||
private FilesystemPackageCacheManager pcm;
|
private FilesystemPackageCacheManager pcm;
|
||||||
private PackageClient pc;
|
private PackageClient pc;
|
||||||
|
private String cache;
|
||||||
|
|
||||||
public List<String> getResourceTypes() {
|
public List<String> getResourceTypes() {
|
||||||
return resourceTypes;
|
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) {
|
public void setCorePackages(boolean corePackages) {
|
||||||
this.corePackages = corePackages;
|
this.corePackages = corePackages;
|
||||||
}
|
}
|
||||||
|
@ -109,6 +121,8 @@ public class PackageVisitor {
|
||||||
System.out.println("Finding packages");
|
System.out.println("Finding packages");
|
||||||
pc = new PackageClient(PackageServer.primaryServer());
|
pc = new PackageClient(PackageServer.primaryServer());
|
||||||
pcm = new FilesystemPackageCacheManager(org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager.FilesystemPackageCacheMode.USER);
|
pcm = new FilesystemPackageCacheManager(org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager.FilesystemPackageCacheMode.USER);
|
||||||
|
|
||||||
|
Set<String> pidList = getAllPackages();
|
||||||
|
|
||||||
Map<String, String> cpidMap = getAllCIPackages();
|
Map<String, String> cpidMap = getAllCIPackages();
|
||||||
Set<String> cpidSet = new HashSet<>();
|
Set<String> cpidSet = new HashSet<>();
|
||||||
|
@ -118,7 +132,7 @@ public class PackageVisitor {
|
||||||
processCurrentPackage(s, cpidMap.get(s), cpidSet, i, cpidMap.size());
|
processCurrentPackage(s, cpidMap.get(s), cpidSet, i, cpidMap.size());
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
Set<String> pidList = getAllPackages();
|
|
||||||
System.out.println("Go: "+pidList.size()+" published packages");
|
System.out.println("Go: "+pidList.size()+" published packages");
|
||||||
i = 0;
|
i = 0;
|
||||||
for (String pid : pidList) {
|
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) {
|
private void processCurrentPackage(String url, String pid, Set<String> cpidSet, int i, int t) {
|
||||||
try {
|
try {
|
||||||
|
long ms1 = System.currentTimeMillis();
|
||||||
String[] p = url.split("\\/");
|
String[] p = url.split("\\/");
|
||||||
String repo = "https://build.fhir.org/ig/"+p[0]+"/"+p[1];
|
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();
|
String fv = npm.fhirVersion();
|
||||||
cpidSet.add(pid);
|
cpidSet.add(pid);
|
||||||
|
long ms2 = System.currentTimeMillis();
|
||||||
|
|
||||||
if (corePackages || !corePackage(npm)) {
|
if (corePackages || !corePackage(npm)) {
|
||||||
int c = 0;
|
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) {
|
} catch (Exception e) {
|
||||||
System.out.println("Unable to process: "+pid+"#current: "+e.getMessage());
|
System.out.println("Unable to process: "+pid+"#current: "+e.getMessage());
|
||||||
|
|
|
@ -2839,10 +2839,11 @@ public class ProfileUtilities extends TranslatingUtilities {
|
||||||
boolean ok = false;
|
boolean ok = false;
|
||||||
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder();
|
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder();
|
||||||
String t = ts.getWorkingCode();
|
String t = ts.getWorkingCode();
|
||||||
|
String tDesc = ts.toString();
|
||||||
for (TypeRefComponent td : base.getType()) {;
|
for (TypeRefComponent td : base.getType()) {;
|
||||||
boolean matchType = false;
|
boolean matchType = false;
|
||||||
String tt = td.getWorkingCode();
|
String tt = td.getWorkingCode();
|
||||||
b.append(tt);
|
b.append(td.toString());
|
||||||
if (td.hasCode() && (tt.equals(t))) {
|
if (td.hasCode() && (tt.equals(t))) {
|
||||||
matchType = true;
|
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
|
// check that any derived target has a reference chain back to one of the base target profiles
|
||||||
for (UriType u : ts.getTargetProfile()) {
|
for (UriType u : ts.getTargetProfile()) {
|
||||||
String url = u.getValue();
|
String url = u.getValue();
|
||||||
boolean tgtOk = !td.hasTargetProfile() || td.hasTargetProfile(url);
|
boolean tgtOk = !td.hasTargetProfile() || sdConformsToTargets(path, derived.getPath(), url, td);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (tgtOk) {
|
if (tgtOk) {
|
||||||
ok = true;
|
ok = true;
|
||||||
} else {
|
} else {
|
||||||
|
@ -2899,11 +2887,34 @@ public class ProfileUtilities extends TranslatingUtilities {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!ok) {
|
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) {
|
private void checkTypeOk(ElementDefinition dest, String ft, StructureDefinition sd, String fieldName) {
|
||||||
boolean ok = false;
|
boolean ok = false;
|
||||||
Set<String> types = new HashSet<>();
|
Set<String> types = new HashSet<>();
|
||||||
|
|
|
@ -2587,7 +2587,7 @@ public boolean hasTarget() {
|
||||||
res = res + "}";
|
res = res + "}";
|
||||||
}
|
}
|
||||||
if (hasTargetProfile()) {
|
if (hasTargetProfile()) {
|
||||||
res = res + "->(";
|
res = res + "(";
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
for (CanonicalType s : getTargetProfile()) {
|
for (CanonicalType s : getTargetProfile()) {
|
||||||
if (first) first = false; else res = res + "|";
|
if (first) first = false; else res = res + "|";
|
||||||
|
|
|
@ -647,6 +647,10 @@ public class Utilities {
|
||||||
return PathBuilder.getPathBuilder().buildPath(args);
|
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 {
|
public static String path(File f, String... args) throws IOException {
|
||||||
String[] a = new String[args.length+1];
|
String[] a = new String[args.length+1];
|
||||||
a[0] = f.getAbsolutePath();
|
a[0] = f.getAbsolutePath();
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package org.hl7.fhir.utilities.json.parser;
|
package org.hl7.fhir.utilities.json.parser;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
@ -167,6 +168,12 @@ public class JsonParser {
|
||||||
compose(element, stream, false);
|
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) {
|
public static byte[] composeBytes(JsonElement element) {
|
||||||
return composeBytes(element, false);
|
return composeBytes(element, false);
|
||||||
}
|
}
|
||||||
|
@ -179,6 +186,12 @@ public class JsonParser {
|
||||||
byte[] cnt = composeBytes(element, pretty);
|
byte[] cnt = composeBytes(element, pretty);
|
||||||
stream.write(cnt);
|
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) {
|
public static byte[] composeBytes(JsonElement element, boolean pretty) {
|
||||||
String s = compose(element, pretty);
|
String s = compose(element, pretty);
|
||||||
|
|
|
@ -5,7 +5,9 @@ import java.io.IOException;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.hl7.fhir.utilities.FhirPublication;
|
import org.hl7.fhir.utilities.FhirPublication;
|
||||||
import org.hl7.fhir.utilities.TextFile;
|
import org.hl7.fhir.utilities.TextFile;
|
||||||
|
@ -67,6 +69,10 @@ public class PackageList {
|
||||||
json.set("date", date);
|
json.set("date", date);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String name() {
|
||||||
|
return json.asString("name");
|
||||||
|
}
|
||||||
|
|
||||||
public List<String> subPackages() {
|
public List<String> subPackages() {
|
||||||
List<String> list = new ArrayList<>();
|
List<String> list = new ArrayList<>();
|
||||||
if (json.has("sub-packages")) {
|
if (json.has("sub-packages")) {
|
||||||
|
@ -169,6 +175,7 @@ public class PackageList {
|
||||||
}
|
}
|
||||||
setDate(date);
|
setDate(date);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String source;
|
private String source;
|
||||||
|
@ -334,5 +341,15 @@ public class PackageList {
|
||||||
return json.asString("introduction");
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue