Build OID -> URL Index

This commit is contained in:
Grahame Grieve 2023-10-12 12:53:55 +11:00
parent e8a162cabb
commit a10ac3c590
5 changed files with 221 additions and 4 deletions

View File

@ -43,6 +43,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import lombok.Getter;
@ -74,11 +75,13 @@ import org.hl7.fhir.r5.model.ElementDefinition;
import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingComponent;
import org.hl7.fhir.r5.model.Enumerations.PublicationStatus;
import org.hl7.fhir.r5.model.IdType;
import org.hl7.fhir.r5.model.Identifier;
import org.hl7.fhir.r5.model.ImplementationGuide;
import org.hl7.fhir.r5.model.Library;
import org.hl7.fhir.r5.model.Measure;
import org.hl7.fhir.r5.model.NamingSystem;
import org.hl7.fhir.r5.model.NamingSystem.NamingSystemIdentifierType;
import org.hl7.fhir.r5.model.NamingSystem.NamingSystemType;
import org.hl7.fhir.r5.model.NamingSystem.NamingSystemUniqueIdComponent;
import org.hl7.fhir.r5.model.OperationDefinition;
import org.hl7.fhir.r5.model.OperationOutcome;
@ -133,11 +136,16 @@ import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.utilities.i18n.I18nBase;
import org.hl7.fhir.utilities.i18n.I18nConstants;
import org.hl7.fhir.utilities.json.JsonException;
import org.hl7.fhir.utilities.json.model.JsonArray;
import org.hl7.fhir.utilities.json.model.JsonProperty;
import org.hl7.fhir.utilities.json.parser.JsonParser;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
import org.hl7.fhir.utilities.validation.ValidationOptions;
import org.hl7.fhir.utilities.validation.ValidationOptions.ValueSetMode;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import javax.annotation.Nonnull;
@ -241,7 +249,10 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
private UcumService ucumService;
protected Map<String, byte[]> binaries = new HashMap<String, byte[]>();
protected Map<String, String> oidCache = new HashMap<>();
protected Map<String, String> oidCacheCS = new HashMap<>();
protected Map<String, String> oidCacheOth = new HashMap<>();
protected Map<String, String> oidCacheManual = new HashMap<>();
protected List<String> oidFiles = new ArrayList<>();
protected Map<String, Map<String, ValidationResult>> validationCache = new HashMap<String, Map<String,ValidationResult>>();
protected String name;
@ -323,7 +334,8 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
codeSystemsUsed.addAll(other.codeSystemsUsed);
ucumService = other.ucumService;
binaries.putAll(other.binaries);
oidCache.putAll(other.oidCache);
oidCacheCS.putAll(other.oidCacheCS);
oidCacheOth.putAll(other.oidCacheOth);
validationCache.putAll(other.validationCache);
tlogging = other.tlogging;
locator = other.locator;
@ -446,7 +458,36 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
}
if (r instanceof CodeSystem || r instanceof NamingSystem) {
oidCache.clear();
oidCacheCS.clear();
String url = null;
Set<String> oids = new HashSet<String>();
if (r instanceof CodeSystem) {
CodeSystem cs = (CodeSystem) r;
url = cs.getUrl();
for (Identifier id : cs.getIdentifier()) {
if (id.hasValue() && id.getValue().startsWith("urn:oid:")) {
oids.add(id.getValue().substring(8));
}
}
}
if (r instanceof NamingSystem) {
NamingSystem ns = ((NamingSystem) r);
if (ns.getKind() == NamingSystemType.CODESYSTEM) {
for (NamingSystemUniqueIdComponent id : ns.getUniqueId()) {
if (id.getType() == NamingSystemIdentifierType.URI) {
url = id.getValue();
}
if (id.getType() == NamingSystemIdentifierType.OID) {
oids.add(id.getValue());
}
}
}
}
if (url != null) {
for (String s : oids) {
oidCacheManual.put(s, url);
}
}
}
if (r instanceof CanonicalResource) {
@ -2778,4 +2819,53 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
this.cachingAllowed = cachingAllowed;
}
@Override
public String urlForOid(boolean codeSystem, String oid) {
if (oid == null) {
return null;
}
Map<String, String> cache = codeSystem ?oidCacheCS : oidCacheOth;
if (cache.isEmpty()) {
loadOidCache();
}
if (cache.containsKey(oid)) {
return cache.get(oid);
}
switch (oid) {
case "2.16.840.1.113883.6.1" : return "http://loinc.org";
case "2.16.840.1.113883.6.96" : return "http://snomed.info/sct";
default:return null;
}
}
private void loadOidCache() {
oidCacheCS.putAll(oidCacheManual);
for (String ff : oidFiles) {
File f = new File(ff);
if (f.exists()) {
org.hl7.fhir.utilities.json.model.JsonObject oids = null;
try {
oids = JsonParser.parseObject(f);
} catch (Exception e) {
e.printStackTrace();
}
if (oids != null && oids.has("cs")) {
loadOids(oidCacheCS, oids.getJsonObject("cs"));
}
if (oids != null && oids.has("other")) {
loadOids(oidCacheOth, oids.getJsonObject("other"));
}
}
}
}
private void loadOids(Map<String, String> cache, org.hl7.fhir.utilities.json.model.JsonObject oids) {
for (JsonProperty p : oids.getProperties()) {
JsonArray a = (JsonArray) p.getValue();
for (String s : a.asStrings()) {
cache.put(s, p.getName());
}
}
}
}

