From 888356999e9753e8cb1cbf4b8fb5d9b648ee0009 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Thu, 31 Oct 2019 21:54:10 +1100 Subject: [PATCH] Update to support new packages, new NPM specification --- .../ExtensionDefinitionGenerator.java | 6 +- .../fhir/r4/context/SimpleWorkerContext.java | 9 +- .../fhir/r5/context/SimpleWorkerContext.java | 9 +- .../fhir/r5/test/utils/TestingUtilities.java | 2 +- .../fhir/r5/utils/NPMPackageGenerator.java | 29 +- .../fhir/r5/test/SnapShotGenerationTests.java | 5 +- .../hl7/fhir/utilities/cache/NpmPackage.java | 77 +- .../cache/NpmPackageIndexBuilder.java | 4 + .../utilities/cache/PackageCacheManager.java | 701 ++++++++---------- .../fhir/r4/validation/ValidationEngine.java | 7 +- .../fhir/r5/validation/ValidationEngine.java | 23 +- .../org/hl7/fhir/r5/validation/Validator.java | 26 +- .../tests/ProfileComparisonTests.java | 2 +- .../tests/ValidationEngineTests.java | 14 +- .../validation/tests/ValidationTestSuite.java | 16 +- 15 files changed, 477 insertions(+), 453 deletions(-) diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/ExtensionDefinitionGenerator.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/ExtensionDefinitionGenerator.java index ff4c2a5f2..a029324c0 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/ExtensionDefinitionGenerator.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/ExtensionDefinitionGenerator.java @@ -393,10 +393,8 @@ public class ExtensionDefinitionGenerator { else if (sourceVersion == FHIRVersion._1_0_2) context = SimpleWorkerContext.fromPackage(npm, new R2ToR4Loader()); pu = new ProfileUtilities(context, null, null); - for (String fn : npm.list("package")) { - if (fn.endsWith(".json") && fn.startsWith("StructureDefinition-")) { - list.add((StructureDefinition) loadResource(npm.load("package", fn), sourceVersion)); - } + for (String fn : npm.listResources("StructureDefinition")) { + list.add((StructureDefinition) loadResource(npm.load("package", fn), sourceVersion)); } for (StructureDefinition sd : list) if (sd.getName().equals("Extension")) { diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/context/SimpleWorkerContext.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/context/SimpleWorkerContext.java index 446b803ca..1e90d4611 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/context/SimpleWorkerContext.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/context/SimpleWorkerContext.java @@ -281,13 +281,8 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon public void loadFromPackage(NpmPackage pi, IContextResourceLoader loader, String... types) throws FileNotFoundException, IOException, FHIRException { if (types.length == 0) types = new String[] { "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire","ConceptMap","StructureMap", "NamingSystem"}; - for (String s : pi.list("package")) { - if (s.contains("-") && s.endsWith(".json")) { - String t = s.substring(0, s.indexOf("-")); - if (Utilities.existsInList(t, types)) { - loadDefinitionItem(s, pi.load("package", s), loader); - } - } + for (String s : pi.listResources(types)) { + loadDefinitionItem(s, pi.load("package", s), loader); } version = pi.version(); } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java index afc63a6e1..db9234ab9 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java @@ -286,13 +286,8 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon public void loadFromPackage(NpmPackage pi, IContextResourceLoader loader, String... types) throws FileNotFoundException, IOException, FHIRException { if (types.length == 0) types = new String[] { "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire","ConceptMap","StructureMap", "NamingSystem"}; - for (String s : pi.list("package")) { - if (s.contains("-") && s.endsWith(".json")) { - String t = s.substring(0, s.indexOf("-")); - if (Utilities.existsInList(t, types)) { - loadDefinitionItem(s, pi.load("package", s), loader); - } - } + for (String s : pi.listResources(types)) { + loadDefinitionItem(s, pi.load("package", s), loader); } version = pi.version(); } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/test/utils/TestingUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/test/utils/TestingUtilities.java index 03c0cb26f..b09e054d4 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/test/utils/TestingUtilities.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/test/utils/TestingUtilities.java @@ -69,7 +69,7 @@ public class TestingUtilities { PackageCacheManager pcm; try { pcm = new PackageCacheManager(true, ToolsVersion.TOOLS_VERSION); - fcontext = SimpleWorkerContext.fromPackage(pcm.loadPackage("hl7.fhir.core", "4.0.0")); + fcontext = SimpleWorkerContext.fromPackage(pcm.loadPackage("hl7.fhir.r4.core", "4.0.1")); fcontext.setUcumService(new UcumEssenceService(TestingUtilities.loadTestResourceStream("ucum", "ucum-essence.xml"))); fcontext.setExpansionProfile(new Parameters()); } catch (Exception e) { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/NPMPackageGenerator.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/NPMPackageGenerator.java index 3e24bc987..0f853e6a6 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/NPMPackageGenerator.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/NPMPackageGenerator.java @@ -63,6 +63,7 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonArray; import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; public class NPMPackageGenerator { @@ -177,11 +178,21 @@ public class NPMPackageGenerator { npm.addProperty("title", ig.getTitle()); if (ig.hasDescription()) npm.addProperty("description", ig.getDescription()+ " (built "+dtHuman+timezone()+")"); + JsonArray vl = new JsonArray(); + + npm.add("fhirVersions", vl); + for (String v : fhirVersion) { + vl.add(new JsonPrimitive(v)); + } + if (kind != PackageType.CORE) { JsonObject dep = new JsonObject(); npm.add("dependencies", dep); - for (String v : fhirVersion) { // TODO: fix for multiple versions - dep.addProperty("hl7.fhir.core", v); + for (String v : fhirVersion) { + String vp = packageForVersion(v); + if (vp != null ) { + dep.addProperty(vp, v); + } } for (ImplementationGuideDependsOnComponent d : ig.getDependsOn()) { dep.addProperty(d.getPackageId(), d.getVersion()); @@ -228,6 +239,20 @@ public class NPMPackageGenerator { } + private String packageForVersion(String v) { + if (v == null) + return null; + if (v.startsWith("1.0")) + return "hl7.fhir.r2.core"; + if (v.startsWith("1.4")) + return "hl7.fhir.r2b.core"; + if (v.startsWith("3.0")) + return "hl7.fhir.r3.core"; + if (v.startsWith("4.0")) + return "hl7.fhir.r4.core"; + return null; + } + private String timezone() { TimeZone tz = TimeZone.getDefault(); Calendar cal = GregorianCalendar.getInstance(tz); diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/SnapShotGenerationTests.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/SnapShotGenerationTests.java index 410a9544d..f2ee0eb9c 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/SnapShotGenerationTests.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/SnapShotGenerationTests.java @@ -484,7 +484,10 @@ public class SnapShotGenerationTests { new NarrativeGenerator("", "http://hl7.org/fhir", TestingUtilities.context()).setPkp(new TestPKP()).generate(output, null); test.output = output; TestingUtilities.context().cacheResource(output); - IOUtils.copy(TestingUtilities.loadTestResourceStream("r5", "snapshot-generation", test.getId()+"-expected.xml"), new FileOutputStream(TestingUtilities.tempFile("snapshot", test.getId()+"-expected.xml"))); + File dst = new File(TestingUtilities.tempFile("snapshot", test.getId()+"-expected.xml")); + if (dst.exists()) + dst.delete(); + IOUtils.copy(TestingUtilities.loadTestResourceStream("r5", "snapshot-generation", test.getId()+"-expected.xml"), new FileOutputStream(dst)); new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(TestingUtilities.tempFile("snapshot", test.getId()+"-actual.xml")), output); StructureDefinition t1 = test.expected.copy(); t1.setText(null); 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 dc054ad69..c33664475 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 @@ -71,6 +71,8 @@ import com.google.gson.JsonObject; private Map content = new HashMap(); private JsonObject npm; private IniFile cache; + private Map> types = new HashMap<>(); + private Map urls = new HashMap<>(); public NpmPackage(JsonObject npm, Map content, List folders) { this.path = null; @@ -88,10 +90,30 @@ import com.google.gson.JsonObject; } } npm = (JsonObject) new com.google.gson.JsonParser().parse(TextFile.fileToString(Utilities.path(path, "package", "package.json"))); + File ji = new File(Utilities.path(path, "package", ".index.json")); + if (ji.exists()) { + readIndexFile((JsonObject) new com.google.gson.JsonParser().parse(TextFile.fileToString(ji))); + } cache = new IniFile(Utilities.path(path, "cache.ini")); } } + private void readIndexFile(JsonObject index) throws IOException { + for (JsonElement e : index.getAsJsonArray("files")) { + JsonObject file = (JsonObject) e; + String type = file.get("resourceType").getAsString(); + String name = file.get("filename").getAsString(); + String url = file.has("url") ? file.get("url").getAsString() : null; + String version = file.has("version") ? file.get("version").getAsString() : null; + if (!types.containsKey(type)) + types.put(type, new ArrayList<>()); + types.get(type).add(name); + if (version != null) + url = url + "|" + version; + urls.put(url, name); + } + } + private List sorted(String[] keys) { List names = new ArrayList(); for (String s : keys) @@ -101,7 +123,12 @@ import com.google.gson.JsonObject; } private static final int BUFFER_SIZE = 1024; + public static NpmPackage fromPackage(InputStream tgz) throws IOException { + return fromPackage(tgz, false); + } + + public static NpmPackage fromPackage(InputStream tgz, boolean progress) throws IOException { NpmPackage res = new NpmPackage(null); GzipCompressorInputStream gzipIn = new GzipCompressorInputStream(tgz); try (TarArchiveInputStream tarIn = new TarArchiveInputStream(gzipIn)) { @@ -126,6 +153,16 @@ import com.google.gson.JsonObject; fos.close(); res.content.put(entry.getName(), fos.toByteArray()); } + i++; + if (progress && i % 50 == 0) { + c++; + System.out.print("."); + if (c == 120) { + System.out.println(""); + System.out.print(" "); + c = 2; + } + } } } res.npm = JsonTrackingParser.parseJson(res.content.get("package/package.json")); @@ -159,6 +196,8 @@ import com.google.gson.JsonObject; } zip.close(); res.npm = (JsonObject) new com.google.gson.JsonParser().parse(new String(res.content.get("package/package.json"))); + if (res.content.containsKey("package/.index.json")) + res.readIndexFile((JsonObject) new com.google.gson.JsonParser().parse(new String(res.content.get("package/.index.json")))); return res; } @@ -187,12 +226,19 @@ import com.google.gson.JsonObject; } public List listResources(String... types) throws IOException { - List files = list("package"); List res = new ArrayList(); - for (String s : files) { - String[] n = s.split("\\-"); - if (Utilities.existsInList(n[0], types)) - res.add(s); + if (this.types.size() > 0) { + for (String s : types) { + if (this.types.containsKey(s)) + res.addAll(this.types.get(s)); + } + } else { + List files = list("package"); + for (String s : files) { + String[] n = s.split("\\-"); + if (Utilities.existsInList(n[0], types)) + res.add(s); + } } return res; } @@ -295,18 +341,25 @@ import com.google.gson.JsonObject; public String fhirVersion() { if ("hl7.fhir.core".equals(npm.get("name").getAsString())) return npm.get("version").getAsString(); + else if (npm.get("name").getAsString().startsWith("hl7.fhir.r2.") || npm.get("name").getAsString().startsWith("hl7.fhir.r2b.") || npm.get("name").getAsString().startsWith("hl7.fhir.r3.") || npm.get("name").getAsString().startsWith("hl7.fhir.r4.")) + return npm.get("version").getAsString(); else { JsonObject dep = npm.getAsJsonObject("dependencies"); if (dep == null) throw new FHIRException("no dependencies found in the Package definition"); - JsonElement core = dep.get("hl7.fhir.core"); - if (core == null) - throw new FHIRException("no dependency on hl7.fhir.core found in the Package definition"); - return core.getAsString(); + for (Entry e : dep.entrySet()) { + if (Utilities.existsInList(e.getKey(), "hl7.fhir.r2.core", "hl7.fhir.r2b.core", "hl7.fhir.r3.core", "hl7.fhir.r4.core")) + return e.getValue().getAsString(); + if (Utilities.existsInList(e.getKey(), "hl7.fhir.core")) // while all packages are updated + return e.getValue().getAsString(); + } + if (npm.has("fhirVersions")) + return npm.getAsJsonArray("fhirVersions").get(0).getAsString(); + throw new FHIRException("no core dependency or FHIR Version found in the Package definition"); } } - public String description() { + public String summary() { if (path != null) return path; else @@ -321,6 +374,10 @@ import com.google.gson.JsonObject; return npm.get("type").getAsString(); } + public String description() { + return npm.has("description") ? npm.get("description").getAsString() : null; + } + public String getPath() { return path; } diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/NpmPackageIndexBuilder.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/NpmPackageIndexBuilder.java index 9d7ddf217..1523fa583 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/NpmPackageIndexBuilder.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/NpmPackageIndexBuilder.java @@ -127,6 +127,10 @@ public class NpmPackageIndexBuilder { new NpmPackageIndexBuilder().executeWithStatus("C:\\work\\org.hl7.fhir\\packages\\fhir.tx.support\\fhir.tx.support.r2"); new NpmPackageIndexBuilder().executeWithStatus("C:\\work\\org.hl7.fhir\\packages\\fhir.tx.support\\fhir.tx.support.r3"); new NpmPackageIndexBuilder().executeWithStatus("C:\\work\\org.hl7.fhir\\packages\\fhir.tx.support\\fhir.tx.support.r4"); + new NpmPackageIndexBuilder().executeWithStatus("C:\\work\\org.hl7.fhir\\packages\\hl7.fhir.rX\\hl7.fhir.core#1.0.2"); + new NpmPackageIndexBuilder().executeWithStatus("C:\\work\\org.hl7.fhir\\packages\\hl7.fhir.rX\\hl7.fhir.core#1.4.0"); + new NpmPackageIndexBuilder().executeWithStatus("C:\\work\\org.hl7.fhir\\packages\\hl7.fhir.rX\\hl7.fhir.core#3.0.2"); + new NpmPackageIndexBuilder().executeWithStatus("C:\\work\\org.hl7.fhir\\packages\\hl7.fhir.rX\\hl7.fhir.core#4.0.1"); } } diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/PackageCacheManager.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/PackageCacheManager.java index 945164eb8..5fe50c814 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/PackageCacheManager.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/PackageCacheManager.java @@ -37,6 +37,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import org.apache.commons.compress.archivers.tar.TarArchiveEntry; import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; @@ -106,7 +107,7 @@ public class PackageCacheManager { public static final String PACKAGE_VERSION_REGEX = "^[a-z][a-z0-9\\_\\-]*(\\.[a-z0-9\\_\\-]+)+\\#[a-z0-9\\-\\_]+(\\.[a-z0-9\\-\\_]+)*$"; private static final int BUFFER_SIZE = 1024; - private static final String CACHE_VERSION = "2"; // second version - see wiki page + private static final String CACHE_VERSION = "3"; // second version - see wiki page private static final int ANALYSIS_VERSION = 2; private String cacheFolder; @@ -129,19 +130,172 @@ public class PackageCacheManager { TextFile.stringToFile("[cache]\r\nversion="+CACHE_VERSION+"\r\n\r\n[urls]\r\n\r\n[local]\r\n\r\n", Utilities.path(cacheFolder, "packages.ini"), false); IniFile ini = new IniFile(Utilities.path(cacheFolder, "packages.ini")); boolean save = false; - String v = ini.getStringProperty("cache", "version"); - if ("1".equals(v)) { - convertPackageCacheFrom1To2(); - ini.setStringProperty("cache", "version", "2", null); - v = ini.getStringProperty("cache", "version"); - save = true; - } + String v = ini.getStringProperty("cache", "version"); if (!CACHE_VERSION.equals(v)) { clearCache(); ini.setStringProperty("cache", "version", CACHE_VERSION, null); save = true; } + save = initUrlMaps(ini, save); + if (save) { + if (!CACHE_VERSION.equals(ini.getStringProperty("cache", "version"))) { + throw new Error("what?"); + } + ini.save(); + } + } + + public static String userDir() throws IOException { + return Utilities.path(System.getProperty("user.home"), ".fhir", "packages"); + } + + // ========================= Utilities ============================================================================ + + private List sorted(String[] keys) { + List names = new ArrayList(); + for (String s : keys) + names.add(s); + Collections.sort(names); + return names; + } + + private NpmPackage loadPackageInfo(String path) throws IOException { + NpmPackage pi = new NpmPackage(path); + return pi; + } + + public String getFolder() { + return cacheFolder; + } + + private void analysePackage(String dir) throws IOException { + NpmPackageIndexBuilder indexer = new NpmPackageIndexBuilder(); + indexer.start(); + int i = 0; + int c = 0; + File[] packages = new File(Utilities.path(dir, "package")).listFiles(); + for (File f : packages) { + indexer.seeFile(f.getName(), TextFile.fileToBytes(f)); + i++; + if (progress && i % 50 == 0) { + c++; + System.out.print("."); + if (c == 120) { + System.out.println(""); + System.out.print(" "); + c = 2; + } + } + } + TextFile.stringToFile(indexer.build(), Utilities.path(dir, "package", ".index.json")); + } + + + + private NpmPackage checkCurrency(String id, NpmPackage p) { + // special case: current versions roll over, and we have to check their currency + try { + String url = ciList.get(id); + JsonObject json = fetchJson(Utilities.pathURL(url, "package.manifest.json")); + String currDate = json.get("date").getAsString(); + String packDate = p.date(); + if (!currDate.equals(packDate)) + return null; // nup, we need a new copy + return p; + } catch (Exception e) { + return p; + } + } + + private JsonObject fetchJson(String source) throws IOException { + URL url = new URL(source); + URLConnection c = url.openConnection(); + return (JsonObject) new com.google.gson.JsonParser().parse(TextFile.streamToString(c.getInputStream())); + } + + private InputStream fetchFromUrlSpecific(String source, boolean optional) throws FHIRException { + try { + URL url = new URL(source); + URLConnection c = url.openConnection(); + return c.getInputStream(); + } catch (Exception e) { + if (optional) + return null; + else + throw new FHIRException(e.getMessage(), e); + } + } + + // ========================= Full Cache Management ============================================================================ + + private void clearCache() throws IOException { + for (File f : new File(cacheFolder).listFiles()) { + if (f.isDirectory()) + FileUtils.deleteDirectory(f); + else if (!f.getName().equals("packages.ini")) + FileUtils.forceDelete(f); + } + IniFile ini = new IniFile(Utilities.path(cacheFolder, "packages.ini")); + ini.removeSection("packages"); + ini.save(); + } + +// private void checkDeleteVersion(String id, String ver, int minVer) { +// if (hasPackage(id, ver)) { +// boolean del = true; +// NpmPackage pck; +// try { +// pck = loadPackageFromCacheOnly(id, ver); +// if (pck.getNpm().has("tools-version")) { +// del = pck.getNpm().get("tools-version").getAsInt() < minVer; +// } +// } catch (Exception e) { +// } +// if (del) +// try { +// removePackage(id, ver); +// } catch (IOException e) { +// } +// } +// } + +//private void convertPackageCacheFrom1To2() throws IOException { +//for (File f : new File(cacheFolder).listFiles()) { +// if (f.isDirectory() && f.getName().contains("-")) { +// String s = f.getName(); +// int i = s.lastIndexOf("-"); +// s = s.substring(0, i)+"#"+s.substring(i+1); +// File nf = new File(Utilities.path(cacheFolder, s)); +// if (!f.renameTo(nf)) +// throw new IOException("Unable to rename "+f.getAbsolutePath()+" to "+nf.getAbsolutePath()); +// } +//} +//} + + // ========================= URL maps (while waiting for package registry) ============================================================================ + + public boolean initUrlMaps(IniFile ini, boolean save) { save = checkIniHasMapping("hl7.fhir.core", "http://hl7.org/fhir", ini) || save; + + save = checkIniHasMapping("hl7.fhir.r2.core", "http://hl7.org/fhir/DSTU2/hl7.fhir.r2.core.tgz", ini) || save; + save = checkIniHasMapping("hl7.fhir.r2.examples", "http://hl7.org/fhir/DSTU2/hl7.fhir.r2.examples.tgz", ini) || save; + save = checkIniHasMapping("hl7.fhir.r2.elements", "http://hl7.org/fhir/DSTU2/hl7.fhir.r2.elements.tgz", ini) || save; + save = checkIniHasMapping("hl7.fhir.r2.expansions", "http://hl7.org/fhir/DSTU2/hl7.fhir.r2.expansions.tgz", ini) || save; + save = checkIniHasMapping("hl7.fhir.r2b.core", "http://hl7.org/fhir/2016May/hl7.fhir.r2b.core.tgz", ini) || save; + save = checkIniHasMapping("hl7.fhir.r2b.examples", "http://hl7.org/fhir/2016May/hl7.fhir.r2b.examples.tgz", ini) || save; + save = checkIniHasMapping("hl7.fhir.r2b.elements", "http://hl7.org/fhir/2016May/hl7.fhir.r2b.elements.tgz", ini) || save; + save = checkIniHasMapping("hl7.fhir.r2b.expansions", "http://hl7.org/fhir/2016May/hl7.fhir.r2b.expansions.tgz", ini) || save; + save = checkIniHasMapping("hl7.fhir.r3.core", "http://hl7.org/fhir/STU3/hl7.fhir.r3.core.tgz", ini) || save; + save = checkIniHasMapping("hl7.fhir.r3.examples", "http://hl7.org/fhir/STU3/hl7.fhir.r3.examples.tgz", ini) || save; + save = checkIniHasMapping("hl7.fhir.r3.elements", "http://hl7.org/fhir/STU3/hl7.fhir.r3.elements.tgz", ini) || save; + save = checkIniHasMapping("hl7.fhir.r3.expansions", "http://hl7.org/fhir/STU3/hl7.fhir.r3.expansions.tgz", ini) || save; + save = checkIniHasMapping("hl7.fhir.r4.core", "http://hl7.org/fhir/R4/hl7.fhir.r4.core.tgz", ini) || save; + save = checkIniHasMapping("hl7.fhir.r4.examples", "http://hl7.org/fhir/R4/hl7.fhir.r4.examples.tgz", ini) || save; + save = checkIniHasMapping("hl7.fhir.r4.elements", "http://hl7.org/fhir/R4/hl7.fhir.r4.elements.tgz", ini) || save; + save = checkIniHasMapping("hl7.fhir.r4.expansions", "http://hl7.org/fhir/R4/hl7.fhir.r4.expansions.tgz", ini) || save; + + save = checkIniHasMapping("hl7.fhir.r5.core", "http://build.fhir.org/package.tgz", ini) || save; + save = checkIniHasMapping("fhir.argonaut.ehr", "http://fhir.org/guides/argonaut", ini) || save; save = checkIniHasMapping("fhir.argonaut.pd", "http://fhir.org/guides/argonaut-pd", ini) || save; save = checkIniHasMapping("fhir.argonaut.scheduling", "http://fhir.org/guides/argonaut-scheduling", ini) || save; @@ -172,59 +326,8 @@ public class PackageCacheManager { save = checkIniHasMapping("hl7.fhir.uv.vhdir", "http://hl7.org/fhir/ig/vhdir", ini) || save; save = checkIniHasMapping("hl7.fhir.vn.base", "http://hl7.org/fhir/ig/vietnam", ini) || save; save = checkIniHasMapping("hl7.fhir.vocabpoc", "http://hl7.org/fhir/ig/vocab-poc", ini) || save; - if (save) { - if (!CACHE_VERSION.equals(ini.getStringProperty("cache", "version"))) { - throw new Error("what?"); - } - ini.save(); - } - checkDeleteVersion("hl7.fhir.core", "1.0.2", 2); - checkDeleteVersion("hl7.fhir.core", "1.4.0", 2); - checkDeleteVersion("hl7.fhir.core", "current", toolsVersion); - checkDeleteVersion("hl7.fhir.core", "4.0.0", toolsVersion); + return save; } - - - private void checkDeleteVersion(String id, String ver, int minVer) { - if (hasPackage(id, ver)) { - boolean del = true; - NpmPackage pck; - try { - pck = loadPackageFromCacheOnly(id, ver); - if (pck.getNpm().has("tools-version")) { - del = pck.getNpm().get("tools-version").getAsInt() < minVer; - } - } catch (Exception e) { - } - if (del) - try { - removePackage(id, ver); - } catch (IOException e) { - } - } - } - - - public void removePackage(String id, String ver) throws IOException { - String f = Utilities.path(cacheFolder, id+"#"+ver); - Utilities.clearDirectory(f); - new File(f).delete(); - } - - - private void convertPackageCacheFrom1To2() throws IOException { - for (File f : new File(cacheFolder).listFiles()) { - if (f.isDirectory() && f.getName().contains("-")) { - String s = f.getName(); - int i = s.lastIndexOf("-"); - s = s.substring(0, i)+"#"+s.substring(i+1); - File nf = new File(Utilities.path(cacheFolder, s)); - if (!f.renameTo(nf)) - throw new IOException("Unable to rename "+f.getAbsolutePath()+" to "+nf.getAbsolutePath()); - } - } - } - private boolean checkIniHasMapping(String pid, String curl, IniFile ini) { if (curl.equals(ini.getStringProperty("urls", pid))) @@ -233,17 +336,6 @@ public class PackageCacheManager { return true; } - - private void clearCache() throws IOException { - for (File f : new File(cacheFolder).listFiles()) { - if (f.isDirectory()) - FileUtils.deleteDirectory(f); - else if (!f.getName().equals("packages.ini")) - FileUtils.forceDelete(f); - } - } - - public void recordMap(String url, String id) throws IOException { if (url == null) return; @@ -280,12 +372,89 @@ public class PackageCacheManager { return null; } - private List sorted(String[] keys) { - List names = new ArrayList(); - for (String s : keys) - names.add(s); - Collections.sort(names); - return names; + public JsonArray loadFromBuildServer() throws IOException { + buildLoaded = true; // whether it succeeds or not + URL url = new URL("https://build.fhir.org/ig/qas.json?nocache=" + System.currentTimeMillis()); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("GET"); + InputStream json = connection.getInputStream(); + buildInfo = (JsonArray) new com.google.gson.JsonParser().parse(TextFile.streamToString(json)); + + for (JsonElement n : buildInfo) { + JsonObject o = (JsonObject) n; + if (o.has("url") && o.has("package-id") && o.get("package-id").getAsString().contains(".")) { + String u = o.get("url").getAsString(); + if (u.contains("/ImplementationGuide/")) + u = u.substring(0, u.indexOf("/ImplementationGuide/")); + recordMap(u, o.get("package-id").getAsString()); + ciList.put(o.get("package-id").getAsString(), "https://build.fhir.org/ig/"+o.get("repo").getAsString()); + } + } + return buildInfo; + } + + public boolean isBuildLoaded() { + return buildLoaded; + } + + + public String buildPath(String url) { + for (JsonElement e : buildInfo) { + JsonObject j = (JsonObject) e; + if (j.has("url") && (url.equals(j.get("url").getAsString()) || j.get("url").getAsString().startsWith(url+"/ImplementationGuide"))) { + return "https://build.fhir.org/ig/"+j.get("repo").getAsString(); + } + } + return null; + } + + public boolean checkBuildLoaded() throws IOException { + if (isBuildLoaded()) + return true; + loadFromBuildServer(); + return false; + } + + public Map getCiList() { + return ciList; + } + + public List getUrls() throws IOException { + if (allUrls == null) + { + IniFile ini = new IniFile(Utilities.path(cacheFolder, "packages.ini")); + allUrls = new ArrayList<>(); + for (String s : ini.getPropertyNames("urls")) + allUrls.add(ini.getStringProperty("urls", s)); + try { + URL url = new URL("https://raw.githubusercontent.com/FHIR/ig-registry/master/fhir-ig-list.json?nocache=" + System.currentTimeMillis()); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("GET"); + InputStream json = connection.getInputStream(); + JsonObject packages = (JsonObject) new com.google.gson.JsonParser().parse(TextFile.streamToString(json)); + JsonArray guides = packages.getAsJsonArray("guides"); + for (JsonElement g : guides) { + JsonObject gi = (JsonObject) g; + if (gi.has("canonical")) + if (!allUrls.contains(gi.get("canonical").getAsString())) + allUrls.add(gi.get("canonical").getAsString()); + } + } catch (Exception e) { + System.out.println("Listing known Implementation Guides failed: "+e.getMessage()); + } + } + return allUrls; + } + + // ========================= Package API ============================================================================ + + public void removePackage(String id, String ver) throws IOException { + String f = Utilities.path(cacheFolder, id+"#"+ver); + Utilities.clearDirectory(f); + IniFile ini = new IniFile(Utilities.path(cacheFolder, "packages.ini")); + ini.removeProperty("packages", id+"#"+ver); + ini.save(); + new File(f).delete(); } /** @@ -295,7 +464,6 @@ public class PackageCacheManager { * @throws IOException */ public NpmPackage loadPackageFromCacheOnly(String id) throws IOException { - String match = null; List l = sorted(new File(cacheFolder).list()); for (int i = l.size()-1; i >= 0; i--) { String f = l.get(i); @@ -321,7 +489,6 @@ public class PackageCacheManager { if (p.name().equals(id) && ("current".equals(version) || "dev".equals(version) || p.version().equals(version))) return p; } - String match = null; for (String f : sorted(new File(cacheFolder).list())) { if (f.equals(id+"#"+version)) { return loadPackageInfo(Utilities.path(cacheFolder, f)); @@ -332,130 +499,49 @@ public class PackageCacheManager { else return null; } - - private NpmPackage loadPackageInfo(String path) throws IOException { - NpmPackage pi = new NpmPackage(path); - return pi; - } + /** + * Add an already fetched package to the cache + */ public NpmPackage addPackageToCache(String id, String version, InputStream tgz) throws IOException { if (progress ) { System.out.println("Installing "+id+"#"+(version == null ? "?" : version)+" to the package cache"); System.out.print(" Fetching:"); } - List files = new ArrayList(); - long size = unPackage(tgz, files); - - byte[] npmb = null; - for (PackageEntry e : files) { - if (e.name.equals("package/package.json")) - npmb = e.bytes; - } - if (npmb == null) - throw new IOException("Unable to find package/package.json in the package file"); + NpmPackage npm = NpmPackage.fromPackage(tgz, true); if (progress ) System.out.print("|"); - JsonObject npm = (JsonObject) new com.google.gson.JsonParser().parse(TextFile.bytesToString(npmb)); - if (npm.get("name") == null || id == null || !id.equals(npm.get("name").getAsString())) - // work around for stupid core-r4 problem - if (!npm.get("name").getAsString().startsWith(id)) - throw new IOException("Attempt to import a mis-identified package. Expected "+id+", got "+npm.get("name").getAsString()); + if (npm.name() == null || id == null || !id.equals(npm.name())) { + if (!id.equals("hl7.fhir.r5.core")) {// temporary work around + throw new IOException("Attempt to import a mis-identified package. Expected "+id+", got "+npm.name()); + } + } if (version == null) - version = npm.get("version").getAsString(); + version = npm.version(); String packRoot = Utilities.path(cacheFolder, id+"#"+version); Utilities.createDirectory(packRoot); Utilities.clearDirectory(packRoot); - for (PackageEntry e : files) { - if (e.bytes == null) { - File f = new File(Utilities.path(packRoot, e.name)); - if (!f.mkdir()) - throw new IOException("Unable to create directory '%s', during extraction of archive contents: "+ f.getAbsolutePath()); - } else { - String fn = Utilities.path(packRoot, e.name); - String dir = Utilities.getDirectoryForFile(fn); - if (!(new File(dir).exists())) - Utilities.createDirectory(dir); - TextFile.bytesToFile(e.bytes, fn); - } - } - if (progress) { - System.out.println(""); - System.out.print(" Analysing"); - } - - Map profiles = new HashMap(); - Map canonicals = new HashMap(); - if ("hl7.fhir.core".equals(npm.get("name").getAsString())) - analysePackage(packRoot, npm.get("version").getAsString(), profiles, canonicals); - else if (npm.has("dependencies")) // templates do not - analysePackage(packRoot, npm.getAsJsonObject("dependencies").get("hl7.fhir.core").getAsString(), profiles, canonicals); - IniFile ini = new IniFile(Utilities.path(packRoot, "cache.ini")); - ini.setTimeStampFormat("dd/MM/yyyy h:mm:ss a"); - ini.setLongProperty("Package", "size", size, null); - ini.setTimestampProperty("Package", "install", Timestamp.from(Instant.now()), null); - for (String p : profiles.keySet()) - ini.setStringProperty("Profiles", p, profiles.get(p), null); - for (String p : canonicals.keySet()) - ini.setStringProperty("Canonicals", p, canonicals.get(p), null); - ini.setIntegerProperty("Packages", "analysis", ANALYSIS_VERSION, null); - ini.save(); - if (progress ) - System.out.println(" done."); - return loadPackageInfo(packRoot); - } - - - public long unPackage(InputStream tgz, List files) throws IOException { - long size = 0; - GzipCompressorInputStream gzipIn = new GzipCompressorInputStream(tgz); - try (TarArchiveInputStream tarIn = new TarArchiveInputStream(gzipIn)) { - TarArchiveEntry entry; - - int i = 0; - int c = 12; - while ((entry = (TarArchiveEntry) tarIn.getNextEntry()) != null) { - i++; - if (progress && i % 20 == 0) { - c++; - System.out.print("."); - if (c == 120) { - System.out.println(""); - System.out.print(" "); - c = 2; - } - } - if (entry.isDirectory()) { - files.add(new PackageEntry(entry.getName())); - } else { - int count; - byte data[] = new byte[BUFFER_SIZE]; - - ByteArrayOutputStream fos = new ByteArrayOutputStream(); - try (BufferedOutputStream dest = new BufferedOutputStream(fos, BUFFER_SIZE)) { - while ((count = tarIn.read(data, 0, BUFFER_SIZE)) != -1) { - dest.write(data, 0, count); - } - } - fos.close(); - files.add(new PackageEntry(entry.getName(), fos.toByteArray())); - size = size + fos.size(); - } - } - } - return size; - } - - private void analysePackage(String dir, String v, Map profiles, Map canonicals) throws IOException { int i = 0; - int c = 11; - File[] packages = new File(Utilities.path(dir, "package")).listFiles(); - for (File f : packages) { + int c = 0; + for (Entry e : npm.getContent().entrySet()) { +// if (e.getValue() == null) { +// thorw +// File f = new File(Utilities.path(packRoot, e.name)); +// if (!f.mkdir()) +// throw new IOException("Unable to create directory '%s', during extraction of archive contents: "+ f.getAbsolutePath()); +// } else { + String fn = Utilities.path(packRoot, e.getKey()); + String dir = Utilities.getDirectoryForFile(fn); + if (!(new File(dir).exists())) + Utilities.createDirectory(dir); + TextFile.bytesToFile(e.getValue(), fn); +// } i++; - if (progress && i % 20 == 0) { + if (progress && i % 50 == 0) { c++; System.out.print("."); if (c == 120) { @@ -464,117 +550,26 @@ public class PackageCacheManager { c = 2; } } - if (!f.getName().startsWith("Bundle-")) { - try { - JsonObject j = (JsonObject) new com.google.gson.JsonParser().parse(TextFile.fileToString(f)); - if (!Utilities.noString(j.get("url").getAsString()) && !Utilities.noString(j.get("resourceType").getAsString())) - canonicals.put(j.get("url").getAsString(), f.getName()); - if ("StructureDefinition".equals(j.get("resourceType").getAsString()) && "resource".equals(j.get("kind").getAsString())) { - String bd = null; - if ("1.0.2".equals(v)) - bd = j.get("constrainedType").getAsString(); - else - bd = j.get("type").getAsString(); - if (Utilities.noString(bd)) - bd = j.get("name").getAsString(); - if (!"Extension".equals(bd)) - profiles.put(j.get("url").getAsString(), bd); - } - } catch (Exception e) { - // nothing - } - } } - } - - public NpmPackage extractLocally(String filename) throws IOException { - return extractLocally(new FileInputStream(filename), filename); - } - - public NpmPackage extractLocally(InputStream tgz, String name) throws IOException { - if (progress ) { - System.out.println("Loading "+name+" to the package cache"); - System.out.print(" Fetching:"); - } - List files = new ArrayList(); + if (progress) { + System.out.println(""); + System.out.print(" Analysing"); + } - unPackage(tgz, files); + analysePackage(packRoot); // do this whether there's an index.json or not. - byte[] npmb = null; - for (PackageEntry e : files) { - if (e.name.equals("package/package.json")) - npmb = e.bytes; - } - if (npmb == null) - throw new IOException("Unable to find package/package.json in the package file"); - - JsonObject npm = (JsonObject) new com.google.gson.JsonParser().parse(TextFile.bytesToString(npmb)); + IniFile ini = new IniFile(Utilities.path(cacheFolder, "packages.ini")); + ini.setTimeStampFormat("yyyyMMddhhmmss"); + ini.setTimestampProperty("packages", id+"#"+version, Timestamp.from(Instant.now()), null); + ini.save(); + if (progress) + System.out.println(" done."); - Map content = new HashMap(); - List folders = new ArrayList(); - - for (PackageEntry e : files) { - if (e.bytes == null) { - folders.add(e.name); - } else { - content.put(e.name, e.bytes); - } - } - System.out.println(" done."); - NpmPackage p = new NpmPackage(npm, content, folders); - recordMap(p.canonical(), p.name()); - return p; + //todo: load dependencies + NpmPackage pck = loadPackageInfo(packRoot); + return pck; } - public String getFolder() { - return cacheFolder; - } - - - public JsonArray loadFromBuildServer() throws IOException { - buildLoaded = true; // whether it succeeds or not - URL url = new URL("https://build.fhir.org/ig/qas.json?nocache=" + System.currentTimeMillis()); - HttpURLConnection connection = (HttpURLConnection) url.openConnection(); - connection.setRequestMethod("GET"); - InputStream json = connection.getInputStream(); - buildInfo = (JsonArray) new com.google.gson.JsonParser().parse(TextFile.streamToString(json)); - - for (JsonElement n : buildInfo) { - JsonObject o = (JsonObject) n; - if (o.has("url") && o.has("package-id") && o.get("package-id").getAsString().contains(".")) { - String u = o.get("url").getAsString(); - if (u.contains("/ImplementationGuide/")) - u = u.substring(0, u.indexOf("/ImplementationGuide/")); - recordMap(u, o.get("package-id").getAsString()); - ciList.put(o.get("package-id").getAsString(), "https://build.fhir.org/ig/"+o.get("repo").getAsString()); - } - } - return buildInfo; - } - - - public boolean isBuildLoaded() { - return buildLoaded; - } - - - public String buildPath(String url) { - for (JsonElement e : buildInfo) { - JsonObject j = (JsonObject) e; - if (j.has("url") && (url.equals(j.get("url").getAsString()) || j.get("url").getAsString().startsWith(url+"/ImplementationGuide"))) { - return "https://build.fhir.org/ig/"+j.get("repo").getAsString(); - } - } - return null; - } - - public boolean checkBuildLoaded() throws IOException { - if (isBuildLoaded()) - return true; - loadFromBuildServer(); - return false; - } - public NpmPackage loadPackage(String id) throws FHIRException, IOException { throw new Error("Not done yet"); } @@ -600,6 +595,12 @@ public class PackageCacheManager { String url = getPackageUrl(id); if (url == null) throw new FHIRException("Unable to resolve the package '"+id+"'"); + if (url.contains(".tgz")) { + InputStream stream = fetchFromUrlSpecific(url, true); + if (stream != null) + return addPackageToCache(id, v, stream); + throw new FHIRException("Unable to find the package source for '"+id+"' at "+url); + } if (v == null) { InputStream stream = fetchFromUrlSpecific(Utilities.pathURL(url, "package.tgz"), true); if (stream == null && isBuildLoaded()) { @@ -642,62 +643,21 @@ public class PackageCacheManager { } - private NpmPackage checkCurrency(String id, NpmPackage p) { - // special case: current versions roll over, and we have to check their currency - try { - String url = ciList.get(id); - JsonObject json = fetchJson(Utilities.pathURL(url, "package.manifest.json")); - String currDate = json.get("date").getAsString(); - String packDate = p.date(); - if (!currDate.equals(packDate)) - return null; // nup, we need a new copy - return p; - } catch (Exception e) { - return p; - } - } - - -// !!! -// if (packageId != null) { -// return loadPackage(); -// } else -// return loadPackage(pcm.extractLocally(stream)); - - - private JsonObject fetchJson(String source) throws IOException { - URL url = new URL(source); - URLConnection c = url.openConnection(); - return (JsonObject) new com.google.gson.JsonParser().parse(TextFile.streamToString(c.getInputStream())); - } - - private InputStream fetchFromUrlSpecific(String source, boolean optional) throws FHIRException { - try { - URL url = new URL(source); - URLConnection c = url.openConnection(); - return c.getInputStream(); - } catch (Exception e) { - if (optional) - return null; - else - throw new FHIRException(e.getMessage(), e); - } - } - - - public void loadFromFolder(String packagesFolder) throws IOException { - for (File f : new File(packagesFolder).listFiles()) { - if (f.getName().endsWith(".tgz")) { - temporaryPackages.add(extractLocally(new FileInputStream(f), f.getName())); - } - } - } - - public Map getCiList() { - return ciList; - } - +// public void loadFromFolder(String packagesFolder) throws IOException { +// for (File f : new File(packagesFolder).listFiles()) { +// if (f.getName().endsWith(".tgz")) { +// temporaryPackages.add(extractLocally(new FileInputStream(f), f.getName())); +// } +// } +// } +// + /** + * turn true if a package exists + * @param id + * @param version + * @return + */ public boolean hasPackage(String id, String version) { for (NpmPackage p : temporaryPackages) { if (p.name().equals(id) && ("current".equals(version) || "dev".equals(version) || p.version().equals(version))) @@ -715,33 +675,13 @@ public class PackageCacheManager { } - public List getUrls() throws IOException { - if (allUrls == null) - { - IniFile ini = new IniFile(Utilities.path(cacheFolder, "packages.ini")); - allUrls = new ArrayList<>(); - for (String s : ini.getPropertyNames("urls")) - allUrls.add(ini.getStringProperty("urls", s)); - try { - URL url = new URL("https://raw.githubusercontent.com/FHIR/ig-registry/master/fhir-ig-list.json?nocache=" + System.currentTimeMillis()); - HttpURLConnection connection = (HttpURLConnection) url.openConnection(); - connection.setRequestMethod("GET"); - InputStream json = connection.getInputStream(); - JsonObject packages = (JsonObject) new com.google.gson.JsonParser().parse(TextFile.streamToString(json)); - JsonArray guides = packages.getAsJsonArray("guides"); - for (JsonElement g : guides) { - JsonObject gi = (JsonObject) g; - if (gi.has("canonical")) - if (!allUrls.contains(gi.get("canonical").getAsString())) - allUrls.add(gi.get("canonical").getAsString()); - } - } catch (Exception e) { - System.out.println("Listing known Implementation Guides failed: "+e.getMessage()); - } - } - return allUrls; - } - + /** + * List which versions of a package are available + * + * @param url + * @return + * @throws IOException + */ public VersionHistory listVersions(String url) throws IOException { if (historyCache.containsKey(url)) @@ -767,18 +707,13 @@ public class PackageCacheManager { } + /** + * Clear the cache + * + * @throws IOException + */ public void clear() throws IOException { - for (File f : new File(cacheFolder).listFiles()) { - if (f.isDirectory()) { - Utilities.clearDirectory(f.getAbsolutePath()); - f.delete(); - } - } - } - - - public static String userDir() throws IOException { - return Utilities.path(System.getProperty("user.home"), ".fhir", "packages"); + clearCache(); } } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/r4/validation/ValidationEngine.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/r4/validation/ValidationEngine.java index bcd3914dd..0a2da0f93 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/r4/validation/ValidationEngine.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/r4/validation/ValidationEngine.java @@ -505,14 +505,13 @@ public class ValidationEngine { } private Map loadPackage(InputStream stream, String name) throws FileNotFoundException, IOException { - return loadPackage(pcm.extractLocally(stream, name)); + return loadPackage(NpmPackage.fromPackage(stream)); } public Map loadPackage(NpmPackage pi) throws IOException { Map res = new HashMap(); - for (String s : pi.list("package")) { - if (s.startsWith("CodeSystem-") || s.startsWith("ConceptMap-") || s.startsWith("ImplementationGuide-") || s.startsWith("StructureMap-") || s.startsWith("ValueSet-") || s.startsWith("StructureDefinition-")) - res.put(s, TextFile.streamToBytes(pi.load("package", s))); + for (String s : pi.listResources("CodeSystem", "ConceptMap", "ImplementationGuide", "StructureMap", "ValueSet", "StructureDefinition")) { + res.put(s, TextFile.streamToBytes(pi.load("package", s))); } String ini = "[FHIR]\r\nversion="+pi.fhirVersion()+"\r\n"; res.put("version.info", ini.getBytes()); diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/r5/validation/ValidationEngine.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/r5/validation/ValidationEngine.java index c2a8a8ae5..e479bb8b3 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/r5/validation/ValidationEngine.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/r5/validation/ValidationEngine.java @@ -415,13 +415,13 @@ public class ValidationEngine implements IValidatorResourceFetcher { private IContextResourceLoader loaderForVersion() { if (Utilities.noString(version)) return null; - if (version.equals("1.0.2")) + if (version.startsWith("1.0")) return new R2ToR5Loader(); - if (version.equals("1.4.0")) + if (version.startsWith("1.4")) return new R2016MayToR5Loader(); // special case - if (version.equals("3.0.1")) + if (version.startsWith("3.0")) return new R3ToR5Loader(); - if (version.equals("4.0.0")) + if (version.startsWith("4.0")) return new R4ToR5Loader(); return null; } @@ -613,14 +613,13 @@ public class ValidationEngine implements IValidatorResourceFetcher { } private Map loadPackage(InputStream stream, String name) throws FileNotFoundException, IOException { - return loadPackage(pcm.extractLocally(stream, name)); + return loadPackage(NpmPackage.fromPackage(stream)); } public Map loadPackage(NpmPackage pi) throws IOException { Map res = new HashMap(); - for (String s : pi.list("package")) { - if (s.startsWith("CodeSystem-") || s.startsWith("ConceptMap-") || s.startsWith("ImplementationGuide-") || s.startsWith("CapabilityStatement-") || s.startsWith("StructureMap-") || s.startsWith("ValueSet-") || s.startsWith("StructureDefinition-")) - res.put(s, TextFile.streamToBytes(pi.load("package", s))); + for (String s : pi.listResources("CodeSystem", "ConceptMap", "ImplementationGuide", "CapabilityStatement", "Conformance", "StructureMap", "ValueSet", "StructureDefinition")) { + res.put(s, TextFile.streamToBytes(pi.load("package", s))); } String ini = "[FHIR]\r\nversion="+pi.fhirVersion()+"\r\n"; res.put("version.info", ini.getBytes()); @@ -787,7 +786,7 @@ public class ValidationEngine implements IValidatorResourceFetcher { System.out.print("* load file: "+fn); Resource r = null; try { - if (version.equals("3.0.1") || version.equals("3.0.0")) { + if (version.startsWith("3.0")) { org.hl7.fhir.dstu3.model.Resource res; if (fn.endsWith(".xml") && !fn.endsWith("template.xml")) res = new org.hl7.fhir.dstu3.formats.XmlParser().parse(new ByteArrayInputStream(t.getValue())); @@ -798,7 +797,7 @@ public class ValidationEngine implements IValidatorResourceFetcher { else throw new Exception("Unsupported format for "+fn); r = VersionConvertor_30_50.convertResource(res, false); - } else if (version.equals("4.0.0")) { + } else if (version.startsWith("4.0")) { org.hl7.fhir.r4.model.Resource res; if (fn.endsWith(".xml") && !fn.endsWith("template.xml")) res = new org.hl7.fhir.r4.formats.XmlParser().parse(new ByteArrayInputStream(t.getValue())); @@ -809,7 +808,7 @@ public class ValidationEngine implements IValidatorResourceFetcher { else throw new Exception("Unsupported format for "+fn); r = VersionConvertor_40_50.convertResource(res); - } else if (version.equals("1.4.0")) { + } else if (version.startsWith("1.4")) { org.hl7.fhir.dstu2016may.model.Resource res; if (fn.endsWith(".xml") && !fn.endsWith("template.xml")) res = new org.hl7.fhir.dstu2016may.formats.XmlParser().parse(new ByteArrayInputStream(t.getValue())); @@ -818,7 +817,7 @@ public class ValidationEngine implements IValidatorResourceFetcher { else throw new Exception("Unsupported format for "+fn); r = VersionConvertor_14_50.convertResource(res); - } else if (version.equals("1.0.2")) { + } else if (version.startsWith("1.0")) { org.hl7.fhir.dstu2.model.Resource res; if (fn.endsWith(".xml") && !fn.endsWith("template.xml")) res = new org.hl7.fhir.dstu2.formats.JsonParser().parse(new ByteArrayInputStream(t.getValue())); diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/r5/validation/Validator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/r5/validation/Validator.java index 4be4b5027..3eb511ca1 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/r5/validation/Validator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/r5/validation/Validator.java @@ -372,12 +372,26 @@ public class Validator { definitions = args[++i]; else if (args[i].equals("-version")) { sv = args[++i]; - if ("1.0".equals(sv)) sv = "1.0.2"; - if ("1.4".equals(sv)) sv = "1.4.0"; - if ("3.0".equals(sv)) sv = "3.0.1"; - if ("4.0".equals(sv)) sv = "4.0.0"; - if (sv.startsWith(Constants.VERSION)) sv = Constants.VERSION; - definitions = "hl7.fhir.core#"+sv; + if (sv.startsWith("1.0")) { + sv = "1.0.2"; + definitions = "hl7.fhir.r2.core#"+sv; + } + if (sv.startsWith("1.4")) { + sv = "1.4.0"; + definitions = "hl7.fhir.r2b.core#"+sv; + } + if (sv.startsWith("3.0")) { + sv = "3.0.2"; + definitions = "hl7.fhir.r3.core#"+sv; + } + if (sv.startsWith("4.0")) { + sv = "4.0.1"; + definitions = "hl7.fhir.r4.core#"+sv; + } + if (sv.startsWith(Constants.VERSION)) { + sv = Constants.VERSION; + definitions = "hl7.fhir.r5.core#"+sv; + } } else if (args[i].equals("-output")) if (i+1 == args.length) throw new Error("Specified -output without indicating output file"); diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ProfileComparisonTests.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ProfileComparisonTests.java index ee19dec88..34b75bce7 100644 --- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ProfileComparisonTests.java +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ProfileComparisonTests.java @@ -24,7 +24,7 @@ public class ProfileComparisonTests { public void testCurrentComparison() throws Exception { if (!TestUtilities.silent) System.out.println("Compare US Patient Core with AU Patient Base"); - ValidationEngine ve = new ValidationEngine("hl7.fhir.core#3.0.1", DEF_TX, null, FhirPublication.R4); + ValidationEngine ve = new ValidationEngine("hl7.fhir.r3.core#3.0.1", DEF_TX, null, FhirPublication.R4); ve.loadIg("hl7.fhir.us.core#1.0.1", false); ve.loadIg("hl7.fhir.au.base#dev", false); 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 b0a3ffc3f..2e89a68e3 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 @@ -27,7 +27,7 @@ public class ValidationEngineTests { public void testCurrentXml() throws Exception { if (!TestUtilities.silent) System.out.println("Validate patient-example.xml in Current version"); - ValidationEngine ve = new ValidationEngine("hl7.fhir.core#4.0.0", DEF_TX, null, FhirPublication.R4); + ValidationEngine ve = new ValidationEngine("hl7.fhir.r4.core#4.0.1", DEF_TX, null, FhirPublication.R4); OperationOutcome op = ve.validate(FhirFormat.XML, TestingUtilities.loadTestResourceStream("validator", "patient-example.xml"), null); int e = errors(op); int w = warnings(op); @@ -47,7 +47,7 @@ public class ValidationEngineTests { public void testCurrentJson() throws Exception { if (!TestUtilities.silent) System.out.println("Validate patient-example.json in Current version"); - ValidationEngine ve = new ValidationEngine("hl7.fhir.core#4.0.0", DEF_TX, null, FhirPublication.R4); + ValidationEngine ve = new ValidationEngine("hl7.fhir.r4.core#4.0.1", DEF_TX, null, FhirPublication.R4); OperationOutcome op = ve.validate(FhirFormat.JSON, TestingUtilities.loadTestResourceStream("validator", "patient-example.json"), null); int e = errors(op); int w = warnings(op); @@ -67,7 +67,7 @@ public class ValidationEngineTests { } if (!TestUtilities.silent) System.out.println("Validate patient-example.xml in v1.4.0 version"); - ValidationEngine ve = new ValidationEngine("hl7.fhir.core#1.4.0", DEF_TX, null, FhirPublication.DSTU2016May); + ValidationEngine ve = new ValidationEngine("hl7.fhir.r2b.core#1.4.0", DEF_TX, null, FhirPublication.DSTU2016May); ve.setNoInvariantChecks(true); OperationOutcome op = ve.validate(FhirFormat.XML, TestingUtilities.loadTestResourceStream("validator", "patient140.xml"), null); if (!TestUtilities.silent) @@ -92,7 +92,7 @@ public class ValidationEngineTests { } if (!org.hl7.fhir.validation.tests.utilities.TestUtilities.silent) System.out.println("Validate patient-example.xml in v1.0.2 version"); - ValidationEngine ve = new ValidationEngine("hl7.fhir.core#1.0.2", DEF_TX, null, FhirPublication.DSTU2); + ValidationEngine ve = new ValidationEngine("hl7.fhir.r2.core#1.0.2", DEF_TX, null, FhirPublication.DSTU2); ve.setNoInvariantChecks(true); OperationOutcome op = ve.validate(FhirFormat.XML, TestingUtilities.loadTestResourceStream("validator", "patient102.xml"), null); if (!TestUtilities.silent) @@ -117,7 +117,7 @@ public class ValidationEngineTests { } if (!TestUtilities.silent) System.out.println("Validate patient-example.xml in v1.0.2 version"); - ValidationEngine ve = new ValidationEngine("hl7.fhir.core#1.0.2", DEF_TX, null, FhirPublication.DSTU2); + ValidationEngine ve = new ValidationEngine("hl7.fhir.r2.core#1.0.2", DEF_TX, null, FhirPublication.DSTU2); ve.setNoInvariantChecks(true); OperationOutcome op = ve.validate(FhirFormat.JSON, TestingUtilities.loadTestResourceStream("validator", "observation102.json"), null); if (!TestUtilities.silent) @@ -139,7 +139,7 @@ public class ValidationEngineTests { public void test301() throws Exception { if (!TestUtilities.silent) System.out.println("Validate observation301.xml against Core"); - ValidationEngine ve = new ValidationEngine("hl7.fhir.core#3.0.1", DEF_TX, null, FhirPublication.STU3); + ValidationEngine ve = new ValidationEngine("hl7.fhir.r3.core#3.0.2", DEF_TX, null, FhirPublication.STU3); if (!TestUtilities.silent) System.out.println(" .. load USCore"); OperationOutcome op = ve.validate(FhirFormat.XML, TestingUtilities.loadTestResourceStream("validator", "observation301.xml"), null); @@ -158,7 +158,7 @@ public class ValidationEngineTests { public void test301USCore() throws Exception { if (!TestUtilities.silent) System.out.println("Validate patient300.xml against US-Core"); - ValidationEngine ve = new ValidationEngine("hl7.fhir.core#3.0.1", DEF_TX, null, FhirPublication.STU3); + ValidationEngine ve = new ValidationEngine("hl7.fhir.r3.core#3.0.2", DEF_TX, null, FhirPublication.STU3); if (!TestUtilities.silent) System.out.println(" .. load USCore"); ve.loadIg("hl7.fhir.us.core#1.0.1", false); diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTestSuite.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTestSuite.java index ec47808f0..7e5f80253 100644 --- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTestSuite.java +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTestSuite.java @@ -93,14 +93,14 @@ public class ValidationTestSuite implements IEvaluationContext, IValidatorResour v = content.get("version").getAsString(); if (ve == null || !v.equals(veVersion)) { - if (v.equals("5.0")) - ve = new ValidationEngine("hl7.fhir.core#current", DEF_TX, null, FhirPublication.R5, true); - else if (v.equals("3.0")) - ve = new ValidationEngine("hl7.fhir.core#3.0.1", DEF_TX, null, FhirPublication.STU3, true); - else if (v.equals("4.0")) - ve = new ValidationEngine("hl7.fhir.core#4.0.0", DEF_TX, null, FhirPublication.R4, true); - else if (v.equals("1.0")) - ve = new ValidationEngine("hl7.fhir.core#1.0.2", DEF_TX, null, FhirPublication.DSTU2, true); + if (v.startsWith("5.0")) + ve = new ValidationEngine("hl7.fhir.r5.core#current", DEF_TX, null, FhirPublication.R5, true); + else if (v.startsWith("3.0")) + ve = new ValidationEngine("hl7.fhir.r3.core#3.0.2", DEF_TX, null, FhirPublication.STU3, true); + else if (v.startsWith("4.0")) + ve = new ValidationEngine("hl7.fhir.r4.core#4.0.1", DEF_TX, null, FhirPublication.R4, true); + else if (v.startsWith("1.0")) + ve = new ValidationEngine("hl7.fhir.r2.core#1.0.2", DEF_TX, null, FhirPublication.DSTU2, true); else throw new Exception("unknown version "+v); TestingUtilities.fcontext = ve.getContext();