implement lazy loading - improve loading times and memory requirements in advance of the challenge of loading UTG for most use cases

This commit is contained in:
Grahame Grieve 2020-07-20 22:57:15 +10:00
parent fb886a7217
commit 52267118c6
15 changed files with 1056 additions and 94 deletions

View File

@ -48,8 +48,11 @@ import org.hl7.fhir.r5.context.IWorkerContext.IContextResourceLoader;
import org.hl7.fhir.r5.model.Bundle;
import org.hl7.fhir.r5.model.Bundle.BundleEntryComponent;
import org.hl7.fhir.r5.model.Bundle.BundleType;
import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent;
import org.hl7.fhir.r5.model.CanonicalResource;
import org.hl7.fhir.r5.model.CanonicalType;
import org.hl7.fhir.r5.model.CodeSystem;
import org.hl7.fhir.r5.model.ElementDefinition;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind;
import org.hl7.fhir.r5.model.UriType;
@ -112,7 +115,46 @@ public class R2016MayToR5Loader extends BaseLoader implements IContextResourceLo
}
return b;
}
@Override
public org.hl7.fhir.r5.model.Resource loadResource(InputStream stream, boolean isJson) throws FHIRException, IOException {
Resource r2016may = null;
if (isJson)
r2016may = new JsonParser().parse(stream);
else
r2016may = new XmlParser().parse(stream);
org.hl7.fhir.r5.model.Resource r5 = VersionConvertor_14_50.convertResource(r2016may);
if (!cslist.isEmpty()) {
throw new FHIRException("Error: Cannot have included code systems");
}
if (killPrimitives) {
throw new FHIRException("Cannot kill primitives when using deferred loading");
}
if (patchUrls) {
if (r5 instanceof StructureDefinition) {
StructureDefinition sd = (StructureDefinition) r5;
sd.setUrl(sd.getUrl().replace("http://hl7.org/fhir/", "http://hl7.org/fhir/4.0/"));
sd.addExtension().setUrl("http://hl7.org/fhir/StructureDefinition/elementdefinition-namespace").setValue(new UriType("http://hl7.org/fhir"));
for (ElementDefinition ed : sd.getSnapshot().getElement())
patchUrl(ed);
for (ElementDefinition ed : sd.getDifferential().getElement())
patchUrl(ed);
}
}
return r5;
}
private void patchUrl(ElementDefinition ed) {
for (TypeRefComponent tr : ed.getType()) {
for (CanonicalType s : tr.getTargetProfile()) {
s.setValue(s.getValue().replace("http://hl7.org/fhir/", "http://hl7.org/fhir/1.4/"));
}
for (CanonicalType s : tr.getProfile()) {
s.setValue(s.getValue().replace("http://hl7.org/fhir/", "http://hl7.org/fhir/1.4/"));
}
}
}
@Override
public boolean ignoreEntry(BundleEntryComponent src) {
return false;

View File

@ -47,8 +47,11 @@ import org.hl7.fhir.r5.context.IWorkerContext.IContextResourceLoader;
import org.hl7.fhir.r5.model.Bundle;
import org.hl7.fhir.r5.model.Bundle.BundleEntryComponent;
import org.hl7.fhir.r5.model.Bundle.BundleType;
import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent;
import org.hl7.fhir.r5.model.CanonicalResource;
import org.hl7.fhir.r5.model.CanonicalType;
import org.hl7.fhir.r5.model.CodeSystem;
import org.hl7.fhir.r5.model.ElementDefinition;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind;
import org.hl7.fhir.r5.model.UriType;
@ -112,6 +115,46 @@ public class R2ToR5Loader extends BaseLoader implements IContextResourceLoader,
return b;
}
@Override
public org.hl7.fhir.r5.model.Resource loadResource(InputStream stream, boolean isJson) throws FHIRException, IOException {
Resource r2 = null;
if (isJson)
r2 = new JsonParser().parse(stream);
else
r2 = new XmlParser().parse(stream);
org.hl7.fhir.r5.model.Resource r5 = VersionConvertor_10_50.convertResource(r2, this);
if (!cslist.isEmpty()) {
throw new FHIRException("Error: Cannot have included code systems");
}
if (killPrimitives) {
throw new FHIRException("Cannot kill primitives when using deferred loading");
}
if (patchUrls) {
if (r5 instanceof StructureDefinition) {
StructureDefinition sd = (StructureDefinition) r5;
sd.setUrl(sd.getUrl().replace("http://hl7.org/fhir/", "http://hl7.org/fhir/4.0/"));
sd.addExtension().setUrl("http://hl7.org/fhir/StructureDefinition/elementdefinition-namespace").setValue(new UriType("http://hl7.org/fhir"));
for (ElementDefinition ed : sd.getSnapshot().getElement())
patchUrl(ed);
for (ElementDefinition ed : sd.getDifferential().getElement())
patchUrl(ed);
}
}
return r5;
}
private void patchUrl(ElementDefinition ed) {
for (TypeRefComponent tr : ed.getType()) {
for (CanonicalType s : tr.getTargetProfile()) {
s.setValue(s.getValue().replace("http://hl7.org/fhir/", "http://hl7.org/fhir/1.0/"));
}
for (CanonicalType s : tr.getProfile()) {
s.setValue(s.getValue().replace("http://hl7.org/fhir/", "http://hl7.org/fhir/1.0/"));
}
}
}
@Override
public boolean ignoreEntry(BundleEntryComponent src) {
return false;

View File

@ -116,6 +116,34 @@ public class R3ToR5Loader extends BaseLoader implements IContextResourceLoader,
}
return b;
}
@Override
public org.hl7.fhir.r5.model.Resource loadResource(InputStream stream, boolean isJson) throws FHIRException, IOException {
Resource r3 = null;
if (isJson)
r3 = new JsonParser().parse(stream);
else
r3 = new XmlParser().parse(stream);
org.hl7.fhir.r5.model.Resource r5 = VersionConvertor_30_50.convertResource(r3, false);
if (!cslist.isEmpty()) {
throw new FHIRException("Error: Cannot have included code systems");
}
if (killPrimitives) {
throw new FHIRException("Cannot kill primitives when using deferred loading");
}
if (patchUrls) {
if (r5 instanceof StructureDefinition) {
StructureDefinition sd = (StructureDefinition) r5;
sd.setUrl(sd.getUrl().replace("http://hl7.org/fhir/", "http://hl7.org/fhir/4.0/"));
sd.addExtension().setUrl("http://hl7.org/fhir/StructureDefinition/elementdefinition-namespace").setValue(new UriType("http://hl7.org/fhir"));
for (ElementDefinition ed : sd.getSnapshot().getElement())
patchUrl(ed);
for (ElementDefinition ed : sd.getDifferential().getElement())
patchUrl(ed);
}
}
return r5;
}
private void patchUrl(ElementDefinition ed) {
for (TypeRefComponent tr : ed.getType()) {

View File

@ -117,6 +117,35 @@ public class R4ToR5Loader extends BaseLoader implements IContextResourceLoader,
return b;
}
@Override
public org.hl7.fhir.r5.model.Resource loadResource(InputStream stream, boolean isJson) throws FHIRException, IOException {
Resource r4 = null;
if (isJson)
r4 = new JsonParser().parse(stream);
else
r4 = new XmlParser().parse(stream);
org.hl7.fhir.r5.model.Resource r5 = VersionConvertor_40_50.convertResource(r4);
if (!cslist.isEmpty()) {
throw new FHIRException("Error: Cannot have included code systems");
}
if (killPrimitives) {
throw new FHIRException("Cannot kill primitives when using deferred loading");
}
if (patchUrls) {
if (r5 instanceof StructureDefinition) {
StructureDefinition sd = (StructureDefinition) r5;
sd.setUrl(sd.getUrl().replace("http://hl7.org/fhir/", "http://hl7.org/fhir/4.0/"));
sd.addExtension().setUrl("http://hl7.org/fhir/StructureDefinition/elementdefinition-namespace").setValue(new UriType("http://hl7.org/fhir"));
for (ElementDefinition ed : sd.getSnapshot().getElement())
patchUrl(ed);
for (ElementDefinition ed : sd.getDifferential().getElement())
patchUrl(ed);
}
}
return r5;
}
private void patchUrl(ElementDefinition ed) {
for (TypeRefComponent tr : ed.getType()) {
for (CanonicalType s : tr.getTargetProfile()) {

View File

@ -115,6 +115,35 @@ public class R5ToR5Loader extends BaseLoader implements IContextResourceLoader,
return b;
}
@Override
public Resource loadResource(InputStream stream, boolean isJson) throws FHIRException, IOException {
Resource r5 = null;
if (isJson)
r5 = new JsonParser().parse(stream);
else
r5 = new XmlParser().parse(stream);
if (!cslist.isEmpty()) {
throw new FHIRException("Error: Cannot have included code systems");
}
if (killPrimitives) {
throw new FHIRException("Cannot kill primitives when using deferred loading");
}
if (patchUrls) {
if (r5 instanceof StructureDefinition) {
StructureDefinition sd = (StructureDefinition) r5;
sd.setUrl(sd.getUrl().replace("http://hl7.org/fhir/", "http://hl7.org/fhir/4.0/"));
sd.addExtension().setUrl("http://hl7.org/fhir/StructureDefinition/elementdefinition-namespace").setValue(new UriType("http://hl7.org/fhir"));
for (ElementDefinition ed : sd.getSnapshot().getElement())
patchUrl(ed);
for (ElementDefinition ed : sd.getDifferential().getElement())
patchUrl(ed);
}
}
return r5;
}
private void patchUrl(ElementDefinition ed) {
for (TypeRefComponent tr : ed.getType()) {
for (CanonicalType s : tr.getTargetProfile()) {

View File

@ -49,6 +49,7 @@ import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.TerminologyServiceException;
import org.hl7.fhir.r5.conformance.ProfileUtilities;
import org.hl7.fhir.r5.context.CanonicalResourceManager.CanonicalResourceProxy;
import org.hl7.fhir.r5.context.IWorkerContext.ILoggingService.LogCategory;
import org.hl7.fhir.r5.context.TerminologyCache.CacheToken;
import org.hl7.fhir.r5.model.BooleanType;
@ -160,7 +161,8 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
private CanonicalResourceManager<Questionnaire> questionnaires = new CanonicalResourceManager<Questionnaire>(false);
private CanonicalResourceManager<OperationDefinition> operations = new CanonicalResourceManager<OperationDefinition>(false);
private CanonicalResourceManager<PlanDefinition> plans = new CanonicalResourceManager<PlanDefinition>(false);
private List<NamingSystem> systems = new ArrayList<NamingSystem>();
private CanonicalResourceManager<NamingSystem> systems = new CanonicalResourceManager<NamingSystem>(false);
private UcumService ucumService;
protected Map<String, byte[]> binaries = new HashMap<String, byte[]>();
@ -216,7 +218,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
plans.copy(other.plans);
questionnaires.copy(other.questionnaires);
operations.copy(other.operations);
systems.addAll(other.systems);
systems.copy(other.systems);
guides.copy(other.guides);
capstmts.copy(other.capstmts);
measures.copy(other.measures);
@ -246,6 +248,55 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
cacheResourceFromPackage(r, null);
}
public void registerResourceFromPackage(CanonicalResourceProxy r, PackageVersion packageInfo) throws FHIRException {
synchronized (lock) {
String url = r.getUrl();
if (!allowLoadingDuplicates && hasResource(r.getType(), url)) {
// spcial workaround for known problems with existing packages
if (Utilities.existsInList(url, "http://hl7.org/fhir/SearchParameter/example")) {
return;
}
throw new DefinitionException(formatMessage(I18nConstants.DUPLICATE_RESOURCE_, url));
}
if ("StructureDefinition".equals(r.getType())) {
StructureDefinition sd = (StructureDefinition) r.getResource();
if ("1.4.0".equals(version)) {
fixOldSD(sd);
}
structures.register(r, packageInfo);
} else if ("ValueSet".equals(r.getType())) {
valueSets.register(r, packageInfo);
} else if ("CodeSystem".equals(r.getType())) {
codeSystems.register(r, packageInfo);
} else if ("ImplementationGuide".equals(r.getType())) {
guides.register(r, packageInfo);
} else if ("CapabilityStatement".equals(r.getType())) {
capstmts.register(r, packageInfo);
} else if ("Measure".equals(r.getType())) {
measures.register(r, packageInfo);
} else if ("Library".equals(r.getType())) {
libraries.register(r, packageInfo);
} else if ("SearchParameter".equals(r.getType())) {
searchParameters.register(r, packageInfo);
} else if ("PlanDefinition".equals(r.getType())) {
plans.register(r, packageInfo);
} else if ("OperationDefinition".equals(r.getType())) {
operations.register(r, packageInfo);
} else if ("Questionnaire".equals(r.getType())) {
questionnaires.register(r, packageInfo);
} else if ("ConceptMap".equals(r.getType())) {
maps.register(r, packageInfo);
} else if ("StructureMap".equals(r.getType())) {
transforms.register(r, packageInfo);
} else if ("NamingSystem".equals(r.getType())) {
systems.register(r, packageInfo);
}
}
}
public void cacheResourceFromPackage(Resource r, PackageVersion packageInfo) throws FHIRException {
synchronized (lock) {
Map<String, Resource> map = allResourcesById.get(r.fhirType());
@ -297,7 +348,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
else if (r instanceof StructureMap)
transforms.see((StructureMap) m, packageInfo);
else if (r instanceof NamingSystem)
systems.add((NamingSystem) r);
systems.see((NamingSystem) m, packageInfo);
}
}
}
@ -842,6 +893,10 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
return fetchResourceWithException(class_, uri, null);
}
public <T extends Resource> T fetchResourceWithException(String cls, String uri) throws FHIRException {
return fetchResourceWithException(cls, uri, null);
}
@SuppressWarnings("unchecked")
public <T extends Resource> T fetchResourceWithException(Class<T> class_, String uri, CanonicalResource source) throws FHIRException {
if (uri == null) {
@ -950,6 +1005,114 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
}
}
@SuppressWarnings("unchecked")
public <T extends Resource> T fetchResourceWithException(String cls, String uri, CanonicalResource source) throws FHIRException {
if (uri == null) {
return null;
}
if ("StructureDefinition".equals(cls)) {
uri = ProfileUtilities.sdNs(uri, getOverrideVersionNs());
}
synchronized (lock) {
String version = null;
if (uri.contains("|")) {
version = uri.substring(uri.lastIndexOf("|")+1);
uri = uri.substring(0, uri.lastIndexOf("|"));
}
if (uri.contains("#"))
uri = uri.substring(0, uri.indexOf("#"));
if (cls == null || "Resource".equals(cls)) {
if (structures.has(uri))
return (T) structures.get(uri, version);
if (guides.has(uri))
return (T) guides.get(uri, version);
if (capstmts.has(uri))
return (T) capstmts.get(uri, version);
if (measures.has(uri))
return (T) measures.get(uri, version);
if (libraries.has(uri))
return (T) libraries.get(uri, version);
if (valueSets.has(uri))
return (T) valueSets.get(uri, version);
if (codeSystems.has(uri))
return (T) codeSystems.get(uri, version);
if (operations.has(uri))
return (T) operations.get(uri, version);
if (searchParameters.has(uri))
return (T) searchParameters.get(uri, version);
if (plans.has(uri))
return (T) plans.get(uri, version);
if (maps.has(uri))
return (T) maps.get(uri, version);
if (transforms.has(uri))
return (T) transforms.get(uri, version);
if (questionnaires.has(uri))
return (T) questionnaires.get(uri, version);
for (Map<String, Resource> rt : allResourcesById.values()) {
for (Resource r : rt.values()) {
if (r instanceof CanonicalResource) {
CanonicalResource mr = (CanonicalResource) r;
if (uri.equals(mr.getUrl()))
return (T) mr;
}
}
}
} else if ("ImplementationGuide".equals(cls)) {
return (T) guides.get(uri, version);
} else if ("CapabilityStatement".equals(cls)) {
return (T) capstmts.get(uri, version);
} else if ("Measure".equals(cls)) {
return (T) measures.get(uri, version);
} else if ("Library".equals(cls)) {
return (T) libraries.get(uri, version);
} else if ("StructureDefinition".equals(cls)) {
return (T) structures.get(uri, version);
} else if ("StructureMap".equals(cls)) {
return (T) transforms.get(uri, version);
} else if ("ValueSet".equals(cls)) {
return (T) valueSets.get(uri, version);
} else if ("CodeSystem".equals(cls)) {
return (T) codeSystems.get(uri, version);
} else if ("ConceptMap".equals(cls)) {
return (T) maps.get(uri, version);
} else if ("PlanDefinition".equals(cls)) {
return (T) plans.get(uri, version);
} else if ("OperationDefinition".equals(cls)) {
OperationDefinition od = operations.get(uri, version);
return (T) od;
} else if ("Questionnaire.class".equals(cls)) {
return (T) questionnaires.get(uri, version);
} else if ("SearchParameter.class".equals(cls)) {
SearchParameter res = searchParameters.get(uri, version);
return (T) res;
}
if ("CodeSystem".equals(cls) && codeSystems.has(uri))
return (T) codeSystems.get(uri, version);
if ("ValueSet".equals(cls) && valueSets.has(uri))
return (T) valueSets.get(uri, version);
if ("Questionnaire".equals(cls))
return (T) questionnaires.get(uri, version);
if (cls == null) {
if (uri.matches(Constants.URI_REGEX) && !uri.contains("ValueSet"))
return null;
// it might be a special URL.
if (Utilities.isAbsoluteUrl(uri) || uri.startsWith("ValueSet/")) {
Resource res = null; // findTxValueSet(uri);
if (res != null)
return (T) res;
}
return null;
}
if (supportedCodeSystems.contains(uri))
return null;
throw new FHIRException(formatMessage(I18nConstants.NOT_DONE_YET_CANT_FETCH_, uri));
}
}
private Set<String> notCanonical = new HashSet<String>();
private String overrideVersionNs;
@ -1024,6 +1187,14 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
}
}
public <T extends Resource> boolean hasResource(String cls, String uri) {
try {
return fetchResourceWithException(cls, uri) != null;
} catch (Exception e) {
return false;
}
}
public TranslationServices translator() {
return translator;
@ -1104,33 +1275,31 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
if (map.containsKey(id))
map.remove(id);
if (fhirType.equals("StructureDefinition"))
if (fhirType.equals("StructureDefinition")) {
structures.drop(id);
else if (fhirType.equals("ImplementationGuide"))
} else if (fhirType.equals("ImplementationGuide")) {
guides.drop(id);
else if (fhirType.equals("CapabilityStatement"))
} else if (fhirType.equals("CapabilityStatement")) {
capstmts.drop(id);
else if (fhirType.equals("Measure"))
} else if (fhirType.equals("Measure")) {
measures.drop(id);
else if (fhirType.equals("Library"))
} else if (fhirType.equals("Library")) {
libraries.drop(id);
else if (fhirType.equals("ValueSet"))
} else if (fhirType.equals("ValueSet")) {
valueSets.drop(id);
else if (fhirType.equals("CodeSystem"))
} else if (fhirType.equals("CodeSystem")) {
codeSystems.drop(id);
else if (fhirType.equals("OperationDefinition"))
} else if (fhirType.equals("OperationDefinition")) {
operations.drop(id);
else if (fhirType.equals("Questionnaire"))
} else if (fhirType.equals("Questionnaire")) {
questionnaires.drop(id);
else if (fhirType.equals("ConceptMap"))
} else if (fhirType.equals("ConceptMap")) {
maps.drop(id);
else if (fhirType.equals("StructureMap"))
} else if (fhirType.equals("StructureMap")) {
transforms.drop(id);
else if (fhirType.equals("NamingSystem"))
for (int i = systems.size()-1; i >= 0; i--) {
if (systems.get(i).getId().equals(id))
systems.remove(i);
}
} else if (fhirType.equals("NamingSystem")) {
systems.drop(id);
}
}
}
@ -1227,7 +1396,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
String uri = OIDUtils.getUriForOid(oid);
if (uri != null)
return uri;
for (NamingSystem ns : systems) {
for (NamingSystem ns : systems.getList()) {
if (hasOid(ns, oid)) {
uri = getUri(ns);
if (uri != null)

View File

@ -9,8 +9,12 @@ import java.util.Map;
import java.util.Set;
import java.util.UUID;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r5.context.CanonicalResourceManager.CanonicalResourceProxy;
import org.hl7.fhir.r5.context.IWorkerContext.PackageVersion;
import org.hl7.fhir.r5.model.CanonicalResource;
import org.hl7.fhir.r5.model.CodeSystem;
import org.hl7.fhir.r5.terminologies.CodeSystemUtilities;
import org.hl7.fhir.utilities.VersionUtilities;
/**
@ -23,6 +27,66 @@ import org.hl7.fhir.utilities.VersionUtilities;
public class CanonicalResourceManager<T extends CanonicalResource> {
public static abstract class CanonicalResourceProxy {
private String type;
private String id;
private String url;
private String version;
private CanonicalResource resource;
public CanonicalResourceProxy(String type, String id, String url, String version) {
super();
this.type = type;
this.id = id;
this.url = url;
this.version = version;
}
public String getType() {
return type;
}
public String getId() {
return id;
}
public String getUrl() {
return url;
}
public String getVersion() {
return version;
}
public boolean hasId() {
return id != null;
}
public boolean hasUrl() {
return url != null;
}
public boolean hasVersion() {
return version != null;
}
public CanonicalResource getResource() throws FHIRException {
if (resource == null) {
resource = loadResource();
if (resource instanceof CodeSystem) {
CodeSystemUtilities.crossLinkCodeSystem((CodeSystem) resource);
}
}
return resource;
}
public void setResource(CanonicalResource resource) {
this.resource = resource;
}
public abstract CanonicalResource loadResource() throws FHIRException;
}
public class CanonicalListSorter implements Comparator<CanonicalResource> {
@Override
@ -35,37 +99,54 @@ public class CanonicalResourceManager<T extends CanonicalResource> {
private class CachedCanonicalResource<T1 extends CanonicalResource> {
private T1 resource;
private CanonicalResourceProxy proxy;
private PackageVersion packageInfo;
public CachedCanonicalResource(T1 resource, PackageVersion packageInfo) {
super();
this.resource = resource;
this.packageInfo = packageInfo;
}
public CachedCanonicalResource(CanonicalResourceProxy proxy, PackageVersion packageInfo) {
super();
this.proxy = proxy;
this.packageInfo = packageInfo;
}
public T1 getResource() {
if (resource == null) {
@SuppressWarnings("unchecked")
T1 res = (T1) proxy.getResource();
synchronized (this) {
resource = res;
}
}
return resource;
}
public PackageVersion getPackageInfo() {
return packageInfo;
}
public String getUrl() {
return resource.getUrl();
return resource != null ? resource.getUrl() : proxy.getUrl();
}
public String getId() {
return resource.getId();
return resource != null ? resource.getId() : proxy.getId();
}
public String getVersion() {
return resource.getVersion();
return resource != null ? resource.getVersion() : proxy.getVersion();
}
public boolean hasVersion() {
return resource.hasVersion();
return resource != null ? resource.hasVersion() : proxy.getVersion() != null;
}
}
public class MetadataResourceVersionComparator<T1 extends CachedCanonicalResource<T>> implements Comparator<T1> {
@Override
public int compare(T1 arg1, T1 arg2) {
String v1 = arg1.getResource().getVersion();
String v2 = arg2.getResource().getVersion();
String v1 = arg1.getVersion();
String v2 = arg2.getVersion();
if (v1 == null && v2 == null) {
return Integer.compare(list.indexOf(arg1), list.indexOf(arg2)); // retain original order
} else if (v1 == null) {
@ -86,7 +167,7 @@ public class CanonicalResourceManager<T extends CanonicalResource> {
private boolean enforceUniqueId;
private List<CachedCanonicalResource<T>> list = new ArrayList<>();
private Map<String, T> map = new HashMap<>();
private Map<String, CachedCanonicalResource<T>> map = new HashMap<>();
public CanonicalResourceManager(boolean enforceUniqueId) {
@ -101,18 +182,31 @@ public class CanonicalResourceManager<T extends CanonicalResource> {
map.putAll(source.map);
}
public void register(CanonicalResourceProxy r, PackageVersion packgeInfo) {
if (!r.hasId()) {
throw new FHIRException("An id is required for a deferred load resource");
}
CanonicalResourceManager<T>.CachedCanonicalResource<T> cr = new CachedCanonicalResource<T>(r, packgeInfo);
see(cr);
}
public void see(T r, PackageVersion packgeInfo) {
if (!r.hasId()) {
r.setId(UUID.randomUUID().toString());
}
if (enforceUniqueId && map.containsKey(r.getId())) {
drop(r.getId());
CanonicalResourceManager<T>.CachedCanonicalResource<T> cr = new CachedCanonicalResource<T>(r, packgeInfo);
see(cr);
}
public void see(CachedCanonicalResource<T> cr) {
if (enforceUniqueId && map.containsKey(cr.getId())) {
drop(cr.getId());
}
// special case logic for UTG support prior to version 5
if (packgeInfo != null && packgeInfo.getId().startsWith("hl7.terminology")) {
if (cr.getPackageInfo() != null && cr.getPackageInfo().getId().startsWith("hl7.terminology")) {
List<CachedCanonicalResource<T>> toDrop = new ArrayList<>();
for (CachedCanonicalResource<T> n : list) {
if (n.getResource().getUrl().equals(r.getUrl()) && isBasePackage(n.getPackageInfo())) {
if (n.getUrl().equals(cr.getUrl()) && isBasePackage(n.getPackageInfo())) {
toDrop.add(n);
}
}
@ -120,15 +214,15 @@ public class CanonicalResourceManager<T extends CanonicalResource> {
drop(n.getId());
}
}
list.add(new CachedCanonicalResource<T>(r, packgeInfo));
map.put(r.getId(), r); // we do this so we can drop by id
list.add(cr);
map.put(cr.getId(), cr); // we do this so we can drop by id
if (r.hasUrl()) {
if (cr.getUrl() != null) {
// first, this is the correct reosurce for this version (if it has a version)
if (r.hasVersion()) {
map.put(r.getUrl()+"|"+r.getVersion(), r);
if (cr.hasVersion()) {
map.put(cr.getUrl()+"|"+cr.getVersion(), cr);
}
updateList(r.getUrl(), r.getVersion());
updateList(cr.getUrl(), cr.getVersion());
}
}
@ -147,19 +241,19 @@ public class CanonicalResourceManager<T extends CanonicalResource> {
// sort by version as much as we are able
Collections.sort(rl, new MetadataResourceVersionComparator<CachedCanonicalResource<T>>());
// the current is the latest
map.put(url, rl.get(rl.size()-1).getResource());
map.put(url, rl.get(rl.size()-1));
// now, also, the latest for major/minor
if (version != null) {
T latest = null;
CachedCanonicalResource<T> latest = null;
for (CachedCanonicalResource<T> t : rl) {
if (VersionUtilities.versionsCompatible(t.getResource().getVersion(), version)) {
latest = t.getResource();
if (VersionUtilities.versionsCompatible(t.getVersion(), version)) {
latest = t;
}
}
if (latest != null) { // might be null if it's not using semver
String lv = VersionUtilities.getMajMin(latest.getVersion());
if (lv != null && !lv.equals(version))
map.put(url+"|"+lv, rl.get(rl.size()-1).getResource());
map.put(url+"|"+lv, rl.get(rl.size()-1));
}
}
}
@ -167,7 +261,7 @@ public class CanonicalResourceManager<T extends CanonicalResource> {
public T get(String url) {
return map.get(url);
return map.containsKey(url) ? map.get(url).getResource() : null;
}
public boolean has(String url) {
@ -179,10 +273,10 @@ public class CanonicalResourceManager<T extends CanonicalResource> {
return get(system);
} else {
if (map.containsKey(system+"|"+version))
return map.get(system+"|"+version);
return map.get(system+"|"+version).getResource();
String mm = VersionUtilities.getMajMin(version);
if (mm != null)
return map.get(system+"|"+mm);
if (mm != null && map.containsKey(system+"|"+mm))
return map.get(system+"|"+mm).getResource();
else
return null;
}

View File

@ -119,7 +119,7 @@ public interface IWorkerContext {
public interface IContextResourceLoader {
Bundle loadBundle(InputStream stream, boolean isJson) throws FHIRException, IOException;
Resource loadResource(InputStream stream, boolean isJson) throws FHIRException, IOException;
String[] getTypes();
}

View File

@ -53,7 +53,9 @@ import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r5.conformance.ProfileUtilities;
import org.hl7.fhir.r5.conformance.ProfileUtilities.ProfileKnowledgeProvider;
import org.hl7.fhir.r5.context.CanonicalResourceManager.CanonicalResourceProxy;
import org.hl7.fhir.r5.context.IWorkerContext.ILoggingService.LogCategory;
import org.hl7.fhir.r5.context.SimpleWorkerContext.PackageResourceLoader;
import org.hl7.fhir.r5.formats.IParser;
import org.hl7.fhir.r5.formats.JsonParser;
import org.hl7.fhir.r5.formats.ParserType;
@ -77,6 +79,7 @@ import org.hl7.fhir.utilities.CSFileInputStream;
import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.cache.NpmPackage;
import org.hl7.fhir.utilities.cache.NpmPackage.PackageResourceInformation;
import org.hl7.fhir.utilities.i18n.I18nConstants;
import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
@ -92,10 +95,39 @@ import ca.uhn.fhir.parser.DataFormatException;
public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerContext, ProfileKnowledgeProvider {
public class PackageResourceLoader extends CanonicalResourceProxy {
private String filename;
private IContextResourceLoader loader;
public PackageResourceLoader(PackageResourceInformation pri, IContextResourceLoader loader) {
super(pri.getType(), pri.getId(), pri.getUrl(),pri.getVersion());
this.filename = pri.getFilename();
this.loader = loader;
}
@Override
public CanonicalResource loadResource() {
try {
FileInputStream f = new FileInputStream(filename);
try {
if (loader != null) {
return (CanonicalResource) loader.loadResource(f, true);
} else {
return (CanonicalResource) new JsonParser().parse(f);
}
} finally {
f.close();
}
} catch (FHIRFormatError | IOException e) {
throw new FHIRException("Error loading "+filename+": "+e.getMessage(), e);
}
}
}
public interface ILoadFilter {
boolean isOkToLoad(Resource resource);
boolean isOkToLoad(String resourceType);
}
public interface IValidatorFactory {
@ -159,6 +191,7 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
public static SimpleWorkerContext fromPackage(NpmPackage pi, boolean allowDuplicates) throws FileNotFoundException, IOException, FHIRException {
return fromPackage(pi, allowDuplicates, null);
}
public static SimpleWorkerContext fromPackage(NpmPackage pi, boolean allowDuplicates, ILoadFilter filter) throws FileNotFoundException, IOException, FHIRException {
SimpleWorkerContext res = new SimpleWorkerContext();
res.setAllowLoadingDuplicates(allowDuplicates);
@ -328,11 +361,12 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
System.out.println("Load Package "+pi.name()+"#"+pi.version());
}
loadedPackages.add(pi.id()+"#"+pi.version());
for (String s : pi.listResources(loader.getTypes())) {
String [] types = loader != null ? loader.getTypes() : new String[] { "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem" };
for (PackageResourceInformation pri : pi.listIndexedResources(types)) {
try {
loadDefinitionItem(s, pi.load("package", s), loader, filter, new PackageVersion(pi.id(), pi.version()));
} catch (FHIRException | IOException e) {
throw new FHIRException(formatMessage(I18nConstants.ERROR_READING__FROM_PACKAGE__, s, pi.name(), pi.version(), e.getMessage()), e);
registerResourceFromPackage(new PackageResourceLoader(pri, loader), new PackageVersion(pi.id(), pi.version()));
} catch (FHIRException e) {
throw new FHIRException(formatMessage(I18nConstants.ERROR_READING__FROM_PACKAGE__, pri.getFilename(), pi.name(), pi.version(), e.getMessage()), e);
}
}
for (String s : pi.list("other")) {
@ -349,10 +383,18 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
System.out.println("Load Package "+pi.name()+"#"+pi.version());
}
loadedPackages.add(pi.id()+"#"+pi.version());
if (types.length == 0)
if (types.length == 0 && loader != null) {
types = loader.getTypes();
}
if (types.length == 0) {
types = new String[] { "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem" };
for (String s : pi.listResources(types)) {
loadDefinitionItem(s, pi.load("package", s), loader, null, new PackageVersion(pi.id(), pi.version()));
}
for (PackageResourceInformation pri : pi.listIndexedResources(types)) {
try {
registerResourceFromPackage(new PackageResourceLoader(pri, loader), new PackageVersion(pi.id(), pi.version()));
} catch (FHIRException e) {
throw new FHIRException(formatMessage(I18nConstants.ERROR_READING__FROM_PACKAGE__, pri.getFilename(), pi.name(), pi.version(), e.getMessage()), e);
}
}
for (String s : pi.list("other")) {
binaries.put(s, TextFile.streamToBytes(pi.load("other", s)));

View File

@ -1,13 +1,30 @@
package org.hl7.fhir.r5.test;
import org.hl7.fhir.r5.context.CanonicalResourceManager;
import org.hl7.fhir.r5.context.CanonicalResourceManager.CanonicalResourceProxy;
import org.hl7.fhir.r5.context.IWorkerContext.PackageVersion;
import org.hl7.fhir.r5.model.CanonicalResource;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.test.CanonicalResourceManagerTester.DeferredLoadTestResource;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class CanonicalResourceManagerTester {
public class DeferredLoadTestResource extends CanonicalResourceProxy {
private CanonicalResource resource;
public DeferredLoadTestResource(CanonicalResource resource) {
super(resource.fhirType(), resource.getId(), resource.getUrl(), resource.getVersion());
this.resource = resource;
}
@Override
public CanonicalResource loadResource() {
return resource;
}
}
@Test
public void testSingleNoVersion() {
CanonicalResourceManager<ValueSet> mrm = new CanonicalResourceManager<>(true);
@ -157,8 +174,7 @@ public class CanonicalResourceManagerTester {
Assertions.assertNull(mrm.get("http://url/ValueSet/234", "4.0.1"));
Assertions.assertNull(mrm.get("http://url/ValueSet/234", "4.0.2"));
Assertions.assertNull(mrm.get("http://url/ValueSet/234", "4.0"));
Assertions.assertNull(mrm.get("http://url/ValueSet/234", "4.1"));
Assertions.assertNull(mrm.get("http://url/ValueSet/234", "4.1"));
}
@Test
@ -422,4 +438,376 @@ public class CanonicalResourceManagerTester {
Assertions.assertTrue(mrm.get("http://terminology.hl7.org/ValueSet/234").getName().equals("2"));
Assertions.assertNull(mrm.get("http://terminology.hl7.org/ValueSet/234", "2.0.0")); // this will get dropped completely because of UTG rules
}
@Test
public void testSingleNoVersionDeferredLoad() {
CanonicalResourceManager<ValueSet> mrm = new CanonicalResourceManager<>(true);
ValueSet vs = new ValueSet();
vs.setId("2345");
vs.setUrl("http://url/ValueSet/234");
// no version
DeferredLoadTestResource vsd = new DeferredLoadTestResource(vs);
mrm.clear();
mrm.register(vsd, null);
Assertions.assertEquals(mrm.size(), 1);
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234"));
Assertions.assertNotNull(mrm.get("2345"));
Assertions.assertNull(mrm.get("http://url/ValueSet/234", "4.0.0"));
mrm.register(vsd, null);
Assertions.assertEquals(mrm.size(), 1);
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234"));
Assertions.assertNotNull(mrm.get("2345"));
Assertions.assertNull(mrm.get("http://url/ValueSet/234", "4.0.0"));
mrm.drop("2344");
Assertions.assertEquals(mrm.size(), 1);
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234"));
Assertions.assertNotNull(mrm.get("2345"));
Assertions.assertNull(mrm.get("http://url/ValueSet/234", "4.0.0"));
mrm.drop("2345");
Assertions.assertEquals(mrm.size(), 0);
Assertions.assertNull(mrm.get("http://url/ValueSet/234"));
Assertions.assertNull(mrm.get("2345"));
Assertions.assertNull(mrm.get("http://url/ValueSet/234", "4.0.0"));
}
@Test
public void testSingleWithVersionDeferredLoad() {
CanonicalResourceManager<ValueSet> mrm = new CanonicalResourceManager<>(true);
ValueSet vs = new ValueSet();
vs.setId("2345");
vs.setUrl("http://url/ValueSet/234");
vs.setVersion("4.0.1");
DeferredLoadTestResource vsd = new DeferredLoadTestResource(vs);
mrm.clear();
mrm.register(vsd, null);
Assertions.assertNotNull(mrm.get("2345"));
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234"));
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0.0"));
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0.1"));
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0.2"));
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0"));
Assertions.assertNull(mrm.get("http://url/ValueSet/234", "4.1"));
}
@Test
public void testSingleWithVersionNotSemVerDeferredLoad() {
CanonicalResourceManager<ValueSet> mrm = new CanonicalResourceManager<>(true);
ValueSet vs = new ValueSet();
vs.setId("2345");
vs.setUrl("http://url/ValueSet/234");
vs.setVersion("20140403");
DeferredLoadTestResource vsd = new DeferredLoadTestResource(vs);
mrm.clear();
mrm.register(vsd, null);
Assertions.assertNotNull(mrm.get("2345"));
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234"));
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "20140403"));
Assertions.assertNull(mrm.get("http://url/ValueSet/234", "20140402"));
Assertions.assertNull(mrm.get("http://url/ValueSet/234", "2014"));
}
@Test
public void testSingleWithDuplicateIds1DeferredLoad() {
CanonicalResourceManager<ValueSet> mrm = new CanonicalResourceManager<>(false);
ValueSet vs1 = new ValueSet();
vs1.setId("2345");
vs1.setUrl("http://url/ValueSet/234");
vs1.setVersion("4.0.1");
vs1.setName("1");
DeferredLoadTestResource vs1d = new DeferredLoadTestResource(vs1);
ValueSet vs2 = new ValueSet();
vs2.setId("2345");
vs2.setUrl("http://url/ValueSet/234");
vs2.setVersion("4.0.2");
vs2.setName("2");
DeferredLoadTestResource vs2d = new DeferredLoadTestResource(vs2);
mrm.clear();
mrm.register(vs1d, null);
Assertions.assertEquals(mrm.size(), 1);
Assertions.assertNotNull(mrm.get("2345"));
Assertions.assertEquals(mrm.get("2345").getName(), "1");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234").getName(), "1");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0.0"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0.0").getName(), "1");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0.1"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0.1").getName(), "1");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0.2"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0.2").getName(), "1");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0").getName(), "1");
Assertions.assertNull(mrm.get("http://url/ValueSet/234", "4.1"));
mrm.register(vs2d, null);
Assertions.assertEquals(mrm.size(), 2);
Assertions.assertNotNull(mrm.get("2345"));
Assertions.assertEquals(mrm.get("2345").getName(), "2");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234").getName(), "2");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0.0"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0.0").getName(), "2");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0.1"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0.1").getName(), "1");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0.2"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0.2").getName(), "2");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0").getName(), "2");
Assertions.assertNull(mrm.get("http://url/ValueSet/234", "4.1"));
mrm.drop("2346"); // doesn't exist;
Assertions.assertEquals(mrm.size(), 2);
Assertions.assertNotNull(mrm.get("2345"));
Assertions.assertNull(mrm.get("2346"));
Assertions.assertEquals(mrm.get("2345").getName(), "2");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234").getName(), "2");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0.0"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0.0").getName(), "2");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0.1"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0.1").getName(), "1");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0.2"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0.2").getName(), "2");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0").getName(), "2");
Assertions.assertNull(mrm.get("http://url/ValueSet/234", "4.1"));
mrm.drop("2345"); // vs2;
Assertions.assertEquals(mrm.size(), 0);
Assertions.assertNull(mrm.get("2345"));
Assertions.assertNull(mrm.get("2346"));
Assertions.assertNull(mrm.get("http://url/ValueSet/234"));
Assertions.assertNull(mrm.get("http://url/ValueSet/234", "4.0.0"));
Assertions.assertNull(mrm.get("http://url/ValueSet/234", "4.0.1"));
Assertions.assertNull(mrm.get("http://url/ValueSet/234", "4.0.2"));
Assertions.assertNull(mrm.get("http://url/ValueSet/234", "4.0"));
Assertions.assertNull(mrm.get("http://url/ValueSet/234", "4.1"));
}
@Test
public void testSingleWithDuplicateIds2DeferredLoad() {
CanonicalResourceManager<ValueSet> mrm = new CanonicalResourceManager<>(true);
ValueSet vs1 = new ValueSet();
vs1.setId("2345");
vs1.setUrl("http://url/ValueSet/234");
vs1.setVersion("4.0.1");
vs1.setName("1");
DeferredLoadTestResource vs1d = new DeferredLoadTestResource(vs1);
ValueSet vs2 = new ValueSet();
vs2.setId("2345");
vs2.setUrl("http://url/ValueSet/234");
vs2.setVersion("4.0.2");
vs2.setName("2");
DeferredLoadTestResource vs2d = new DeferredLoadTestResource(vs2);
mrm.clear();
mrm.register(vs1d, null);
Assertions.assertEquals(mrm.size(), 1);
Assertions.assertNotNull(mrm.get("2345"));
Assertions.assertEquals(mrm.get("2345").getName(), "1");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234").getName(), "1");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0.0"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0.0").getName(), "1");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0.1"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0.1").getName(), "1");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0.2"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0.2").getName(), "1");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0").getName(), "1");
Assertions.assertNull(mrm.get("http://url/ValueSet/234", "4.1"));
mrm.register(vs2d, null);
Assertions.assertEquals(mrm.size(), 1);
Assertions.assertNotNull(mrm.get("2345"));
Assertions.assertEquals(mrm.get("2345").getName(), "2");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234").getName(), "2");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0.0"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0.0").getName(), "2");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0.1"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0.1").getName(), "2");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0.2"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0.2").getName(), "2");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0").getName(), "2");
Assertions.assertNull(mrm.get("http://url/ValueSet/234", "4.1"));
mrm.drop("2345"); // vs2;
Assertions.assertEquals(mrm.size(), 0);
Assertions.assertNull(mrm.get("2345"));
Assertions.assertNull(mrm.get("2346"));
Assertions.assertNull(mrm.get("http://url/ValueSet/234"));
Assertions.assertNull(mrm.get("http://url/ValueSet/234", "4.0.0"));
Assertions.assertNull(mrm.get("http://url/ValueSet/234", "4.0.1"));
Assertions.assertNull(mrm.get("http://url/ValueSet/234", "4.0.2"));
Assertions.assertNull(mrm.get("http://url/ValueSet/234", "4.0"));
Assertions.assertNull(mrm.get("http://url/ValueSet/234", "4.1"));
}
@Test
public void testSingleWithVersions1DeferredLoad() {
CanonicalResourceManager<ValueSet> mrm = new CanonicalResourceManager<>(true);
ValueSet vs1 = new ValueSet();
vs1.setId("2345");
vs1.setUrl("http://url/ValueSet/234");
vs1.setVersion("4.0.1");
vs1.setName("1");
DeferredLoadTestResource vs1d = new DeferredLoadTestResource(vs1);
ValueSet vs2 = new ValueSet();
vs2.setId("2346");
vs2.setUrl("http://url/ValueSet/234");
vs2.setVersion("4.0.2");
vs2.setName("2");
DeferredLoadTestResource vs2d = new DeferredLoadTestResource(vs2);
mrm.clear();
mrm.register(vs1d, null);
Assertions.assertEquals(mrm.size(), 1);
Assertions.assertNotNull(mrm.get("2345"));
Assertions.assertEquals(mrm.get("2345").getName(), "1");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234").getName(), "1");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0.0"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0.0").getName(), "1");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0.1"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0.1").getName(), "1");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0.2"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0.2").getName(), "1");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0").getName(), "1");
Assertions.assertNull(mrm.get("http://url/ValueSet/234", "4.1"));
mrm.register(vs2d, null);
Assertions.assertEquals(mrm.size(), 2);
Assertions.assertNotNull(mrm.get("2345"));
Assertions.assertEquals(mrm.get("2345").getName(), "1");
Assertions.assertNotNull(mrm.get("2346"));
Assertions.assertEquals(mrm.get("2346").getName(), "2");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234").getName(), "2");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0.0"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0.0").getName(), "2");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0.1"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0.1").getName(), "1");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0.2"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0.2").getName(), "2");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0").getName(), "2");
Assertions.assertNull(mrm.get("http://url/ValueSet/234", "4.1"));
mrm.drop("2346"); // vs2;
Assertions.assertEquals(mrm.size(), 1);
Assertions.assertNotNull(mrm.get("2345"));
Assertions.assertNull(mrm.get("2346"));
Assertions.assertEquals(mrm.get("2345").getName(), "1");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234").getName(), "1");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0.0"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0.0").getName(), "1");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0.1"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0.1").getName(), "1");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0.2"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0.2").getName(), "1");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0").getName(), "1");
Assertions.assertNull(mrm.get("http://url/ValueSet/234", "4.1"));
}
@Test
public void testSingleWithVersions2DeferredLoad() {
CanonicalResourceManager<ValueSet> mrm = new CanonicalResourceManager<>(true);
ValueSet vs1 = new ValueSet();
vs1.setId("2345");
vs1.setUrl("http://url/ValueSet/234");
vs1.setVersion("4.0.1");
vs1.setName("1");
DeferredLoadTestResource vs1d = new DeferredLoadTestResource(vs1);
ValueSet vs2 = new ValueSet();
vs2.setId("2346");
vs2.setUrl("http://url/ValueSet/234");
vs2.setVersion("4.0.2");
vs2.setName("2");
DeferredLoadTestResource vs2d = new DeferredLoadTestResource(vs2);
mrm.clear();
mrm.register(vs1d, null);
Assertions.assertEquals(mrm.size(), 1);
Assertions.assertNotNull(mrm.get("2345"));
Assertions.assertEquals(mrm.get("2345").getName(), "1");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234").getName(), "1");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0.0"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0.0").getName(), "1");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0.1"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0.1").getName(), "1");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0.2"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0.2").getName(), "1");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0").getName(), "1");
Assertions.assertNull(mrm.get("http://url/ValueSet/234", "4.1"));
mrm.register(vs2d, null);
Assertions.assertEquals(mrm.size(), 2);
Assertions.assertNotNull(mrm.get("2345"));
Assertions.assertEquals(mrm.get("2345").getName(), "1");
Assertions.assertNotNull(mrm.get("2346"));
Assertions.assertEquals(mrm.get("2346").getName(), "2");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234").getName(), "2");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0.0"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0.0").getName(), "2");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0.1"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0.1").getName(), "1");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0.2"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0.2").getName(), "2");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0").getName(), "2");
Assertions.assertNull(mrm.get("http://url/ValueSet/234", "4.1"));
mrm.drop("2345"); // vs1;
Assertions.assertEquals(mrm.size(), 1);
Assertions.assertNull(mrm.get("2345"));
Assertions.assertNotNull(mrm.get("2346"));
Assertions.assertEquals(mrm.get("2346").getName(), "2");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234").getName(), "2");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0.0"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0.0").getName(), "2");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0.1"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0.1").getName(), "2");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0.2"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0.2").getName(), "2");
Assertions.assertNotNull(mrm.get("http://url/ValueSet/234", "4.0"));
Assertions.assertEquals(mrm.get("http://url/ValueSet/234", "4.0").getName(), "2");
Assertions.assertNull(mrm.get("http://url/ValueSet/234", "4.1"));
}
}

View File

@ -72,6 +72,11 @@ public class SnapShotGenerationTests {
return null;
}
@Override
public Resource loadResource(InputStream stream, boolean isJson) throws FHIRException, IOException {
return null;
}
@Override
public String[] getTypes() {
return types;

View File

@ -447,6 +447,10 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple
return loadPackageFromFile(id, version.substring(5));
}
if (version == null && id.contains("#")) {
version = id.substring(id.indexOf("#")+1);
id = id.substring(0, id.indexOf("#"));
}
NpmPackage p = loadPackageFromCacheOnly(id, version);
if (p != null) {
if ("current".equals(version)) {

View File

@ -61,6 +61,7 @@ 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.cache.NpmPackage.PackageResourceInformationSorter;
import org.hl7.fhir.utilities.cache.PackageGenerator.PackageType;
import org.hl7.fhir.utilities.json.JSONUtil;
import org.hl7.fhir.utilities.json.JsonTrackingParser;
@ -82,6 +83,50 @@ import com.google.gson.JsonObject;
*/
public class NpmPackage {
public class PackageResourceInformationSorter implements Comparator<PackageResourceInformation> {
@Override
public int compare(PackageResourceInformation o1, PackageResourceInformation o2) {
return o1.filename.compareTo(o2.filename);
}
}
public class PackageResourceInformation {
private String id;
private String type;
private String url;
private String version;
private String filename;
private String supplements;
public PackageResourceInformation(String root, JsonObject fi) throws IOException {
super();
id = JSONUtil.str(fi, "id");
type = JSONUtil.str(fi, "resourceType");
url = JSONUtil.str(fi, "url");
version = JSONUtil.str(fi, "version");
filename = Utilities.path(root, JSONUtil.str(fi, "filename"));
supplements = JSONUtil.str(fi, "supplements");
}
public String getId() {
return id;
}
public String getType() {
return type;
}
public String getUrl() {
return url;
}
public String getVersion() {
return version;
}
public String getFilename() {
return filename;
}
public String getSupplements() {
return supplements;
}
}
public class IndexVersionSorter implements Comparator<JsonObject> {
@Override
@ -489,6 +534,19 @@ public class NpmPackage {
return res;
}
public List<PackageResourceInformation> listIndexedResources(String... types) throws IOException {
List<PackageResourceInformation> res = new ArrayList<PackageResourceInformation>();
NpmPackageFolder folder = folders.get("package");
for (JsonElement e : folder.index.getAsJsonArray("files")) {
JsonObject fi = e.getAsJsonObject();
if (Utilities.existsInList(JSONUtil.str(fi, "resourceType"), types)) {
res.add(new PackageResourceInformation(folder.folder.getAbsolutePath(), fi));
}
}
// Collections.sort(res, new PackageResourceInformationSorter());
return res;
}
/**
* use the name from listResources()
*

View File

@ -44,16 +44,24 @@ public class NpmPackageIndexBuilder {
files.add(fi);
fi.addProperty("filename", name);
fi.addProperty("resourceType", json.get("resourceType").getAsString());
if (json.has("id") && json.get("id").isJsonPrimitive())
if (json.has("id") && json.get("id").isJsonPrimitive()) {
fi.addProperty("id", json.get("id").getAsString());
if (json.has("url") && json.get("url").isJsonPrimitive())
}
if (json.has("url") && json.get("url").isJsonPrimitive()) {
fi.addProperty("url", json.get("url").getAsString());
if (json.has("version") && json.get("version").isJsonPrimitive())
}
if (json.has("version") && json.get("version").isJsonPrimitive()) {
fi.addProperty("version", json.get("version").getAsString());
if (json.has("kind") && json.get("kind").isJsonPrimitive())
}
if (json.has("kind") && json.get("kind").isJsonPrimitive()) {
fi.addProperty("kind", json.get("kind").getAsString());
if (json.has("type") && json.get("type").isJsonPrimitive())
}
if (json.has("type") && json.get("type").isJsonPrimitive()) {
fi.addProperty("type", json.get("type").getAsString());
}
if (json.has("supplements") && json.get("supplements").isJsonPrimitive()) {
fi.addProperty("supplements", json.get("supplements").getAsString());
}
}
} catch (Exception e) {
System.out.println("Error parsing "+name+": "+e.getMessage());

View File

@ -6,6 +6,7 @@ import org.hl7.fhir.convertors.loaders.R2016MayToR5Loader;
import org.hl7.fhir.convertors.loaders.R2ToR5Loader;
import org.hl7.fhir.convertors.loaders.R3ToR5Loader;
import org.hl7.fhir.convertors.loaders.R4ToR5Loader;
import org.hl7.fhir.convertors.loaders.R5ToR5Loader;
import org.hl7.fhir.convertors.txClient.TerminologyClientFactory;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
@ -38,6 +39,7 @@ import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.utilities.cache.NpmPackage;
import org.hl7.fhir.utilities.cache.PackageClient;
import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager;
import org.hl7.fhir.utilities.cache.ToolsVersion;
import org.hl7.fhir.utilities.i18n.I18nBase;
@ -368,18 +370,32 @@ public class ValidationEngine implements IValidatorResourceFetcher {
}
private void loadCoreDefinitions(String src, boolean recursive) throws Exception {
Map<String, byte[]> source = loadIgSource(src, recursive, true);
if (version == null)
version = getVersionFromPack(source);
context = SimpleWorkerContext.fromDefinitions(source, loaderForVersion(), new PackageVersion(src));
if (pcm == null) {
pcm = new FilesystemPackageCacheManager(true, ToolsVersion.TOOLS_VERSION);
}
NpmPackage npm = pcm.loadPackage(src, null);
if (npm != null) {
version = npm.fhirVersion();
context = SimpleWorkerContext.fromPackage(npm, loaderForVersion());
} else {
Map<String, byte[]> source = loadIgSource(src, recursive, true);
if (version == null) {
version = getVersionFromPack(source);
}
context = SimpleWorkerContext.fromDefinitions(source, loaderForVersion(), new PackageVersion(src));
grabNatives(source, "http://hl7.org/fhir");
}
context.setAllowLoadingDuplicates(true); // because of Forge
context.setExpansionProfile(makeExpProfile());
NpmPackage npm = pcm.loadPackage("hl7.fhir.xver-extensions", "0.0.4");
context.loadFromPackage(npm, null);
grabNatives(source, "http://hl7.org/fhir");
NpmPackage npmX = pcm.loadPackage("hl7.fhir.xver-extensions", "0.0.4");
context.loadFromPackage(npmX, null);
}
private IContextResourceLoader loaderForVersion() {
return loaderForVersion(version);
}
private IContextResourceLoader loaderForVersion(String version) {
if (Utilities.noString(version))
return null;
if (version.startsWith("1.0"))
@ -390,6 +406,8 @@ public class ValidationEngine implements IValidatorResourceFetcher {
return new R3ToR5Loader(new String[] { "CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire","ConceptMap","StructureMap", "NamingSystem"});
if (version.startsWith("4.0"))
return new R4ToR5Loader(new String[] { "CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire","ConceptMap","StructureMap", "NamingSystem"});
if (version.startsWith("5.0"))
return new R5ToR5Loader(new String[] { "CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire","ConceptMap","StructureMap", "NamingSystem"});
return null;
}
@ -752,34 +770,39 @@ public class ValidationEngine implements IValidatorResourceFetcher {
}
public void loadIg(String src, boolean recursive) throws IOException, FHIRException, Exception {
String canonical = null;
Map<String, byte[]> source = loadIgSource(src, recursive, true);
String version = Constants.VERSION;
if (this.version != null)
version = this.version;
if (source.containsKey("version.info"))
version = readInfoVersion(source.get("version.info"));
for (Entry<String, byte[]> t : source.entrySet()) {
String fn = t.getKey();
if (!exemptFile(fn)) {
Resource r = loadFileWithErrorChecking(version, t, fn);
if (r != null) {
context.cacheResource(r);
if (r instanceof ImplementationGuide) {
canonical = ((ImplementationGuide) r).getUrl();
igs.add((ImplementationGuide) r);
if (canonical.contains("/ImplementationGuide/")) {
Resource r2 = r.copy();
((ImplementationGuide) r2).setUrl(canonical.substring(0, canonical.indexOf("/ImplementationGuide/")));
context.cacheResource(r2);
NpmPackage npm = pcm.loadPackage(src, null);
if (npm != null) {
context.loadFromPackage(npm, loaderForVersion(npm.fhirVersion()));
} else {
String canonical = null;
Map<String, byte[]> source = loadIgSource(src, recursive, true);
String version = Constants.VERSION;
if (this.version != null)
version = this.version;
if (source.containsKey("version.info"))
version = readInfoVersion(source.get("version.info"));
for (Entry<String, byte[]> t : source.entrySet()) {
String fn = t.getKey();
if (!exemptFile(fn)) {
Resource r = loadFileWithErrorChecking(version, t, fn);
if (r != null) {
context.cacheResource(r);
if (r instanceof ImplementationGuide) {
canonical = ((ImplementationGuide) r).getUrl();
igs.add((ImplementationGuide) r);
if (canonical.contains("/ImplementationGuide/")) {
Resource r2 = r.copy();
((ImplementationGuide) r2).setUrl(canonical.substring(0, canonical.indexOf("/ImplementationGuide/")));
context.cacheResource(r2);
}
}
}
}
}
}
if (canonical != null) {
grabNatives(source, canonical);
if (canonical != null) {
grabNatives(source, canonical);
}
}
}