Merge pull request #1438 from hapifhir/2023-09-gg-performance
2023 09 gg performance
This commit is contained in:
commit
dd9c2fb9d0
|
@ -2,6 +2,7 @@ package org.hl7.fhir.convertors.misc;
|
|||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
@ -10,6 +11,7 @@ import java.util.ArrayList;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
@ -35,6 +37,7 @@ import org.hl7.fhir.r5.model.Enumerations.FHIRVersionEnumFactory;
|
|||
import org.hl7.fhir.r5.model.ImplementationGuide;
|
||||
import org.hl7.fhir.r5.model.Resource;
|
||||
import org.hl7.fhir.utilities.TextFile;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.VersionUtilities;
|
||||
import org.hl7.fhir.utilities.json.model.JsonArray;
|
||||
import org.hl7.fhir.utilities.json.model.JsonObject;
|
||||
|
@ -118,11 +121,11 @@ public class NpmPackageVersionConverter {
|
|||
NpmPackageIndexBuilder indexer = indexers.get(n);
|
||||
if (indexer == null) {
|
||||
indexer = new NpmPackageIndexBuilder();
|
||||
indexer.start();
|
||||
indexer.start(Utilities.path("[tmp]", "tmp-"+UUID.randomUUID().toString()+".db"));
|
||||
indexers.put(n, indexer);
|
||||
}
|
||||
indexer.seeFile(s, b);
|
||||
if (!s.equals(".index.json") && !s.equals("package.json")) {
|
||||
if (!s.equals(".index.json") && !s.equals("package.json") && !s.equals(".index.db")) {
|
||||
TarArchiveEntry entry = new TarArchiveEntry(e.getKey());
|
||||
entry.setSize(b.length);
|
||||
tar.putArchiveEntry(entry);
|
||||
|
@ -137,6 +140,13 @@ public class NpmPackageVersionConverter {
|
|||
tar.putArchiveEntry(entry);
|
||||
tar.write(cnt);
|
||||
tar.closeArchiveEntry();
|
||||
cnt = TextFile.fileToBytes(e.getValue().getDbFilename());
|
||||
new File(e.getValue().getDbFilename()).delete();
|
||||
entry = new TarArchiveEntry(e.getKey() + "/.index.db");
|
||||
entry.setSize(cnt.length);
|
||||
tar.putArchiveEntry(entry);
|
||||
tar.write(cnt);
|
||||
tar.closeArchiveEntry();
|
||||
}
|
||||
|
||||
byte[] cnt = output.get("package/package.json");
|
||||
|
|
|
@ -57,6 +57,7 @@ import org.hl7.fhir.r4b.model.Enumeration;
|
|||
import org.hl7.fhir.r4b.model.Enumerations.FHIRVersion;
|
||||
import org.hl7.fhir.r4b.model.ImplementationGuide;
|
||||
import org.hl7.fhir.r4b.model.ImplementationGuide.ImplementationGuideDependsOnComponent;
|
||||
import org.hl7.fhir.r4b.utils.NPMPackageGenerator.Category;
|
||||
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
|
||||
import org.hl7.fhir.utilities.TextFile;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
|
@ -110,6 +111,7 @@ public class NPMPackageGenerator {
|
|||
private JsonObject packageManifest;
|
||||
private NpmPackageIndexBuilder indexer;
|
||||
private String igVersion;
|
||||
private String indexdb;
|
||||
|
||||
public NPMPackageGenerator(String destFile, String canonical, String url, PackageType kind, ImplementationGuide ig,
|
||||
Date date, boolean notForPublication) throws FHIRException, IOException {
|
||||
|
@ -324,8 +326,9 @@ public class NPMPackageGenerator {
|
|||
bufferedOutputStream = new BufferedOutputStream(OutputStream);
|
||||
gzipOutputStream = new GzipCompressorOutputStream(bufferedOutputStream);
|
||||
tar = new TarArchiveOutputStream(gzipOutputStream);
|
||||
indexdb = Utilities.path("[tmp]", "tmp-"+UUID.randomUUID().toString()+".db");
|
||||
indexer = new NpmPackageIndexBuilder();
|
||||
indexer.start();
|
||||
indexer.start(indexdb);
|
||||
}
|
||||
|
||||
public void addFile(Category cat, String name, byte[] content) throws IOException {
|
||||
|
@ -367,6 +370,9 @@ public class NPMPackageGenerator {
|
|||
private void buildIndexJson() throws IOException {
|
||||
byte[] content = TextFile.stringToBytes(indexer.build(), false);
|
||||
addFile(Category.RESOURCE, ".index.json", content);
|
||||
content = TextFile.fileToBytes(indexdb);
|
||||
new File(indexdb).delete();
|
||||
addFile(Category.RESOURCE, ".index.db", content);
|
||||
}
|
||||
|
||||
public String filename() {
|
||||
|
|
|
@ -121,7 +121,7 @@ public class JsonParser extends ParserBase {
|
|||
|
||||
@Override
|
||||
public List<NamedElement> parse(InputStream inStream) throws IOException, FHIRException {
|
||||
// long start = System.currentTimeMillis();
|
||||
long start = System.currentTimeMillis();
|
||||
byte[] content = TextFile.streamToBytes(inStream);
|
||||
NamedElement ctxt = new NamedElement("focus", "json", content);
|
||||
|
||||
|
@ -145,8 +145,8 @@ public class JsonParser extends ParserBase {
|
|||
List<NamedElement> res = new ArrayList<>();
|
||||
res.add(ctxt);
|
||||
|
||||
// long t=System.currentTimeMillis()-start;
|
||||
// System.out.println("json parser: "+(t)+": "+content.length+(t == 0 ? "" : " @ "+(content.length / t)));
|
||||
long t=System.currentTimeMillis()-start;
|
||||
System.out.println("json parser: "+(t)+"ms, "+(content.length/1024)+"kb "+(t == 0 ? "" : " @ "+(content.length / t)+"kb/s"));
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -213,55 +213,88 @@ public class JsonParser extends ParserBase {
|
|||
// save time refetching these if we're in a loop
|
||||
properties = element.getProperty().getChildProperties(element.getName(), null);
|
||||
}
|
||||
Map<String, JsonProperty> recognisedChildren = processChildren(errors, path, object);
|
||||
processChildren(errors, path, object);
|
||||
|
||||
// note that we do not trouble ourselves to maintain the wire format order here
|
||||
// first pass: process the properties
|
||||
for (Property property : properties) {
|
||||
parseChildItem(errors, path, recognisedChildren, element, property);
|
||||
parseChildItem(errors, path, object.getProperties(), element, property);
|
||||
}
|
||||
|
||||
// second pass: check for things not processed
|
||||
checkNotProcessed(errors, path, element, hasResourceType, recognisedChildren);
|
||||
// second pass: check for things not processed (including duplicates)
|
||||
checkNotProcessed(errors, path, element, hasResourceType, object.getProperties());
|
||||
|
||||
|
||||
if (object.isExtraComma()) {
|
||||
logError(errors, "2022-11-26", object.getEnd().getLine(), object.getEnd().getCol(), path, IssueType.INVALID, context.formatMessage(I18nConstants.JSON_COMMA_EXTRA, "Object"), IssueSeverity.ERROR);
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
private void checkNotProcessed(List<ValidationMessage> errors, String path, Element element, boolean hasResourceType, Map<String, JsonProperty> recognisedChildren) {
|
||||
private void checkNotProcessed(List<ValidationMessage> errors, String path, Element element, boolean hasResourceType, List<JsonProperty> children) {
|
||||
if (policy != ValidationPolicy.NONE) {
|
||||
for (Entry<String, JsonProperty> e : recognisedChildren.entrySet()) {
|
||||
if (e.getValue().getTag() == 0) {
|
||||
StructureDefinition sd = element.getProperty().isLogical() ? contextUtilities.fetchByJsonName(e.getKey()) : null;
|
||||
for (JsonProperty e : children) {
|
||||
if (e.getTag() == 0) {
|
||||
StructureDefinition sd = element.getProperty().isLogical() ? contextUtilities.fetchByJsonName(e.getName()) : null;
|
||||
if (sd != null) {
|
||||
Property property = new Property(context, sd.getSnapshot().getElementFirstRep(), sd, element.getProperty().getUtils());
|
||||
parseChildItem(errors, path, recognisedChildren, element, property);
|
||||
} else if ("fhir_comments".equals(e.getKey()) && (VersionUtilities.isR2BVer(context.getVersion()) || VersionUtilities.isR2Ver(context.getVersion()))) {
|
||||
if (!e.getValue().getValue().isJsonArray()) {
|
||||
logError(errors, "2022-12-17", line(e.getValue().getValue()), col(e.getValue().getValue()), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.ILLEGAL_COMMENT_TYPE, e.getValue().getValue().type().toName()), IssueSeverity.ERROR);
|
||||
parseChildItem(errors, path, children, element, property);
|
||||
} else if ("fhir_comments".equals(e.getName()) && (VersionUtilities.isR2BVer(context.getVersion()) || VersionUtilities.isR2Ver(context.getVersion()))) {
|
||||
if (!e.getValue().isJsonArray()) {
|
||||
logError(errors, "2022-12-17", line(e.getValue()), col(e.getValue()), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.ILLEGAL_COMMENT_TYPE, e.getValue().type().toName()), IssueSeverity.ERROR);
|
||||
} else {
|
||||
for (JsonElement c : e.getValue().getValue().asJsonArray()) {
|
||||
for (JsonElement c : e.getValue().asJsonArray()) {
|
||||
if (!c.isJsonString()) {
|
||||
logError(errors, "2022-12-17", line(e.getValue().getValue()), col(e.getValue().getValue()), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.ILLEGAL_COMMENT_TYPE, c.type().toName()), IssueSeverity.ERROR);
|
||||
logError(errors, "2022-12-17", line(e.getValue()), col(e.getValue()), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.ILLEGAL_COMMENT_TYPE, c.type().toName()), IssueSeverity.ERROR);
|
||||
} else {
|
||||
element.getComments().add(c.asString());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (hasResourceType && "resourceType".equals(e.getKey())) {
|
||||
} else if (hasResourceType && "resourceType".equals(e.getName())) {
|
||||
// nothing
|
||||
} else {
|
||||
logError(errors, ValidationMessage.NO_RULE_DATE, line(e.getValue().getValue()), col(e.getValue().getValue()), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.UNRECOGNISED_PROPERTY_, e.getKey()), IssueSeverity.ERROR);
|
||||
JsonProperty p = getFoundJsonPropertyByName(e.getName(), children);
|
||||
if (p != null) {
|
||||
logError(errors, "2022-11-26", line(e.getValue()), col(e.getValue()), path, IssueType.INVALID, context.formatMessage(I18nConstants.DUPLICATE_JSON_PROPERTY, e.getName()), IssueSeverity.ERROR);
|
||||
} else {
|
||||
logError(errors, ValidationMessage.NO_RULE_DATE, line(e.getValue()), col(e.getValue()), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.UNRECOGNISED_PROPERTY_, e.getName()), IssueSeverity.ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, JsonProperty> processChildren(List<ValidationMessage> errors, String path, JsonObject object) {
|
||||
Map<String, JsonProperty> recognisedChildren = new HashMap<>();
|
||||
Set<String> unique = new HashSet<>();
|
||||
private JsonProperty getFoundJsonPropertyByName(String name, List<JsonProperty> children) {
|
||||
int hash = name.hashCode();
|
||||
for (JsonProperty p : children) {
|
||||
if (p.getTag() == 1 && hash == p.getNameHash()) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private JsonProperty getJsonPropertyByName(String name, List<JsonProperty> children) {
|
||||
int hash = name.hashCode();
|
||||
for (JsonProperty p : children) {
|
||||
if (p.getTag() == 0 && hash == p.getNameHash()) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private JsonProperty getJsonPropertyByBaseName(String name, List<JsonProperty> children) {
|
||||
for (JsonProperty p : children) {
|
||||
if (p.getTag() == 0 && p.getName().startsWith(name)) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void processChildren(List<ValidationMessage> errors, String path, JsonObject object) {
|
||||
for (JsonProperty p : object.getProperties()) {
|
||||
if (p.isUnquotedName()) {
|
||||
logError(errors, "2022-11-26", line(p.getValue()), col(p.getValue()), path, IssueType.INVALID, context.formatMessage(I18nConstants.JSON_PROPERTY_NO_QUOTES, p.getName()), IssueSeverity.ERROR);
|
||||
|
@ -269,20 +302,13 @@ public class JsonParser extends ParserBase {
|
|||
if (p.isNoComma()) {
|
||||
logError(errors, "2022-11-26", line(p.getValue()), col(p.getValue()), path, IssueType.INVALID, context.formatMessage(I18nConstants.JSON_COMMA_MISSING), IssueSeverity.ERROR);
|
||||
}
|
||||
if (unique.contains(p.getName())) {
|
||||
logError(errors, "2022-11-26", line(p.getValue()), col(p.getValue()), path, IssueType.INVALID, context.formatMessage(I18nConstants.DUPLICATE_JSON_PROPERTY, p.getName()), IssueSeverity.ERROR);
|
||||
} else {
|
||||
unique.add(p.getName());
|
||||
recognisedChildren.put(p.getName(), p);
|
||||
}
|
||||
}
|
||||
return recognisedChildren;
|
||||
}
|
||||
|
||||
public void parseChildItem(List<ValidationMessage> errors, String path, Map<String, JsonProperty> children, Element context, Property property) {
|
||||
public void parseChildItem(List<ValidationMessage> errors, String path, List<JsonProperty> children, Element context, Property property) {
|
||||
JsonProperty jp = getJsonPropertyByName(property.getJsonName(), children);
|
||||
if (property.isChoice() || property.getDefinition().getPath().endsWith("data[x]")) {
|
||||
if (property.isJsonPrimitiveChoice()) {
|
||||
JsonProperty jp = children.get(property.getJsonName());
|
||||
if (jp != null) {
|
||||
jp.setTag(1);
|
||||
JsonElement je = jp.getValue();
|
||||
|
@ -291,30 +317,38 @@ public class JsonParser extends ParserBase {
|
|||
logError(errors, ValidationMessage.NO_RULE_DATE, line(je), col(je), path, IssueType.STRUCTURE, this.context.formatMessage(I18nConstants.UNRECOGNISED_PROPERTY_TYPE, describeType(je), property.getName(), property.typeSummary()), IssueSeverity.ERROR);
|
||||
} else if (property.hasType(type)) {
|
||||
Property np = new Property(property.getContext(), property.getDefinition(), property.getStructure(), property.getUtils(), type);
|
||||
parseChildPrimitive(errors, children, context, np, path, property.getName(), false);
|
||||
parseChildPrimitive(errors, jp, getJsonPropertyByName("_"+property.getJsonName(), children), context, np, path, property.getName(), false);
|
||||
} else {
|
||||
logError(errors, ValidationMessage.NO_RULE_DATE, line(je), col(je), path, IssueType.STRUCTURE, this.context.formatMessage(I18nConstants.UNRECOGNISED_PROPERTY_TYPE_WRONG, describeType(je), property.getName(), type, property.typeSummary()), IssueSeverity.ERROR);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
String baseName = property.getJsonName().substring(0, property.getName().length()-3);
|
||||
jp = getJsonPropertyByBaseName(baseName, children);
|
||||
if (jp != null) {
|
||||
for (TypeRefComponent type : property.getDefinition().getType()) {
|
||||
String eName = property.getJsonName().substring(0, property.getName().length()-3) + Utilities.capitalize(type.getWorkingCode());
|
||||
if (!isPrimitive(type.getWorkingCode()) && children.containsKey(eName)) {
|
||||
parseChildComplex(errors, path, children, context, property, eName, false);
|
||||
String eName = baseName + Utilities.capitalize(type.getWorkingCode());
|
||||
if (jp.getName().equals(eName)) {
|
||||
JsonProperty jp1 = getJsonPropertyByName("_"+eName, children);
|
||||
if (!isPrimitive(type.getWorkingCode()) && jp != null) {
|
||||
parseChildComplex(errors, path, jp, context, property, eName, false);
|
||||
break;
|
||||
} else if (isPrimitive(type.getWorkingCode()) && (children.containsKey(eName) || children.containsKey("_"+eName))) {
|
||||
parseChildPrimitive(errors, children, context, property, path, eName, false);
|
||||
} else if (isPrimitive(type.getWorkingCode()) && (jp != null || jp1 != null)) {
|
||||
parseChildPrimitive(errors, jp, jp1, context, property, path, eName, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (property.isPrimitive(property.getType(null))) {
|
||||
parseChildPrimitive(errors, children, context, property, path, property.getJsonName(), property.hasJsonName());
|
||||
} else if (children.containsKey(property.getJsonName())) {
|
||||
parseChildComplex(errors, path, children, context, property, property.getJsonName(), property.hasJsonName());
|
||||
parseChildPrimitive(errors, jp, getJsonPropertyByName("_"+property.getJsonName(), children), context, property, path, property.getJsonName(), property.hasJsonName());
|
||||
} else if (jp != null) {
|
||||
parseChildComplex(errors, path, jp, context, property, property.getJsonName(), property.hasJsonName());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private String getTypeFromJsonType(JsonElement je) {
|
||||
if (je.isJsonPrimitive()) {
|
||||
JsonPrimitive p = je.asJsonPrimitive();
|
||||
|
@ -335,10 +369,9 @@ public class JsonParser extends ParserBase {
|
|||
}
|
||||
}
|
||||
|
||||
private void parseChildComplex(List<ValidationMessage> errors, String path, Map<String, JsonProperty> children, Element element, Property property, String name, boolean isJsonName) throws FHIRException {
|
||||
private void parseChildComplex(List<ValidationMessage> errors, String path, JsonProperty p, Element element, Property property, String name, boolean isJsonName) throws FHIRException {
|
||||
String npath = path+"."+property.getName();
|
||||
String fpath = element.getPath()+"."+property.getName();
|
||||
JsonProperty p = children.get(name);
|
||||
if (p != null) { p.setTag(1); }
|
||||
JsonElement e = p == null ? null : p.getValue();
|
||||
if (property.isList() && !property.isJsonKeyArray() && (e instanceof JsonArray)) {
|
||||
|
@ -533,11 +566,11 @@ public class JsonParser extends ParserBase {
|
|||
return e.type().toName();
|
||||
}
|
||||
|
||||
private void parseChildPrimitive(List<ValidationMessage> errors, Map<String, JsonProperty> children, Element element, Property property, String path, String name, boolean isJsonName) throws FHIRException {
|
||||
// JsonProperty main = children.containsKey(name) ? children.get(name) : null;
|
||||
// JsonProperty fork = children.containsKey("_"+name) ? children.get("_"+name) : null;
|
||||
private void parseChildPrimitive(List<ValidationMessage> errors, JsonProperty main, JsonProperty fork, Element element, Property property, String path, String name, boolean isJsonName) throws FHIRException {
|
||||
String npath = path+"."+property.getName();
|
||||
String fpath = element.getPath()+"."+property.getName();
|
||||
JsonProperty main = children.containsKey(name) ? children.get(name) : null;
|
||||
JsonProperty fork = children.containsKey("_"+name) ? children.get("_"+name) : null;
|
||||
if (main != null) { main.setTag(1); }
|
||||
if (fork != null) { fork.setTag(1); }
|
||||
|
||||
|
|
|
@ -101,6 +101,7 @@ public class NPMPackageGenerator {
|
|||
private JsonObject packageManifest;
|
||||
private NpmPackageIndexBuilder indexer;
|
||||
private String igVersion;
|
||||
private String indexdb;
|
||||
|
||||
|
||||
public NPMPackageGenerator(String destFile, String canonical, String url, PackageType kind, ImplementationGuide ig, Date date, boolean notForPublication) throws FHIRException, IOException {
|
||||
|
@ -315,8 +316,9 @@ public class NPMPackageGenerator {
|
|||
bufferedOutputStream = new BufferedOutputStream(OutputStream);
|
||||
gzipOutputStream = new GzipCompressorOutputStream(bufferedOutputStream);
|
||||
tar = new TarArchiveOutputStream(gzipOutputStream);
|
||||
indexdb = Utilities.path("[tmp]", "tmp-"+UUID.randomUUID().toString()+".db");
|
||||
indexer = new NpmPackageIndexBuilder();
|
||||
indexer.start();
|
||||
indexer.start(indexdb);
|
||||
}
|
||||
|
||||
|
||||
|
@ -383,6 +385,9 @@ public class NPMPackageGenerator {
|
|||
private void buildIndexJson() throws IOException {
|
||||
byte[] content = TextFile.stringToBytes(indexer.build(), false);
|
||||
addFile(Category.RESOURCE, ".index.json", content);
|
||||
content = TextFile.fileToBytes(indexdb);
|
||||
new File(indexdb).delete();
|
||||
addFile(Category.RESOURCE, ".index.db", content);
|
||||
}
|
||||
|
||||
public String filename() {
|
||||
|
|
|
@ -992,6 +992,11 @@ public class I18nConstants {
|
|||
public static final String BUNDLE_BUNDLE_ENTRY_MULTIPLE_PROFILES_NO_MATCH = "BUNDLE_BUNDLE_ENTRY_MULTIPLE_PROFILES_NO_MATCH";
|
||||
public static final String BUNDLE_BUNDLE_ENTRY_MULTIPLE_PROFILES_MULTIPLE_MATCHES = "BUNDLE_BUNDLE_ENTRY_MULTIPLE_PROFILES_MULTIPLE_MATCHES";
|
||||
public static final String BUNDLE_BUNDLE_ENTRY_MULTIPLE_PROFILES_NO_MATCH_REASON = "BUNDLE_BUNDLE_ENTRY_MULTIPLE_PROFILES_NO_MATCH_REASON";
|
||||
public static final String VALIDATION_HL7_WG_NEEDED = "VALIDATION_HL7_WG_NEEDED";
|
||||
public static final String VALIDATION_HL7_WG_UNKNOWN = "VALIDATION_HL7_WG_UNKNOWN";
|
||||
public static final String VALIDATION_HL7_PUBLISHER_MISMATCH = "VALIDATION_HL7_PUBLISHER_MISMATCH";
|
||||
public static final String VALIDATION_HL7_WG_URL = "VALIDATION_HL7_WG_URL";
|
||||
public static final String VALIDATION_HL7_PUBLISHER_MISSING = "VALIDATION_HL7_PUBLISHER_MISSING";
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -3,16 +3,18 @@ package org.hl7.fhir.utilities.json.model;
|
|||
public class JsonProperty {
|
||||
private String name;
|
||||
private JsonElement value;
|
||||
private int nameHash; // for faster name comparison
|
||||
|
||||
boolean noComma; // parse in Json5 mode, but records this so the validator can complain
|
||||
boolean unquotedName;
|
||||
boolean unquotedValue;
|
||||
|
||||
private int tag;
|
||||
private int tag; // used for status in validator - faster parsing
|
||||
|
||||
public JsonProperty(String name, JsonElement value) {
|
||||
super();
|
||||
this.name = name;
|
||||
this.nameHash = name.hashCode();
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
|
@ -65,4 +67,8 @@ public class JsonProperty {
|
|||
this.tag = tag;
|
||||
}
|
||||
|
||||
public int getNameHash() {
|
||||
return nameHash;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -52,6 +52,7 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.zip.Deflater;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
@ -598,7 +599,7 @@ public class NpmPackage {
|
|||
public void indexFolder(String desc, NpmPackageFolder folder) throws FileNotFoundException, IOException {
|
||||
List<String> remove = new ArrayList<>();
|
||||
NpmPackageIndexBuilder indexer = new NpmPackageIndexBuilder();
|
||||
indexer.start();
|
||||
indexer.start(folder.folder != null ? Utilities.path(folder.folder.getAbsolutePath(), ".index.db") : null);
|
||||
for (String n : folder.listFiles()) {
|
||||
if (!indexer.seeFile(n, folder.fetchFile(n))) {
|
||||
remove.add(n);
|
||||
|
@ -1076,7 +1077,7 @@ public class NpmPackage {
|
|||
Utilities.createDirectory(pd.getAbsolutePath());
|
||||
}
|
||||
NpmPackageIndexBuilder indexer = new NpmPackageIndexBuilder();
|
||||
indexer.start();
|
||||
indexer.start(Utilities.path(dir.getAbsolutePath(), n, ".index.db"));
|
||||
for (String s : folder.content.keySet()) {
|
||||
byte[] b = folder.content.get(s);
|
||||
indexer.seeFile(s, b);
|
||||
|
@ -1112,7 +1113,8 @@ public class NpmPackage {
|
|||
n = "package/"+n;
|
||||
}
|
||||
NpmPackageIndexBuilder indexer = new NpmPackageIndexBuilder();
|
||||
indexer.start();
|
||||
String filename = Utilities.path("[tmp]", "tmp-"+UUID.randomUUID().toString()+".db");
|
||||
indexer.start(filename);
|
||||
for (String s : folder.content.keySet()) {
|
||||
byte[] b = folder.content.get(s);
|
||||
String name = n+"/"+s;
|
||||
|
@ -1135,6 +1137,16 @@ public class NpmPackage {
|
|||
tar.putArchiveEntry(entry);
|
||||
tar.write(cnt);
|
||||
tar.closeArchiveEntry();
|
||||
var file = new File(filename);
|
||||
if (file.exists()) {
|
||||
cnt = TextFile.fileToBytes(file);
|
||||
file.delete();
|
||||
entry = new TarArchiveEntry(n+"/.index.db");
|
||||
entry.setSize(cnt.length);
|
||||
tar.putArchiveEntry(entry);
|
||||
tar.write(cnt);
|
||||
tar.closeArchiveEntry();
|
||||
}
|
||||
}
|
||||
byte[] cnt = TextFile.stringToBytes(JsonParser.compose(npm, true), false);
|
||||
TarArchiveEntry entry = new TarArchiveEntry("package/package.json");
|
||||
|
|
|
@ -2,6 +2,11 @@ package org.hl7.fhir.utilities.npm;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.utilities.TextFile;
|
||||
|
@ -13,6 +18,8 @@ import org.hl7.fhir.utilities.json.parser.JsonParser;
|
|||
/**
|
||||
* This class builds the .index.json for a package
|
||||
*
|
||||
* it also builds a .index.db since that may provide faster access
|
||||
*
|
||||
* @author grahame
|
||||
*
|
||||
*/
|
||||
|
@ -21,12 +28,40 @@ public class NpmPackageIndexBuilder {
|
|||
public static final Integer CURRENT_INDEX_VERSION = 2;
|
||||
private JsonObject index;
|
||||
private JsonArray files;
|
||||
private Connection conn;
|
||||
private PreparedStatement psql;
|
||||
private String dbFilename;
|
||||
|
||||
public void start() {
|
||||
public void start(String filename) {
|
||||
index = new JsonObject();
|
||||
index.add("index-version", CURRENT_INDEX_VERSION);
|
||||
files = new JsonArray();
|
||||
index.add("files", files);
|
||||
|
||||
|
||||
dbFilename = filename;
|
||||
if (filename != null) {
|
||||
try {
|
||||
new File(filename).delete();
|
||||
conn = DriverManager.getConnection("jdbc:sqlite:"+filename);
|
||||
Statement stmt = conn.createStatement();
|
||||
stmt.execute("CREATE TABLE index (\r\n"+
|
||||
"FileName nvarchar NOT NULL,\r\n"+
|
||||
"ResourceType nvarchar NOT NULL,\r\n"+
|
||||
"Id nvarchar NULL,\r\n"+
|
||||
"Url nvarchar NULL,\r\n"+
|
||||
"Version nvarchar NULL,\r\n"+
|
||||
"Kind nvarchar NULL,\r\n"+
|
||||
"Type nvarchar NULL,\r\n"+
|
||||
"Supplements nvarchar NULL,\r\n"+
|
||||
"Content nvarchar NULL,\r\n"+
|
||||
"PRIMARY KEY (FileName))\r\n");
|
||||
|
||||
psql = conn.prepareStatement("Insert into index (FileName, ResourceType, Id, Url, Version, Kind, Type, Supplements, Content) values (?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
||||
} catch (Exception e) {
|
||||
conn = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean seeFile(String name, byte[] content) {
|
||||
|
@ -60,6 +95,18 @@ public class NpmPackageIndexBuilder {
|
|||
if (json.hasPrimitive("content")) {
|
||||
fi.add("content", json.asString("content"));
|
||||
}
|
||||
if (psql != null) {
|
||||
psql.setString(1, name); // FileName);
|
||||
psql.setString(2, json.asString("resourceType")); // ResourceType");
|
||||
psql.setString(3, json.asString("id")); // Id");
|
||||
psql.setString(4, json.asString("url")); // Url");
|
||||
psql.setString(5, json.asString("version")); // Version");
|
||||
psql.setString(6, json.asString("kind")); // Kind");
|
||||
psql.setString(7, json.asString("type")); // Type");
|
||||
psql.setString(8, json.asString("supplements")); // Supplements");
|
||||
psql.setString(9, json.asString("content")); // Content");
|
||||
psql.execute();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println("Error parsing "+name+": "+e.getMessage());
|
||||
|
@ -72,6 +119,13 @@ public class NpmPackageIndexBuilder {
|
|||
}
|
||||
|
||||
public String build() {
|
||||
try {
|
||||
if (conn != null) {
|
||||
conn.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// nothing
|
||||
}
|
||||
String res = JsonParser.compose(index, true);
|
||||
index = null;
|
||||
files = null;
|
||||
|
@ -95,7 +149,7 @@ public class NpmPackageIndexBuilder {
|
|||
if (!existsFile(folder, "package.json")) {
|
||||
throw new FHIRException("Not a proper package? (can't find package.json)");
|
||||
}
|
||||
start();
|
||||
start(Utilities.path(folder, ".index.db"));
|
||||
File dir = new File(folder);
|
||||
for (File f : dir.listFiles()) {
|
||||
seeFile(f.getName(), TextFile.fileToBytes(f));
|
||||
|
@ -103,7 +157,6 @@ public class NpmPackageIndexBuilder {
|
|||
TextFile.stringToFile(build(), Utilities.path(folder, ".index.json"));
|
||||
}
|
||||
|
||||
|
||||
private boolean existsFolder(String... args) throws IOException {
|
||||
File f = new File(Utilities.path(args));
|
||||
return f.exists() && f.isDirectory();
|
||||
|
@ -114,7 +167,6 @@ public class NpmPackageIndexBuilder {
|
|||
return f.exists() && !f.isDirectory();
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
new NpmPackageIndexBuilder().executeWithStatus("C:\\work\\org.hl7.fhir\\packages\\hl7.fhir.rX\\hl7.fhir.r4.core");
|
||||
new NpmPackageIndexBuilder().executeWithStatus("C:\\work\\org.hl7.fhir\\packages\\hl7.fhir.rX\\hl7.fhir.r4.examples");
|
||||
|
@ -143,4 +195,8 @@ public class NpmPackageIndexBuilder {
|
|||
new NpmPackageIndexBuilder().executeWithStatus("C:\\work\\org.hl7.fhir\\packages\\hl7.fhir.rX\\hl7.fhir.core#4.0.1");
|
||||
}
|
||||
|
||||
public String getDbFilename() {
|
||||
return dbFilename;
|
||||
}
|
||||
|
||||
}
|
|
@ -1050,5 +1050,8 @@ VALUESET_INC_TOO_MANY_CODES = The value set include has too many codes to valida
|
|||
BUNDLE_BUNDLE_ENTRY_MULTIPLE_PROFILES_NO_MATCH = The {1} resource did not match any of the allowed profiles (Type {2}: {3})
|
||||
BUNDLE_BUNDLE_ENTRY_MULTIPLE_PROFILES_MULTIPLE_MATCHES = The {1} resource matched more than one of the allowed profiles ({3})
|
||||
BUNDLE_BUNDLE_ENTRY_MULTIPLE_PROFILES_NO_MATCH_REASON = The {1} resource did not math the profile {2} because: {3}
|
||||
|
||||
|
||||
VALIDATION_HL7_WG_NEEDED = When HL7 is publishing a resource, the owning committee must be stated using the {0} extension
|
||||
VALIDATION_HL7_WG_UNKNOWN = The nominated WG ''{0}'' is unknown
|
||||
VALIDATION_HL7_PUBLISHER_MISMATCH = The nominated WG ''{0}'' means that the publisher should be ''{1}'' but ''{2}'' was found
|
||||
VALIDATION_HL7_WG_URL = The nominated WG ''{0}'' means that the contact url should be ''{1}'' but it was not found
|
||||
VALIDATION_HL7_PUBLISHER_MISSING = When HL7 is publishing a resource, the publisher must be provided, and for WG ''{0}'' it should be ''{1}''
|
||||
|
|
|
@ -1330,6 +1330,11 @@ public class BaseValidator implements IValidationContextResourceLoader {
|
|||
return url != null && url.contains("hl7");
|
||||
}
|
||||
|
||||
protected boolean isHL7Core(Element cr) {
|
||||
String url = cr.getChildValue("url");
|
||||
return url != null && url.startsWith("http://hl7.org/fhir/") && !url.startsWith("http://hl7.org/fhir/test");
|
||||
}
|
||||
|
||||
public boolean isAllowExamples() {
|
||||
return this.allowExamples;
|
||||
}
|
||||
|
|
|
@ -5338,6 +5338,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
}
|
||||
|
||||
public boolean checkSpecials(ValidatorHostContext hostContext, List<ValidationMessage> errors, Element element, NodeStack stack, boolean checkSpecials, PercentageTracker pct, ValidationMode mode) {
|
||||
boolean ok = true;
|
||||
|
||||
long t = System.nanoTime();
|
||||
try {
|
||||
|
@ -5350,41 +5351,137 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
hint(errors, "2023-08-14", IssueType.BUSINESSRULE, element.line(), element.col(), stack.getLiteralPath(), statusCodesDeeplyConsistent(status, standardsStatus), I18nConstants.VALIDATION_VAL_STATUS_INCONSISTENT_HINT, status, standardsStatus);
|
||||
}
|
||||
}
|
||||
|
||||
if (isHL7Core(element)) {
|
||||
ok = checkPublisherConsistency(errors, element, stack) && ok;
|
||||
}
|
||||
}
|
||||
if (element.getType().equals(BUNDLE)) {
|
||||
return new BundleValidator(this, serverBase).validateBundle(errors, element, stack, checkSpecials, hostContext, pct, mode);
|
||||
return new BundleValidator(this, serverBase).validateBundle(errors, element, stack, checkSpecials, hostContext, pct, mode) && ok;
|
||||
} else if (element.getType().equals("Observation")) {
|
||||
return validateObservation(errors, element, stack);
|
||||
return validateObservation(errors, element, stack) && ok;
|
||||
} else if (element.getType().equals("Questionnaire")) {
|
||||
return new QuestionnaireValidator(this, myEnableWhenEvaluator, fpe, questionnaireMode).validateQuestionannaire(errors, element, element, stack);
|
||||
return new QuestionnaireValidator(this, myEnableWhenEvaluator, fpe, questionnaireMode).validateQuestionannaire(errors, element, element, stack) && ok;
|
||||
} else if (element.getType().equals("QuestionnaireResponse")) {
|
||||
return new QuestionnaireValidator(this, myEnableWhenEvaluator, fpe, questionnaireMode).validateQuestionannaireResponse(hostContext, errors, element, stack);
|
||||
return new QuestionnaireValidator(this, myEnableWhenEvaluator, fpe, questionnaireMode).validateQuestionannaireResponse(hostContext, errors, element, stack) && ok;
|
||||
} else if (element.getType().equals("Measure")) {
|
||||
return new MeasureValidator(this).validateMeasure(hostContext, errors, element, stack);
|
||||
return new MeasureValidator(this).validateMeasure(hostContext, errors, element, stack) && ok;
|
||||
} else if (element.getType().equals("MeasureReport")) {
|
||||
return new MeasureValidator(this).validateMeasureReport(hostContext, errors, element, stack);
|
||||
return new MeasureValidator(this).validateMeasureReport(hostContext, errors, element, stack) && ok;
|
||||
} else if (element.getType().equals("CapabilityStatement")) {
|
||||
return validateCapabilityStatement(errors, element, stack);
|
||||
return validateCapabilityStatement(errors, element, stack) && ok;
|
||||
} else if (element.getType().equals("CodeSystem")) {
|
||||
return new CodeSystemValidator(this).validateCodeSystem(errors, element, stack, baseOptions.withLanguage(stack.getWorkingLang()));
|
||||
return new CodeSystemValidator(this).validateCodeSystem(errors, element, stack, baseOptions.withLanguage(stack.getWorkingLang())) && ok;
|
||||
} else if (element.getType().equals("ConceptMap")) {
|
||||
return new ConceptMapValidator(this).validateConceptMap(errors, element, stack, baseOptions.withLanguage(stack.getWorkingLang()));
|
||||
return new ConceptMapValidator(this).validateConceptMap(errors, element, stack, baseOptions.withLanguage(stack.getWorkingLang())) && ok;
|
||||
} else if (element.getType().equals("SearchParameter")) {
|
||||
return new SearchParameterValidator(this, fpe).validateSearchParameter(errors, element, stack);
|
||||
return new SearchParameterValidator(this, fpe).validateSearchParameter(errors, element, stack) && ok;
|
||||
} else if (element.getType().equals("StructureDefinition")) {
|
||||
return new StructureDefinitionValidator(this, fpe, wantCheckSnapshotUnchanged).validateStructureDefinition(errors, element, stack);
|
||||
return new StructureDefinitionValidator(this, fpe, wantCheckSnapshotUnchanged).validateStructureDefinition(errors, element, stack) && ok;
|
||||
} else if (element.getType().equals("StructureMap")) {
|
||||
return new StructureMapValidator(this, fpe, profileUtilities).validateStructureMap(errors, element, stack);
|
||||
return new StructureMapValidator(this, fpe, profileUtilities).validateStructureMap(errors, element, stack) && ok;
|
||||
} else if (element.getType().equals("ValueSet")) {
|
||||
return new ValueSetValidator(this).validateValueSet(errors, element, stack);
|
||||
return new ValueSetValidator(this).validateValueSet(errors, element, stack) && ok;
|
||||
} else {
|
||||
return true;
|
||||
return ok;
|
||||
}
|
||||
} finally {
|
||||
timeTracker.spec(t);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkPublisherConsistency(List<ValidationMessage> errors, Element element, NodeStack stack) {
|
||||
|
||||
String pub = element.getNamedChildValue("publisher");
|
||||
Base wgT = element.getExtensionValue(ToolingExtensions.EXT_WORKGROUP);
|
||||
String wg = wgT == null ? null : wgT.primitiveValue();
|
||||
List<String> urls = new ArrayList<>();
|
||||
for (Element c : element.getChildren("contact")) {
|
||||
for (Element t : c.getChildren("telecom")) {
|
||||
if ("url".equals(t.getNamedChildValue("system")) && t.getNamedChildValue("value") != null) {
|
||||
urls.add(t.getNamedChildValue("value"));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (rule(errors, "2023-09-15", IssueType.BUSINESSRULE, element.line(), element.col(), stack.getLiteralPath(), wg != null, I18nConstants.VALIDATION_HL7_WG_NEEDED, ToolingExtensions.EXT_WORKGROUP)) {
|
||||
String name = nameForWG(wg);
|
||||
String url = urlForWG(wg);
|
||||
if (rule(errors, "2023-09-15", IssueType.BUSINESSRULE, element.line(), element.col(), stack.getLiteralPath(), name != null, I18nConstants.VALIDATION_HL7_WG_UNKNOWN, wg)) {
|
||||
String rpub = "HL7 International / "+name;
|
||||
if (warning(errors, "2023-09-15", IssueType.BUSINESSRULE, element.line(), element.col(), stack.getLiteralPath(), pub != null, I18nConstants.VALIDATION_HL7_PUBLISHER_MISSING, wg, rpub)) {
|
||||
warningOrError(pub.contains("/"), errors, "2023-09-15", IssueType.BUSINESSRULE, element.line(), element.col(), stack.getLiteralPath(), rpub.equals(pub), I18nConstants.VALIDATION_HL7_PUBLISHER_MISMATCH, wg, rpub, pub);
|
||||
}
|
||||
warning(errors, "2023-09-15", IssueType.BUSINESSRULE, element.line(), element.col(), stack.getLiteralPath(),
|
||||
Utilities.startsWithInList(url, urls), I18nConstants.VALIDATION_HL7_WG_URL, wg, url);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private String urlForWG(String wg) {
|
||||
switch (wg) {
|
||||
case "cbcc": return "http://www.hl7.org/Special/committees/homehealth";
|
||||
case "cds": return "http://www.hl7.org/Special/committees/dss";
|
||||
case "cqi": return "http://www.hl7.org/Special/committees/cqi";
|
||||
case "cg": return "http://www.hl7.org/Special/committees/clingenomics";
|
||||
case "dev": return "http://www.hl7.org/Special/committees/healthcaredevices";
|
||||
case "ehr": return "http://www.hl7.org/special/committees/ehr";
|
||||
case "fhir": return "http://www.hl7.org/Special/committees/fiwg";
|
||||
case "fm": return "http://www.hl7.org/Special/committees/fm";
|
||||
case "hsi": return "http://www.hl7.org/Special/committees/hsi";
|
||||
case "ii": return "http://www.hl7.org/Special/committees/imagemgt";
|
||||
case "inm": return "http://www.hl7.org/special/committees/inm";
|
||||
case "mnm": return "http://www.hl7.org/special/committees/mnm";
|
||||
case "its": return "http://www.hl7.org/special/committees/xml";
|
||||
case "oo": return "http://www.hl7.org/Special/committees/orders";
|
||||
case "pa": return "http://www.hl7.org/Special/committees/pafm";
|
||||
case "pc": return "http://www.hl7.org/Special/committees/patientcare";
|
||||
case "pe": return "http://www.hl7.org/Special/committees/patientempowerment";
|
||||
case "pher": return "http://www.hl7.org/Special/committees/pher";
|
||||
case "phx": return "http://www.hl7.org/Special/committees/medication";
|
||||
case "brr": return "http://www.hl7.org/Special/committees/rcrim";
|
||||
case "sd": return "http://www.hl7.org/Special/committees/structure";
|
||||
case "sec": return "http://www.hl7.org/Special/committees/secure";
|
||||
case "us": return "http://www.hl7.org/Special/Committees/usrealm";
|
||||
case "vocab": return "http://www.hl7.org/Special/committees/Vocab";
|
||||
case "aid": return "http://www.hl7.org/Special/committees/java";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String nameForWG(String wg) {
|
||||
switch (wg) {
|
||||
|
||||
case "cbcc": return "Community Based Collaborative Care";
|
||||
case "cds": return "Clinical Decision Support";
|
||||
case "cqi": return "Clinical Quality Information";
|
||||
case "cg": return "Clinical Genomics";
|
||||
case "dev": return "Health Care Devices";
|
||||
case "ehr": return "Electronic Health Records";
|
||||
case "fhir": return "FHIR Infrastructure";
|
||||
case "fm": return "Financial Management";
|
||||
case "hsi": return "Health Standards Integration";
|
||||
case "ii": return "Imaging Integration";
|
||||
case "inm": return "Infrastructure And Messaging";
|
||||
case "mnm": return "Modeling and Methodology";
|
||||
case "its": return "Implementable Technology Specifications";
|
||||
case "oo": return "Orders and Observations";
|
||||
case "pa": return "Patient Administration";
|
||||
case "pc": return "Patient Care";
|
||||
case "pe": return "Patient Empowerment";
|
||||
case "pher": return "Public Health and Emergency Response";
|
||||
case "phx": return "Pharmacy";
|
||||
case "brr": return "Biomedical Research and Regulation";
|
||||
case "sd": return "Structured Documents";
|
||||
case "sec": return "Security";
|
||||
case "us": return "US Realm Taskforce";
|
||||
case "vocab": return "Terminology Infrastructure";
|
||||
case "aid": return "Application Implementation and Design";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean statusCodesConsistent(String status, String standardsStatus) {
|
||||
switch (standardsStatus) {
|
||||
case "draft": return Utilities.existsInList(status, "draft");
|
||||
|
|
2
pom.xml
2
pom.xml
|
@ -20,7 +20,7 @@
|
|||
<properties>
|
||||
<guava_version>32.0.1-jre</guava_version>
|
||||
<hapi_fhir_version>6.4.1</hapi_fhir_version>
|
||||
<validator_test_case_version>1.4.4</validator_test_case_version>
|
||||
<validator_test_case_version>1.4.5-SNAPSHOT</validator_test_case_version>
|
||||
<jackson_version>2.15.2</jackson_version>
|
||||
<junit_jupiter_version>5.9.2</junit_jupiter_version>
|
||||
<junit_platform_launcher_version>1.8.2</junit_platform_launcher_version>
|
||||
|
|
Loading…
Reference in New Issue