View File

@ -1034,5 +1034,6 @@ public interface IWorkerContext {
public boolean isForPublication();
public void setForPublication(boolean value);
public String urlForOid(boolean codeSystem, String oid);
}

View File

@ -482,6 +482,8 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
packageTracker.packageLoaded(pi.id(), pi.version());
}
oidFiles.add(pi.getFolders().get("package").oidIndexFile());
if ((types == null || types.size() == 0) && loader != null) {
types = loader.getTypes();
}
@ -803,5 +805,6 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
return VersionUtilities.getSpecUrl(getVersion())+"/";
}
}

View File

@ -311,6 +311,22 @@ public class NpmPackage {
}
}
}
public JsonObject oidIndex() throws IOException {
if (folder == null) {
return null;
} else {
File ij = new File(fn(".oids.json"));
if (ij.exists()) {
return JsonParser.parseObject(ij);
} else {
return null;
}
}
}
public String oidIndexFile() throws IOException {
return fn(".oids.json");
}
}
private String path;
@ -597,10 +613,37 @@ public class NpmPackage {
JsonObject index = folder.index();
if (index == null || index.forceArray("files").size() == 0) {
indexFolder(desc, folder);
}
index = folder.oidIndex();
if (index == null || index.forceArray("oids").size() == 0) {
indexOidsInFolder(desc, folder);
}
}
}
public void indexOidsInFolder(String desc, NpmPackageFolder folder) throws FileNotFoundException, IOException {
List<String> remove = new ArrayList<>();
NpmPackageIndexBuilder indexer = new NpmPackageIndexBuilder();
indexer.start(folder.folder != null ? Utilities.path(folder.folder.getAbsolutePath(), ".index.db") : null);
for (String n : folder.listFiles()) {
if (!indexer.seeOidsInFile(n, folder.fetchFile(n))) {
remove.add(n);
}
}
for (String n : remove) {
folder.removeFile(n);
}
String json = JsonParser.compose(indexer.getOidIndex(), true);
try {
if (folder.folder != null) {
TextFile.stringToFile(json, Utilities.path(folder.folder.getAbsolutePath(), ".oids.json"));
}
} catch (Exception e) {
TextFile.stringToFile(json, Utilities.path("[tmp]", ".oids.json"));
throw new IOException("Error parsing "+(desc == null ? "" : desc+"#")+"package/"+folder.folderName+"/.oids.json: "+e.getMessage(), e);
}
}
public void indexFolder(String desc, NpmPackageFolder folder) throws FileNotFoundException, IOException {
List<String> remove = new ArrayList<>();
NpmPackageIndexBuilder indexer = new NpmPackageIndexBuilder();

View File

@ -7,8 +7,11 @@ import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashSet;
import java.util.Set;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.json.model.JsonArray;
@ -31,12 +34,21 @@ public class NpmPackageIndexBuilder {
private Connection conn;
private PreparedStatement psql;
private String dbFilename;
private JsonObject oidIndex;
private JsonObject oidIndexCS;
private JsonObject oidIndexOther;
public void start(String filename) {
index = new JsonObject();
index.add("index-version", CURRENT_INDEX_VERSION);
files = new JsonArray();
index.add("files", files);
oidIndex = new JsonObject();
oidIndexCS = new JsonObject();
oidIndex.add("cs", oidIndexCS);
oidIndexOther = new JsonObject();
oidIndex.add("other", oidIndexOther);
dbFilename = filename;
@ -59,7 +71,7 @@ public class NpmPackageIndexBuilder {
"Derivation nvarchar NULL,\r\n"+
"PRIMARY KEY (FileName))\r\n");
psql = conn.prepareStatement("Insert into ResourceList (FileName, ResourceType, Id, Url, Version, Kind, Type, Supplements, Content, ValueSet) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
psql = conn.prepareStatement("Insert into ResourceList (FileName, ResourceType, Id, Url, Version, Kind, Type, Supplements, Content, ValueSet, OIDs) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
} catch (Exception e) {
if (conn != null) {
try {
@ -109,6 +121,7 @@ public class NpmPackageIndexBuilder {
if (json.hasPrimitive("derivation")) {
fi.add("derivation", json.asString("derivation"));
}
if (psql != null) {
psql.setString(1, name); // FileName);
psql.setString(2, json.asString("resourceType")); // ResourceType");
@ -133,7 +146,70 @@ public class NpmPackageIndexBuilder {
}
return true;
}
public boolean seeOidsInFile(String name, byte[] content) {
if (name.endsWith(".json")) {
try {
JsonObject json = JsonParser.parseObject(content);
String rt = json.asString("resourceType");
if (rt != null) {
Set<String> oids = new HashSet<String>();
String url = null;
if ("NamingSystem".equals(rt)) {
for (JsonObject id : json.getJsonObjects("uniqueId")) {
String t = id.asString("type");
String v = id.asString("value");
if ("url".equals(t) && v != null) {
url = v;
} else if ("oid".equals(t) && v != null) {
oids.add(v);
}
}
JsonArray a = new JsonArray();
("codesystem".equals(json.asString("kind")) ? oidIndexCS : oidIndexOther).add(url, a);
for (String s : oids) {
a.add(s);
}
} else {
if (json.hasPrimitive("url")) {
if (json.has("oid")) {
oids.add(json.asString("oid"));
}
if (json.has("url")) {
String v = json.asString("url");
if (v != null && v.startsWith("urn:oid:")) {
oids.add(v.substring(8));
}
}
for (JsonObject id : json.getJsonObjects("identifier")) {
String v = id.asString("value");
if (v != null && v.startsWith("urn:oid:")) {
oids.add(v.substring(8));
}
}
if (!oids.isEmpty()) {
JsonArray a = new JsonArray();
("CodeSystem".equals(rt) ? oidIndexCS : oidIndexOther).add(json.asString("url"), a);
for (String s : oids) {
a.add(s);
}
}
}
}
}
} catch (Exception e) {
System.out.println("Error parsing "+name+": "+e.getMessage());
if (name.contains("openapi")) {
return false;
}
}
}
return true;
}
public String build() {
try {
if (conn != null) {
@ -215,4 +291,8 @@ public class NpmPackageIndexBuilder {
return dbFilename;
}
public JsonObject getOidIndex() {
return oidIndex;
}
}