Merge pull request #1440 from hapifhir/2023-09-gg-type-performance

2023 09 gg type performance
This commit is contained in:
Grahame Grieve 2023-09-20 16:52:40 +10:00 committed by GitHub
commit d2dfce22f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
47 changed files with 601 additions and 345 deletions

View File

@ -135,22 +135,24 @@ public class PackageVisitor {
System.out.println("Go: "+pidList.size()+" published packages");
i = 0;
for (String pid : pidList) {
if (!cpidSet.contains(pid)) {
cpidSet.add(pid);
List<String> vList = listVersions(pid);
if (oldVersions) {
for (String v : vList) {
processPackage(pid, v, i, pidList.size());
for (String pid : pidList) {
if (pid != null) {
if (!cpidSet.contains(pid)) {
cpidSet.add(pid);
List<String> vList = listVersions(pid);
if (oldVersions) {
for (String v : vList) {
processPackage(pid, v, i, pidList.size());
}
} else if (vList.isEmpty()) {
System.out.println("No Packages for "+pid);
} else {
processPackage(pid, vList.get(vList.size() - 1), i, pidList.size());
}
} else if (vList.isEmpty()) {
System.out.println("No Packages for "+pid);
} else {
processPackage(pid, vList.get(vList.size() - 1), i, pidList.size());
}
}
i++;
}
i++;
}
}
JsonObject json = JsonParser.parseObjectFromUrl("https://raw.githubusercontent.com/FHIR/ig-registry/master/fhir-ig-list.json");
i = 0;
List<JsonObject> objects = json.getJsonObjects("guides");
@ -192,8 +194,8 @@ public class PackageVisitor {
long ms2 = System.currentTimeMillis();
if (corePackages || !corePackage(npm)) {
int c = 0;
if (fv != null && (versions.isEmpty() || versions.contains(fv))) {
int c = 0;
for (String type : resourceTypes) {
for (String s : npm.listResources(type)) {
c++;
@ -205,8 +207,10 @@ public class PackageVisitor {
}
}
}
}
System.out.println("Processed: "+pid+"#current: "+c+" resources ("+i+" of "+t+", "+(ms2-ms1)+"/"+(System.currentTimeMillis()-ms2)+"ms)");
System.out.println("Processed: "+pid+"#current: "+c+" resources ("+i+" of "+t+", "+(ms2-ms1)+"/"+(System.currentTimeMillis()-ms2)+"ms)");
} else {
System.out.println("Ignored: "+pid+"#current: no version");
}
}
} catch (Exception e) {
System.out.println("Unable to process: "+pid+"#current: "+e.getMessage());
@ -262,7 +266,7 @@ public class PackageVisitor {
for (Element channel : XMLUtil.getNamedChildren(xml.getDocumentElement(), "channel")) {
for (Element item : XMLUtil.getNamedChildren(channel, "item")) {
String pid = XMLUtil.getNamedChildText(item, "title");
if (pid.contains("#")) {
if (pid != null && pid.contains("#")) {
list.add(pid.substring(0, pid.indexOf("#")));
}
}

View File

@ -88,9 +88,11 @@ public class TerminologyClientR4 implements ITerminologyClient {
vs2 = client.expandValueset(vs2, p2, params); // todo: second parameter
return (ValueSet) VersionConvertorFactory_40_50.convertResource(vs2);
} catch (org.hl7.fhir.r4.utils.client.EFhirClientException e) {
throw new org.hl7.fhir.r5.utils.client.EFhirClientException(e.getMessage(),
(org.hl7.fhir.r5.model.OperationOutcome) VersionConvertorFactory_40_50.convertResource(e.getServerErrors().get(0)));
if (e.getServerErrors().size() > 0) {
throw new org.hl7.fhir.r5.utils.client.EFhirClientException(e.getMessage(), (org.hl7.fhir.r5.model.OperationOutcome) VersionConvertorFactory_40_50.convertResource(e.getServerErrors().get(0)));
} else {
throw new org.hl7.fhir.r5.utils.client.EFhirClientException(e.getMessage());
}
}
}
@ -165,7 +167,8 @@ public class TerminologyClientR4 implements ITerminologyClient {
@Override
public Bundle validateBatch(Bundle batch) {
return (Bundle) VersionConvertorFactory_40_50.convertResource(client.transaction((org.hl7.fhir.r4.model.Bundle) VersionConvertorFactory_40_50.convertResource(batch)));
org.hl7.fhir.r4.model.Bundle result = client.transaction((org.hl7.fhir.r4.model.Bundle) VersionConvertorFactory_40_50.convertResource(batch));
return result == null ? null : (Bundle) VersionConvertorFactory_40_50.convertResource(result);
}
@Override

View File

@ -449,8 +449,14 @@ public class FHIRToolingClient {
throw new EFhirClientException("Server returned error code " + result.getHttpStatus(),
(OperationOutcome) result.getPayload());
}
} catch (IOException e) {
throw new FHIRException(e);
} catch (EFhirClientException e) {
if (e.getServerErrors().size() > 0) {
throw new EFhirClientException(e.getMessage(), e.getServerErrors().get(0));
} else {
throw new EFhirClientException(e.getMessage(), e);
}
} catch (Exception e) {
throw new EFhirClientException(e.getMessage(), e);
}
return result == null ? null : (ValueSet) result.getPayload();
}

View File

@ -273,7 +273,12 @@ public class FhirRequestBuilder {
}
if (error != null) {
throw new EFhirClientException("Error from server: " + ResourceUtilities.getErrorDescription(error), error);
String s = ResourceUtilities.getErrorDescription(error);
System.out.println(s);
if (s.startsWith("Unable to find value set")) {
System.out.println("!");
}
throw new EFhirClientException("Error from "+source+": " + ResourceUtilities.getErrorDescription(error), error);
}
return resource;

View File

@ -180,6 +180,9 @@ public class ComparisonSession {
}
private VersionComparisonAnnotation getAnnotation(Base b) {
if (b == null) {
return null;
}
if (b.hasUserData(VersionComparisonAnnotation.USER_DATA_NAME)) {
return (VersionComparisonAnnotation) b.getUserData(VersionComparisonAnnotation.USER_DATA_NAME);
} else {
@ -203,8 +206,14 @@ public class ComparisonSession {
public void markDeleted(Base parent, String name, Base other) {
if (isAnnotate() && other != null) {
getAnnotation(parent).deleted(name, other);
getAnnotation(other).deleted();
VersionComparisonAnnotation annotation = getAnnotation(parent);
if (annotation != null) {
annotation.deleted(name, other);
}
annotation = getAnnotation(other);
if (annotation != null) {
annotation.deleted();
}
}
}

View File

@ -3431,7 +3431,8 @@ public class ProfileUtilities extends TranslatingUtilities {
private void compareDiffs(List<ElementDefinition> diffList, List<ElementDefinition> newDiff, List<String> errors) {
if (diffList.size() != newDiff.size()) {
errors.add("The diff list size changed when sorting - was "+diffList.size()+" is now "+newDiff.size());
errors.add("The diff list size changed when sorting - was "+diffList.size()+" is now "+newDiff.size()+
" ["+CommaSeparatedStringBuilder.buildObjects(diffList)+"]/["+CommaSeparatedStringBuilder.buildObjects(newDiff)+"]");
} else {
for (int i = 0; i < Integer.min(diffList.size(), newDiff.size()); i++) {
ElementDefinition e = diffList.get(i);

View File

@ -124,6 +124,7 @@ import org.hl7.fhir.r5.terminologies.client.TerminologyClientContext;
import org.hl7.fhir.r5.utils.PackageHackerR5;
import org.hl7.fhir.r5.utils.ResourceUtilities;
import org.hl7.fhir.r5.utils.ToolingExtensions;
import org.hl7.fhir.r5.utils.client.EFhirClientException;
import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier;
import org.hl7.fhir.utilities.TimeTracker;
import org.hl7.fhir.utilities.ToolingClientLogger;
@ -141,7 +142,7 @@ import com.google.gson.JsonObject;
import javax.annotation.Nonnull;
public abstract class BaseWorkerContext extends I18nBase implements IWorkerContext{
public abstract class BaseWorkerContext extends I18nBase implements IWorkerContext {
private static final boolean QA_CHECK_REFERENCE_SOURCE = false; // see comments below
@ -223,6 +224,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
private CanonicalResourceManager<ConceptMap> maps = new CanonicalResourceManager<ConceptMap>(false, minimalMemory);
protected CanonicalResourceManager<StructureMap> transforms = new CanonicalResourceManager<StructureMap>(false, minimalMemory);
private CanonicalResourceManager<StructureDefinition> structures = new CanonicalResourceManager<StructureDefinition>(false, minimalMemory);
private TypeManager typeManager = new TypeManager(structures);
private final CanonicalResourceManager<Measure> measures = new CanonicalResourceManager<Measure>(false, minimalMemory);
private final CanonicalResourceManager<Library> libraries = new CanonicalResourceManager<Library>(false, minimalMemory);
private CanonicalResourceManager<ImplementationGuide> guides = new CanonicalResourceManager<ImplementationGuide>(false, minimalMemory);
@ -279,6 +281,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
this.valueSets = valueSets;
this.maps = maps;
this.structures = profiles;
this.typeManager = new TypeManager(structures);
this.guides = guides;
clock = new TimeTracker();
}
@ -292,6 +295,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
maps.copy(other.maps);
transforms.copy(other.transforms);
structures.copy(other.structures);
typeManager = new TypeManager(structures);
searchParameters.copy(other.searchParameters);
plans.copy(other.plans);
questionnaires.copy(other.questionnaires);
@ -370,6 +374,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
fixOldSD(sd);
}
structures.register(r, packageInfo);
typeManager.see(r);
break;
case "ValueSet":
valueSets.register(r, packageInfo);
@ -462,6 +467,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
fixOldSD(sd);
}
structures.see(sd, packageInfo);
typeManager.see(sd);
} else if (r instanceof ValueSet) {
valueSets.see((ValueSet) m, packageInfo);
} else if (r instanceof CodeSystem) {
@ -775,17 +781,21 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
}
if (noTerminologyServer) {
return new ValueSetExpansionOutcome(formatMessage(I18nConstants.ERROR_EXPANDING_VALUESET_RUNNING_WITHOUT_TERMINOLOGY_SERVICES), TerminologyServiceErrorClass.NOSERVICE);
return new ValueSetExpansionOutcome(formatMessage(I18nConstants.ERROR_EXPANDING_VALUESET_RUNNING_WITHOUT_TERMINOLOGY_SERVICES), TerminologyServiceErrorClass.NOSERVICE, false);
}
Map<String, String> params = new HashMap<String, String>();
params.put("_limit", Integer.toString(expandCodesLimit ));
params.put("_incomplete", "true");
txLog("$expand on "+txCache.summary(vs));
if (addDependentResources(p, vs)) {
p.addParameter().setName("cache-id").setValue(new IdType(tcc.getCacheId()));
}
try {
ValueSet result = tcc.getClient().expandValueset(vs, p, params);
res = new ValueSetExpansionOutcome(result).setTxLink(txLog.getLastId());
} catch (Exception e) {
res = new ValueSetExpansionOutcome(e.getMessage() == null ? e.getClass().getName() : e.getMessage(), TerminologyServiceErrorClass.UNKNOWN);
res = new ValueSetExpansionOutcome(e.getMessage() == null ? e.getClass().getName() : e.getMessage(), TerminologyServiceErrorClass.UNKNOWN, true);
if (txLog != null) {
res.setTxLink(txLog.getLastId());
}
@ -815,7 +825,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
throw new Error(formatMessage(I18nConstants.NO_PARAMETERS_PROVIDED_TO_EXPANDVS));
}
if (vs.getUrl().equals("http://hl7.org/fhir/ValueSet/all-time-units") || vs.getUrl().equals("http://hl7.org/fhir/ValueSet/all-distance-units")) {
return new ValueSetExpansionOutcome("This value set is not expanded correctly at this time (will be fixed in a future version)", TerminologyServiceErrorClass.VALUESET_UNSUPPORTED);
return new ValueSetExpansionOutcome("This value set is not expanded correctly at this time (will be fixed in a future version)", TerminologyServiceErrorClass.VALUESET_UNSUPPORTED, false);
}
Parameters p = pIn.copy();
@ -857,7 +867,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
} catch (Exception e) {
allErrors.addAll(vse.getAllErrors());
e.printStackTrace();
res = new ValueSetExpansionOutcome(e.getMessage(), TerminologyServiceErrorClass.UNKNOWN);
res = new ValueSetExpansionOutcome(e.getMessage(), TerminologyServiceErrorClass.UNKNOWN, e instanceof EFhirClientException);
}
allErrors.addAll(vse.getAllErrors());
if (res.getValueset() != null) {
@ -868,17 +878,17 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
return res;
}
if (res.getErrorClass() == TerminologyServiceErrorClass.INTERNAL_ERROR || isNoTerminologyServer()) { // this class is created specifically to say: don't consult the server
return new ValueSetExpansionOutcome(res.getError(), res.getErrorClass());
return new ValueSetExpansionOutcome(res.getError(), res.getErrorClass(), false);
}
// if that failed, we try to expand on the server
if (addDependentResources(p, vs)) {
p.addParameter().setName("cache-id").setValue(new IdType(tcc.getCacheId()));
}
if (noTerminologyServer) {
return new ValueSetExpansionOutcome(formatMessage(I18nConstants.ERROR_EXPANDING_VALUESET_RUNNING_WITHOUT_TERMINOLOGY_SERVICES), TerminologyServiceErrorClass.NOSERVICE, allErrors);
return new ValueSetExpansionOutcome(formatMessage(I18nConstants.ERROR_EXPANDING_VALUESET_RUNNING_WITHOUT_TERMINOLOGY_SERVICES), TerminologyServiceErrorClass.NOSERVICE, allErrors, false);
}
p.addParameter().setName("cache-id").setValue(new IdType(tcc.getCacheId()));
addDependentResources(p, vs);
Map<String, String> params = new HashMap<String, String>();
params.put("_limit", Integer.toString(expandCodesLimit ));
params.put("_incomplete", "true");
@ -893,7 +903,11 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
}
res = new ValueSetExpansionOutcome(result).setTxLink(txLog.getLastId());
} catch (Exception e) {
res = new ValueSetExpansionOutcome((e.getMessage() == null ? e.getClass().getName() : e.getMessage()), TerminologyServiceErrorClass.UNKNOWN, allErrors).setTxLink(txLog == null ? null : txLog.getLastId());
if (res != null && !res.isFromServer()) {
res = new ValueSetExpansionOutcome(res.getError()+" (and "+e.getMessage()+")", res.getErrorClass(), false);
} else {
res = new ValueSetExpansionOutcome((e.getMessage() == null ? e.getClass().getName() : e.getMessage()), TerminologyServiceErrorClass.UNKNOWN, allErrors, true).setTxLink(txLog == null ? null : txLog.getLastId());
}
}
txCache.cacheExpansion(cacheToken, res, TerminologyCache.PERMANENT);
return res;
@ -1278,10 +1292,8 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
p.setParameter("includeDefinition", false);
p.setParameter("excludeNested", !hierarchical);
boolean cached = addDependentResources(p, vs);
if (cached) {
p.addParameter().setName("cache-id").setValue(new IdType(tcc.getCacheId()));
}
addDependentResources(p, vs);
p.addParameter().setName("cache-id").setValue(new IdType(tcc.getCacheId()));
return p;
}
@ -1475,9 +1487,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
cache = true;
addDependentResources(pin, vs);
}
if (cache) {
pin.addParameter().setName("cache-id").setValue(new IdType(tcc.getCacheId()));
}
pin.addParameter().setName("cache-id").setValue(new IdType(tcc.getCacheId()));
for (ParametersParameterComponent pp : pin.getParameter()) {
if (pp.getName().equals("profile")) {
throw new Error(formatMessage(I18nConstants.CAN_ONLY_SPECIFY_PROFILE_IN_THE_CONTEXT));
@ -2337,6 +2347,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
if (fhirType.equals("StructureDefinition")) {
structures.drop(id);
typeManager.reload();
} else if (fhirType.equals("ImplementationGuide")) {
guides.drop(id);
} else if (fhirType.equals("CapabilityStatement")) {
@ -2463,34 +2474,23 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
if (Utilities.isAbsoluteUrl(typeName)) {
return fetchResource(StructureDefinition.class, typeName);
} else {
Set<StructureDefinition> types = new HashSet<>();
types.addAll(fetchTypeDefinitions(typeName));
types.removeIf(sd -> sd.getDerivation() == TypeDerivationRule.CONSTRAINT);
if (types.size() == 0) {
return null; // throw new FHIRException("Unresolved type "+typeName+" (0)");
} else if (types.size() == 1) {
return types.iterator().next();
} else {
types.removeIf(sd -> !sd.getUrl().startsWith("http://hl7.org/fhir/StructureDefinition/"));
if (types.size() == 0) {
return null;
} else if (types.size() != 1) {
throw new FHIRException("Ambiguous type "+typeName+" ("+types.toString()+") (contact Grahame Grieve for investigation)");
} else {
return types.iterator().next();
}
}
return typeManager.fetchTypeDefinition(typeName);
}
}
@Override
public List<StructureDefinition> fetchTypeDefinitions(String typeName) {
List<StructureDefinition> res = new ArrayList<>();
structures.listAll(res);
res.removeIf(sd -> !sd.hasType() || !(sd.getType().equals(typeName) || sd.getTypeTail().equals(typeName)));
return res;
return typeManager.getDefinitions(typeName);
}
public boolean isPrimitiveType(String type) {
return typeManager.isPrimitive(type);
}
public boolean isDataType(String type) {
return typeManager.isDataType(type);
}
public boolean isTlogging() {
return tlogging;
}
@ -2627,6 +2627,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
maps.setVersion(version);
transforms.setVersion(version);
structures.setVersion(version);
typeManager.reload();
measures.setVersion(version);
libraries.setVersion(version);
guides.setVersion(version);

View File

@ -31,10 +31,11 @@ public class CanonicalResourceManager<T extends CanonicalResource> {
private String url;
private String version;
private String supplements;
private String derivation;
private CanonicalResource resource;
private boolean hacked;
public CanonicalResourceProxy(String type, String id, String url, String version, String supplements) {
public CanonicalResourceProxy(String type, String id, String url, String version, String supplements, String derivation) {
super();
this.type = type;
this.id = id;
@ -75,6 +76,14 @@ public class CanonicalResourceManager<T extends CanonicalResource> {
return supplements;
}
public String getDerivation() {
return derivation;
}
public void setDerivation(String derivation) {
this.derivation = derivation;
}
public CanonicalResource getResource() throws FHIRException {
if (resource == null) {
resource = loadResource();

View File

@ -310,8 +310,7 @@ public class ContextUtilities implements ProfileKnowledgeProvider {
@Override
public boolean isPrimitiveType(String type) {
StructureDefinition sd = context.fetchTypeDefinition(type);
return sd != null && sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE;
return context.isPrimitiveType(type);
}
@Override
@ -364,11 +363,6 @@ public class ContextUtilities implements ProfileKnowledgeProvider {
return false;
}
public boolean isPrimitiveDatatype(String type) {
StructureDefinition sd = context.fetchTypeDefinition(type);
return sd != null && sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE;
}
public StructureDefinition fetchByJsonName(String key) {
for (StructureDefinition sd : context.fetchResourcesByType(StructureDefinition.class)) {
ElementDefinition ed = sd.getSnapshot().getElementFirstRep();

View File

@ -938,7 +938,20 @@ public interface IWorkerContext {
*/
public List<StructureDefinition> fetchTypeDefinitions(String n);
/**
* return whether type is primitive type. This is called a lot, and needs a high performance implementation
* @param type
* @return
*/
public boolean isPrimitiveType(String type);
/**
* return whether type is data type. This is called a lot, and needs a high performance implementation
* @param type
* @return
*/
public boolean isDataType(String type);
/**
* Returns a set of keys that can be used to get binaries from this context.
* The binaries come from the loaded packages (mostly the pubpack)
@ -1020,4 +1033,6 @@ public interface IWorkerContext {
public boolean isForPublication();
public void setForPublication(boolean value);
}

View File

@ -99,7 +99,7 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
private final IContextResourceLoader loader;
public PackageResourceLoader(PackageResourceInformation pri, IContextResourceLoader loader) {
super(pri.getResourceType(), pri.getId(), loader == null ? pri.getUrl() :loader.patchUrl(pri.getUrl(), pri.getResourceType()), pri.getVersion(), pri.getSupplements());
super(pri.getResourceType(), pri.getId(), loader == null ? pri.getUrl() :loader.patchUrl(pri.getUrl(), pri.getResourceType()), pri.getVersion(), pri.getSupplements(), pri.getDerivation());
this.filename = pri.getFilename();
this.loader = loader;
}

View File

@ -530,6 +530,8 @@ public class TerminologyCache {
sw.write(BREAK+"\r\n");
if (ce.e != null) {
sw.write("e: {\r\n");
if (ce.e.isFromServer())
sw.write(" \"from-server\" : true,\r\n");
if (ce.e.getValueset() != null)
sw.write(" \"valueSet\" : "+json.composeString(ce.e.getValueset()).trim()+",\r\n");
sw.write(" \"error\" : \""+Utilities.escapeJson(ce.e.getError()).trim()+"\"\r\n}\r\n");
@ -623,9 +625,9 @@ public class TerminologyCache {
String error = loadJS(o.get("error"));
if (e) {
if (o.has("valueSet"))
ce.e = new ValueSetExpansionOutcome((ValueSet) new JsonParser().parse(o.getAsJsonObject("valueSet")), error, TerminologyServiceErrorClass.UNKNOWN);
ce.e = new ValueSetExpansionOutcome((ValueSet) new JsonParser().parse(o.getAsJsonObject("valueSet")), error, TerminologyServiceErrorClass.UNKNOWN, o.has("from-server"));
else
ce.e = new ValueSetExpansionOutcome(error, TerminologyServiceErrorClass.UNKNOWN);
ce.e = new ValueSetExpansionOutcome(error, TerminologyServiceErrorClass.UNKNOWN, o.has("from-server"));
} else {
String t = loadJS(o.get("severity"));
IssueSeverity severity = t == null ? null : IssueSeverity.fromCode(t);

View File

@ -0,0 +1,119 @@
package org.hl7.fhir.r5.context;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r5.context.CanonicalResourceManager.CanonicalResourceProxy;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind;
import org.hl7.fhir.r5.model.StructureDefinition.TypeDerivationRule;
import org.hl7.fhir.utilities.Utilities;
public class TypeManager {
private CanonicalResourceManager<StructureDefinition> structures;
private Map<String, Set<StructureDefinition>> typeDefinitions = new HashMap<>();
private Map<String, Set<StructureDefinition>> fhirTypeDefinitions = new HashMap<>();
private Set<String> primitiveNames = new HashSet<>();
private Set<String> dataTypeNames = new HashSet<>();
public TypeManager(CanonicalResourceManager<StructureDefinition> structures) {
super();
this.structures = structures;
reload();
}
public void reload() {
typeDefinitions.clear();
primitiveNames.clear();
dataTypeNames.clear();
for (StructureDefinition sd : structures.getList()) {
see(sd);
}
}
public void see(CanonicalResourceProxy r) {
if (!"constraint".equals(r.getDerivation())) {
see((StructureDefinition) r.getResource());
}
}
public void see(StructureDefinition sd) {
if (sd.getDerivation() != TypeDerivationRule.CONSTRAINT) {
String type = sd.getType();
Set<StructureDefinition> types = typeDefinitions.get(type);
if (types == null) {
types = new HashSet<>();
typeDefinitions.put(type, types);
}
types.add(sd);
if (sd.getUrl().startsWith("http://hl7.org/fhir/StructureDefinition/")) {
types = fhirTypeDefinitions.get(type);
if (types == null) {
types = new HashSet<>();
fhirTypeDefinitions.put(type, types);
}
types.add(sd);
}
if (sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE) {
primitiveNames.add(sd.getType());
} else if (sd.getKind() == StructureDefinitionKind.COMPLEXTYPE) {
dataTypeNames.add(sd.getType());
}
}
}
public List<StructureDefinition> getDefinitions(String typeName) {
List<StructureDefinition> list = new ArrayList<>();
Set<StructureDefinition> defined = typeDefinitions.get(typeName);
if (defined != null) {
list.addAll(defined);
}
return list;
}
public StructureDefinition fetchTypeDefinition(String typeName) {
Set<StructureDefinition> types = typeDefinitions.get(typeName);
if (types == null) {
return null; // throw new FHIRException("Unresolved type "+typeName+" (0)");
} else if (types.size() == 1) {
return types.iterator().next();
} else {
types = fhirTypeDefinitions.get(typeName);
if (types == null) {
return null;
} else if (types.size() != 1) {
throw new FHIRException("Ambiguous type "+typeName+" ("+types.toString()+") (contact Grahame Grieve for investigation)");
} else {
return types.iterator().next();
}
}
}
public boolean isPrimitive(String type) {
if (primitiveNames.contains(type) || Utilities.existsInList(type, "boolean", "integer", "integer64", "string", "decimal", "uri", "base64Binary", "instant", "date", "dateTime", "time", "code", "oid", "id", "markdown", "unsignedInt", "positiveInt", "uuid", "xhtml", "url", "canonical")) {
return true;
} else {
StructureDefinition sd = structures.get(type);
return sd != null && sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE;
}
}
public boolean isDataType(String type) {
if (dataTypeNames.contains(type) || Utilities.existsInList(type, "Address", "Age", "Annotation", "Attachment", "CodeableConcept", "Coding", "ContactPoint", "Count", "Distance", "Duration", "HumanName", "Identifier", "Money", "Period", "Quantity", "Range", "Ratio", "Reference", "SampledData", "Signature", "Timing",
"ContactDetail", "Contributor", "DataRequirement", "Expression", "ParameterDefinition", "RelatedArtifact", "TriggerDefinition", "UsageContext")) {
return true;
} else {
StructureDefinition sd = structures.get(type);
return sd != null && sd.getKind() == StructureDefinitionKind.COMPLEXTYPE;
}
}
}

View File

@ -556,7 +556,7 @@ public class Element extends Base {
return ne;
} else if (p.getDefinition().isChoice() && name.startsWith(p.getName().replace("[x]", ""))) {
String type = name.substring(p.getName().length()-3);
if (new ContextUtilities(property.getContext()).isPrimitiveDatatype(Utilities.uncapitalize(type))) {
if (property.getContext().isPrimitiveType(Utilities.uncapitalize(type))) {
type = Utilities.uncapitalize(type);
}
Element ne = new Element(name, p);
@ -1335,7 +1335,7 @@ public class Element extends Base {
for (Property p : property.getChildProperties(this.name, type)) {
if (p.getName().equals(name)) {
if (!p.isList()) {
if (!p.isList() && hasChild(name)) {
throw new Error(name+" on "+this.name+" is not a list, so can't add an element");
}
Element ne = new Element(name, p);

View File

@ -45,12 +45,12 @@ public class FmlParser extends ParserBase {
}
@Override
public List<NamedElement> parse(InputStream inStream) throws IOException, FHIRFormatError, DefinitionException, FHIRException {
public List<ValidatedFragment> parse(InputStream inStream) throws IOException, FHIRFormatError, DefinitionException, FHIRException {
byte[] content = TextFile.streamToBytes(inStream);
ByteArrayInputStream stream = new ByteArrayInputStream(content);
String text = TextFile.streamToString(stream);
List<NamedElement> result = new ArrayList<>();
NamedElement ctxt = new NamedElement("focus", "fml", content);
List<ValidatedFragment> result = new ArrayList<>();
ValidatedFragment ctxt = new ValidatedFragment("focus", "fml", content);
ctxt.setElement(parse(ctxt.getErrors(), text));
result.add(ctxt);
return result;
@ -571,7 +571,9 @@ public class FmlParser extends ParserBase {
private void parseParameter(Element ref, FHIRLexer lexer) throws FHIRLexerException, FHIRFormatError {
boolean r5 = VersionUtilities.isR5Plus(context.getVersion());
String name = r5 ? "parameter" : "variable";
if (!lexer.isConstant()) {
if (ref.hasChildren(name) && !ref.getChildByName(name).isList()) {
throw lexer.error("variable on target is not a list, so can't add an element");
} else if (!lexer.isConstant()) {
ref.addElement(name).markLocation(lexer.getCurrentLocation()).makeElement(r5 ? "valueId" : "value").setValue(lexer.take());
} else if (lexer.isStringConstant())
ref.addElement(name).markLocation(lexer.getCurrentLocation()).makeElement(r5 ? "valueString" : "value").setValue(lexer.readConstant("??"));

View File

@ -52,7 +52,6 @@ import org.hl7.fhir.r5.conformance.profile.ProfileUtilities;
import org.hl7.fhir.r5.context.ContextUtilities;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.elementmodel.Element.SpecialElement;
import org.hl7.fhir.r5.elementmodel.ParserBase.NamedElement;
import org.hl7.fhir.r5.formats.IParser.OutputStyle;
import org.hl7.fhir.r5.formats.JsonCreator;
import org.hl7.fhir.r5.formats.JsonCreatorCanonical;
@ -120,10 +119,10 @@ public class JsonParser extends ParserBase {
@Override
public List<NamedElement> parse(InputStream inStream) throws IOException, FHIRException {
long start = System.currentTimeMillis();
public List<ValidatedFragment> parse(InputStream inStream) throws IOException, FHIRException {
// long start = System.currentTimeMillis();
byte[] content = TextFile.streamToBytes(inStream);
NamedElement ctxt = new NamedElement("focus", "json", content);
ValidatedFragment ctxt = new ValidatedFragment("focus", "json", content);
ByteArrayInputStream stream = new ByteArrayInputStream(content);
@ -141,16 +140,21 @@ public class JsonParser extends ParserBase {
obj = org.hl7.fhir.utilities.json.parser.JsonParser.parseObject(source, true, true);
}
ctxt.setElement(parse(ctxt.getErrors(), obj));
List<NamedElement> res = new ArrayList<>();
if (obj != null) {
ctxt.setElement(parse(ctxt.getErrors(), obj));
}
List<ValidatedFragment> res = new ArrayList<>();
res.add(ctxt);
long t=System.currentTimeMillis()-start;
System.out.println("json parser: "+(t)+"ms, "+(content.length/1024)+"kb "+(t == 0 ? "" : " @ "+(content.length / t)+"kb/s"));
// 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;
}
public Element parse(List<ValidationMessage> errors, JsonObject object) throws FHIRException {
if (object == null) {
System.out.println("What?");
}
StructureDefinition sd = getLogical();
String name;
String path;

View File

@ -41,7 +41,6 @@ import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat;
import org.hl7.fhir.r5.elementmodel.ParserBase.NamedElement;
import org.hl7.fhir.r5.formats.IParser.OutputStyle;
import org.hl7.fhir.r5.model.StructureDefinition;
@ -106,7 +105,7 @@ public class Manager {
}
}
public static List<NamedElement> parse(IWorkerContext context, InputStream source, FhirFormat inputFormat) throws FHIRFormatError, DefinitionException, IOException, FHIRException {
public static List<ValidatedFragment> parse(IWorkerContext context, InputStream source, FhirFormat inputFormat) throws FHIRFormatError, DefinitionException, IOException, FHIRException {
return makeParser(context, inputFormat).parse(source);
}

View File

@ -39,7 +39,6 @@ import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities;
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities.SourcedChildDefinitions;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.elementmodel.ParserBase.NamedElement;
import org.hl7.fhir.r5.formats.IParser.OutputStyle;
import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.CodeableConcept;
@ -72,7 +71,7 @@ public class ObjectConverter {
org.hl7.fhir.r5.formats.JsonParser jp = new org.hl7.fhir.r5.formats.JsonParser();
jp.compose(bs, ig);
ByteArrayInputStream bi = new ByteArrayInputStream(bs.toByteArray());
List<NamedElement> list = new JsonParser(context).parse(bi);
List<ValidatedFragment> list = new JsonParser(context).parse(bi);
if (list.size() != 1) {
throw new FHIRException("Unable to convert because the source contains multieple resources");
}

View File

@ -35,7 +35,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.ArrayList;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
@ -69,54 +68,6 @@ public abstract class ParserBase {
}
}
public class NamedElement {
private String name;
private String extension;
private Element element;
private byte[] content;
private List<ValidationMessage> errors = new ArrayList<>();
public NamedElement(String name, String extension, Element element, byte[] content) {
super();
this.name = name;
this.element = element;
this.content = content;
this.extension = extension;
}
public NamedElement(String name, String extension, byte[] content) {
super();
this.name = name;
this.content = content;
this.extension = extension;
}
public String getName() {
return name;
}
public Element getElement() {
return element;
}
public byte[] getContent() {
return content;
}
public List<ValidationMessage> getErrors() {
return errors;
}
public void setElement(Element element) {
this.element = element;
}
public String getFilename() {
return name+"."+extension;
}
}
public interface ILinkResolver {
String resolveType(String type);
String resolveProperty(Property property);
@ -126,13 +77,7 @@ public abstract class ParserBase {
public enum ValidationPolicy { NONE, QUICK, EVERYTHING }
public boolean isPrimitive(String code) {
StructureDefinition sd = context.fetchTypeDefinition(code);
if (sd != null) {
return sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE;
}
return Utilities.existsInList(code, "boolean", "integer", "integer64", "string", "decimal", "uri", "base64Binary", "instant", "date", "dateTime", "time", "code", "oid", "id", "markdown", "unsignedInt", "positiveInt", "uuid", "xhtml", "url", "canonical");
return context.isPrimitiveType(code);
}
protected IWorkerContext context;
@ -152,20 +97,20 @@ public abstract class ParserBase {
this.policy = policy;
}
public abstract List<NamedElement> parse(InputStream stream) throws IOException, FHIRFormatError, DefinitionException, FHIRException;
public abstract List<ValidatedFragment> parse(InputStream stream) throws IOException, FHIRFormatError, DefinitionException, FHIRException;
public Element parseSingle(InputStream stream, List<ValidationMessage> errors) throws IOException, FHIRFormatError, DefinitionException, FHIRException {
List<NamedElement> res = parse(stream);
List<ValidatedFragment> res = parse(stream);
if (res.size() != 1) {
throw new FHIRException("Parsing FHIR content returned multiple elements in a context where only one element is allowed");
}
var resE = res.get(0);
if (resE.getElement() == null) {
throw new FHIRException("Parsing FHIR content failed: "+errorSummary(resE.errors));
throw new FHIRException("Parsing FHIR content failed: "+errorSummary(resE.getErrors()));
} else if (res.size() == 0) {
throw new FHIRException("Parsing FHIR content returned no elements in a context where one element is required because: "+errorSummary(resE.errors));
throw new FHIRException("Parsing FHIR content returned no elements in a context where one element is required because: "+errorSummary(resE.getErrors()));
}
if (errors != null) {
errors.addAll(resE.getErrors());

View File

@ -249,12 +249,7 @@ public class Property {
* @param E.g. "integer"
*/
public boolean isPrimitive(String code) {
if (Utilities.isAbsoluteUrl(code)) {
StructureDefinition sd = context.fetchTypeDefinition(code);
return sd != null && sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE;
} else {
return TypesUtilities.isPrimitive(code);
}
return context.isPrimitiveType(code);
}
public boolean isPrimitive() {

View File

@ -27,7 +27,7 @@ public class ResourceParser extends ParserBase {
}
@Override
public List<NamedElement> parse(InputStream stream) throws IOException, FHIRFormatError, DefinitionException, FHIRException {
public List<ValidatedFragment> parse(InputStream stream) throws IOException, FHIRFormatError, DefinitionException, FHIRException {
throw new NotImplementedException("parse(InputStream stream)"); // doesns't make sense
}

View File

@ -24,7 +24,6 @@ import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.elementmodel.ParserBase.NamedElement;
import org.hl7.fhir.r5.elementmodel.SHCParser.SHCSignedJWT;
import org.hl7.fhir.r5.formats.IParser.OutputStyle;
import org.hl7.fhir.utilities.TextFile;
@ -80,11 +79,11 @@ public class SHCParser extends ParserBase {
jsonParser = new JsonParser(context);
}
public List<NamedElement> parse(InputStream inStream) throws IOException, FHIRFormatError, DefinitionException, FHIRException {
public List<ValidatedFragment> parse(InputStream inStream) throws IOException, FHIRFormatError, DefinitionException, FHIRException {
byte[] content = TextFile.streamToBytes(inStream);
ByteArrayInputStream stream = new ByteArrayInputStream(content);
List<NamedElement> res = new ArrayList<>();
NamedElement shc = new NamedElement("shc", "json", content);
List<ValidatedFragment> res = new ArrayList<>();
ValidatedFragment shc = new ValidatedFragment("shc", "json", content);
res.add(shc);
String src = TextFile.streamToString(stream).trim();
@ -166,7 +165,7 @@ public class SHCParser extends ParserBase {
return res;
}
// ok. all checks passed, we can now validate the bundle
NamedElement bnd = new NamedElement(path, "json", org.hl7.fhir.utilities.json.parser.JsonParser.composeBytes(cs.getJsonObject("fhirBundle")));
ValidatedFragment bnd = new ValidatedFragment(path, "json", org.hl7.fhir.utilities.json.parser.JsonParser.composeBytes(cs.getJsonObject("fhirBundle")));
res.add(bnd);
bnd.setElement(jsonParser.parse(bnd.getErrors(), cs.getJsonObject("fhirBundle")));
}

View File

@ -72,11 +72,11 @@ public class SHLParser extends ParserBase {
super(context);
}
public List<NamedElement> parse(InputStream inStream) throws IOException, FHIRFormatError, DefinitionException, FHIRException {
public List<ValidatedFragment> parse(InputStream inStream) throws IOException, FHIRFormatError, DefinitionException, FHIRException {
byte[] content = TextFile.streamToBytes(inStream);
List<NamedElement> res = new ArrayList<>();
NamedElement shl = addNamedElement(res, "shl", "txt", content);
List<ValidatedFragment> res = new ArrayList<>();
ValidatedFragment shl = addNamedElement(res, "shl", "txt", content);
String src = TextFile.bytesToString(content);
if (src.startsWith("shlink:/")) {
@ -93,7 +93,7 @@ public class SHLParser extends ParserBase {
}
if (src != null) {
byte[] cntin = Base64.getUrlDecoder().decode(src);
NamedElement json = addNamedElement(res, "json", "json", cntin);
ValidatedFragment json = addNamedElement(res, "json", "json", cntin);
JsonObject j = null;
try {
j = org.hl7.fhir.utilities.json.parser.JsonParser.parseObject(cntin);
@ -145,8 +145,8 @@ public class SHLParser extends ParserBase {
}
private void checkManifest(List<NamedElement> res, HTTPResult cnt) throws IOException {
NamedElement manifest = addNamedElement(res, "manifest", "json", cnt.getContent());
private void checkManifest(List<ValidatedFragment> res, HTTPResult cnt) throws IOException {
ValidatedFragment manifest = addNamedElement(res, "manifest", "json", cnt.getContent());
if (!cnt.getContentType().equals("application/json")) {
logError(manifest.getErrors(), "202-08-31", 1, 1, "manifest", IssueType.STRUCTURE, "The mime type should be application/json not "+cnt.getContentType(), IssueSeverity.ERROR);
@ -188,7 +188,7 @@ public class SHLParser extends ParserBase {
}
}
private void processManifestEntry(List<NamedElement> res, List<ValidationMessage> errors, JsonObject j, String path, String name) throws FHIRFormatError, DefinitionException, FHIRException, IOException {
private void processManifestEntry(List<ValidatedFragment> res, List<ValidationMessage> errors, JsonObject j, String path, String name) throws FHIRFormatError, DefinitionException, FHIRException, IOException {
for (JsonProperty p : j.getProperties()) {
if (!Utilities.existsInList(p.getName(), "contentType", "location", "embedded")) {
logError(errors, "202-08-31", p.getValue().getStart().getLine(), p.getValue().getStart().getCol(), "manifest."+p.getName(),
@ -242,8 +242,8 @@ public class SHLParser extends ParserBase {
}
}
private void processContent(List<NamedElement> res, List<ValidationMessage> errors, String path, String name, String jose, String ct) throws FHIRFormatError, DefinitionException, FHIRException, IOException {
NamedElement bin = addNamedElement(res, "encrypted", "jose", TextFile.stringToBytes(jose, false));
private void processContent(List<ValidatedFragment> res, List<ValidationMessage> errors, String path, String name, String jose, String ct) throws FHIRFormatError, DefinitionException, FHIRException, IOException {
ValidatedFragment bin = addNamedElement(res, "encrypted", "jose", TextFile.stringToBytes(jose, false));
byte[] cnt = null;
JWEObject jwe;
try {
@ -261,7 +261,7 @@ public class SHLParser extends ParserBase {
res.addAll(shc.parse(new ByteArrayInputStream(cnt)));
break;
case "application/fhir+json":
NamedElement doc = addNamedElement(res, name, "json", cnt);
ValidatedFragment doc = addNamedElement(res, name, "json", cnt);
// a JSON file containing any FHIR resource (e.g., an individual resource or a Bundle of resources). Generally this format may not be tamper-proof.
logError(doc.getErrors(), "202-08-31", 1, 1, name, IssueType.STRUCTURE, "Processing content of type 'application/smart-api-access' is not done yet", IssueSeverity.INFORMATION);
break;
@ -279,8 +279,8 @@ public class SHLParser extends ParserBase {
}
}
private NamedElement addNamedElement(List<NamedElement> res, String name, String type, byte[] content) {
NamedElement result = new NamedElement(name, type, content);
private ValidatedFragment addNamedElement(List<ValidatedFragment> res, String name, String type, byte[] content) {
ValidatedFragment result = new ValidatedFragment(name, type, content);
res.add(result);
return result;
}

View File

@ -45,7 +45,6 @@ import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.elementmodel.Element.SpecialElement;
import org.hl7.fhir.r5.elementmodel.ParserBase.NamedElement;
import org.hl7.fhir.r5.formats.IParser.OutputStyle;
import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent;
import org.hl7.fhir.r5.model.StructureDefinition;
@ -81,9 +80,9 @@ public class TurtleParser extends ParserBase {
super(context);
}
@Override
public List<NamedElement> parse(InputStream inStream) throws IOException, FHIRException {
public List<ValidatedFragment> parse(InputStream inStream) throws IOException, FHIRException {
byte[] content = TextFile.streamToBytes(inStream);
NamedElement ctxt = new NamedElement("focus", "ttl", content);
ValidatedFragment ctxt = new ValidatedFragment("focus", "ttl", content);
ByteArrayInputStream stream = new ByteArrayInputStream(content);
Turtle src = new Turtle();
@ -99,7 +98,7 @@ public class TurtleParser extends ParserBase {
src.parse(TextFile.streamToString(stream));
ctxt.setElement(parse(ctxt.getErrors(), src));
}
List<NamedElement> res = new ArrayList<>();
List<ValidatedFragment> res = new ArrayList<>();
res.add(ctxt);
return res;
}

View File

@ -0,0 +1,54 @@
package org.hl7.fhir.r5.elementmodel;
import java.util.ArrayList;
import java.util.List;
import org.hl7.fhir.utilities.validation.ValidationMessage;
public class ValidatedFragment {
private String name;
private String extension;
private Element element;
private byte[] content;
private List<ValidationMessage> errors = new ArrayList<>();
public ValidatedFragment(String name, String extension, Element element, byte[] content) {
super();
this.name = name;
this.element = element;
this.content = content;
this.extension = extension;
}
public ValidatedFragment(String name, String extension, byte[] content) {
super();
this.name = name;
this.content = content;
this.extension = extension;
}
public String getName() {
return name;
}
public Element getElement() {
return element;
}
public byte[] getContent() {
return content;
}
public List<ValidationMessage> getErrors() {
return errors;
}
public void setElement(Element element) {
this.element = element;
}
public String getFilename() {
return name+"."+extension;
}
}

View File

@ -454,7 +454,7 @@ public class VerticalBarParser extends ParserBase {
private Delimiters delimiters = new Delimiters();
@Override
public List<NamedElement> parse(InputStream inStream) throws IOException, FHIRFormatError, DefinitionException, FHIRException {
public List<ValidatedFragment> parse(InputStream inStream) throws IOException, FHIRFormatError, DefinitionException, FHIRException {
StructureDefinition sd = context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/v2/StructureDefinition/Message");
Element message = new Element("Message", new Property(context, sd.getSnapshot().getElementFirstRep(), sd));
byte[] content = TextFile.streamToBytes(inStream);
@ -464,8 +464,8 @@ public class VerticalBarParser extends ParserBase {
preDecode(reader);
while (!reader.isFinished()) // && (getOptions().getSegmentLimit() == 0 || getOptions().getSegmentLimit() > message.getSegments().size()))
readSegment(message, reader);
List<NamedElement> res = new ArrayList<>();
res.add(new NamedElement("focus", "hl7", message, content));
List<ValidatedFragment> res = new ArrayList<>();
res.add(new ValidatedFragment("focus", "hl7", message, content));
return res;
}

View File

@ -111,10 +111,10 @@ public class XmlParser extends ParserBase {
this.allowXsiLocation = allowXsiLocation;
}
public List<NamedElement> parse(InputStream inStream) throws FHIRFormatError, DefinitionException, FHIRException, IOException {
public List<ValidatedFragment> parse(InputStream inStream) throws FHIRFormatError, DefinitionException, FHIRException, IOException {
byte[] content = TextFile.streamToBytes(inStream);
NamedElement context = new NamedElement("focus", "xml", content);
ValidatedFragment context = new ValidatedFragment("focus", "xml", content);
ByteArrayInputStream stream = new ByteArrayInputStream(content);
Document doc = null;
@ -177,7 +177,7 @@ public class XmlParser extends ParserBase {
if (doc != null) {
context.setElement(parse(context.getErrors(), doc));
}
List<NamedElement> res = new ArrayList<>();
List<ValidatedFragment> res = new ArrayList<>();
res.add(context);
return res;
}

View File

@ -323,7 +323,7 @@ public class PEBuilder {
if (passElementPropsCheck(defn) && !Utilities.existsInList(defn.getName(), omitList)) {
PEDefinitionElement pe = new PEDefinitionElement(this, profile, defn, parent.path());
pe.setRecursing(definition == defn || (profile.getDerivation() == TypeDerivationRule.SPECIALIZATION && profile.getType().equals("Extension")));
if (cu.isPrimitiveDatatype(definition.getTypeFirstRep().getWorkingCode()) && "value".equals(pe.name())) {
if (context.isPrimitiveType(definition.getTypeFirstRep().getWorkingCode()) && "value".equals(pe.name())) {
pe.setMustHaveValue(definition.getMustHaveValue());
}
pe.setInFixedValue(definition.hasFixed() || definition.hasPattern() || parent.isInFixedValue());

View File

@ -111,6 +111,7 @@ public class LiquidRenderer extends ResourceRenderer implements ILiquidRendering
LiquidEngine engine = new LiquidEngine(context.getWorker(), context.getServices());
XhtmlNode xn;
try {
engine.setIncludeResolver(new LiquidRendererIncludeResolver(context));
LiquidDocument doc = engine.parse(liquidTemplate, "template");
engine.setRenderingSupport(this);
String html = engine.evaluate(doc, r.getBase(), new LiquidRendererContxt(rcontext, r));

View File

@ -801,7 +801,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
}
} else if (hasDef && element.getType().get(0).getWorkingCode() != null && element.getType().get(0).getWorkingCode().startsWith("@")) {
row.setIcon("icon_reuse.png", HierarchicalTableGenerator.TEXT_ICON_REUSE);
} else if (hasDef && isPrimitive(element.getType().get(0).getWorkingCode())) {
} else if (hasDef && context.getContext().isPrimitiveType(element.getType().get(0).getWorkingCode())) {
if (keyRows.contains(element.getId())) {
row.setIcon("icon-key.png", HierarchicalTableGenerator.TEXT_ICON_KEY);
} else {
@ -809,7 +809,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
}
} else if (hasDef && element.getType().get(0).hasTarget()) {
row.setIcon("icon_reference.png", HierarchicalTableGenerator.TEXT_ICON_REFERENCE);
} else if (hasDef && isDataType(element.getType().get(0).getWorkingCode())) {
} else if (hasDef && context.getContext().isDataType(element.getType().get(0).getWorkingCode())) {
row.setIcon("icon_datatype.gif", HierarchicalTableGenerator.TEXT_ICON_DATATYPE);
} else if (hasDef && element.hasExtension(ToolingExtensions.EXT_JSON_PROP_KEY)) {
row.setIcon("icon-object-box.png", HierarchicalTableGenerator.TEXT_ICON_OBJECT_BOX);
@ -1309,7 +1309,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
boolean first = true;
for (StructureDefinition sd : children) {
if (first) first = false; else c.addPiece(gen.new Piece(null, ", ", null));
c.addPiece(gen.new Piece(sd.getWebPath(), sd.getTypeName(), null));
c.addPiece(gen.new Piece(sd.getWebPath(), sd.getName(), null));
}
}
}
@ -2122,7 +2122,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
if (!pattern) {
c.addPiece(gen.new Piece(null, "0..0", null));
row.setIcon("icon_fixed.gif", "Fixed Value" /*HierarchicalTableGenerator.TEXT_ICON_FIXED*/);
} else if (isPrimitive(t.getTypeCode())) {
} else if (context.getContext().isPrimitiveType(t.getTypeCode())) {
row.setIcon("icon_primitive.png", HierarchicalTableGenerator.TEXT_ICON_PRIMITIVE);
c.addPiece(gen.new Piece(null, "0.."+(t.getMaxCardinality() == 2147483647 ? "*": Integer.toString(t.getMaxCardinality())), null));
} else if (isReference(t.getTypeCode())) {
@ -2450,28 +2450,6 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
return path;
}
protected boolean isPrimitive(String value) {
StructureDefinition sd = context.getWorker().fetchTypeDefinition(value);
if (sd == null) // might be running before all SDs are available
return Utilities.existsInList(value, "base64Binary", "boolean", "canonical", "code", "date", "dateTime", "decimal", "id", "instant", "integer", "integer64", "markdown", "oid", "positiveInt", "string", "time", "unsignedInt", "uri", "url", "uuid");
else
return sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE;
}
private boolean isDataType(String value) {
StructureDefinition sd = context.getWorker().fetchTypeDefinition(value);
if (sd == null) // might be running before all SDs are available
return Utilities.existsInList(value, "Address", "Age", "Annotation", "Attachment", "CodeableConcept", "Coding", "ContactPoint", "Count", "Distance", "Duration", "HumanName", "Identifier", "Money", "Period", "Quantity", "Range", "Ratio", "Reference", "SampledData", "Signature", "Timing",
"ContactDetail", "Contributor", "DataRequirement", "Expression", "ParameterDefinition", "RelatedArtifact", "TriggerDefinition", "UsageContext");
else
return sd.getKind() == StructureDefinitionKind.COMPLEXTYPE && sd.getDerivation() == TypeDerivationRule.SPECIALIZATION;
}
private boolean slicesExist(List<ElementDefinition> elements, ElementDefinition element) {
if (elements == null) {
return true;
@ -3827,7 +3805,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
private boolean hasPrimitiveTypes(ElementDefinition d) {
for (TypeRefComponent tr : d.getType()) {
if (isPrimitive(tr.getCode())) {
if (context.getContext().isPrimitiveType(tr.getCode())) {
return true;
}
}

View File

@ -15,8 +15,10 @@ import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.exceptions.TerminologyServiceException;
import org.hl7.fhir.r5.comparison.VersionComparisonAnnotation;
import org.hl7.fhir.r5.context.TerminologyCache;
import org.hl7.fhir.r5.context.IWorkerContext.CodingValidationRequest;
import org.hl7.fhir.r5.context.IWorkerContext.ValidationResult;
import org.hl7.fhir.r5.context.TerminologyCache.CacheToken;
import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.BooleanType;
import org.hl7.fhir.r5.model.CanonicalResource;
@ -26,8 +28,10 @@ import org.hl7.fhir.r5.model.Coding;
import org.hl7.fhir.r5.model.ConceptMap;
import org.hl7.fhir.r5.model.DataType;
import org.hl7.fhir.r5.model.Enumerations.FilterOperator;
import org.hl7.fhir.r5.model.Enumerations.PublicationStatus;
import org.hl7.fhir.r5.model.Extension;
import org.hl7.fhir.r5.model.ExtensionHelper;
import org.hl7.fhir.r5.model.Parameters;
import org.hl7.fhir.r5.model.PrimitiveType;
import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.model.StringType;
@ -38,6 +42,7 @@ import org.hl7.fhir.r5.model.ValueSet.ConceptReferenceComponent;
import org.hl7.fhir.r5.model.ValueSet.ConceptReferenceDesignationComponent;
import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent;
import org.hl7.fhir.r5.model.ValueSet.ConceptSetFilterComponent;
import org.hl7.fhir.r5.model.ValueSet.ValueSetComposeComponent;
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionComponent;
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent;
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionParameterComponent;
@ -48,9 +53,11 @@ import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceContext;
import org.hl7.fhir.r5.terminologies.CodeSystemUtilities;
import org.hl7.fhir.r5.terminologies.ValueSetUtilities;
import org.hl7.fhir.r5.terminologies.expansion.ValueSetExpansionOutcome;
import org.hl7.fhir.r5.terminologies.utilities.TerminologyServiceErrorClass;
import org.hl7.fhir.r5.utils.ToolingExtensions;
import org.hl7.fhir.utilities.LoincLinker;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.i18n.I18nConstants;
import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator;
import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Row;
import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.TableModel;
@ -1142,7 +1149,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
}
}
private boolean genInclude(XhtmlNode ul, ConceptSetComponent inc, String type, List<String> langs, boolean doDesignations, List<UsedConceptMap> maps, Map<String, String> designations, int index, Resource vsRes) throws FHIRException, IOException {
private boolean genInclude(XhtmlNode ul, ConceptSetComponent inc, String type, List<String> langs, boolean doDesignations, List<UsedConceptMap> maps, Map<String, String> designations, int index, ValueSet vsRes) throws FHIRException, IOException {
boolean hasExtensions = false;
XhtmlNode li;
li = ul.li();
@ -1165,7 +1172,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
}
// for performance reasons, we do all the fetching in one batch
definitions = getConceptsForCodes(e, inc);
definitions = getConceptsForCodes(e, inc, vsRes, index);
XhtmlNode t = li.table("none");
@ -1361,7 +1368,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
}
private Map<String, ConceptDefinitionComponent> getConceptsForCodes(CodeSystem e, ConceptSetComponent inc) {
private Map<String, ConceptDefinitionComponent> getConceptsForCodes(CodeSystem e, ConceptSetComponent inc, ValueSet source, int index) {
if (e == null) {
e = getContext().getWorker().fetchCodeSystem(inc.getSystem());
}
@ -1369,13 +1376,21 @@ public class ValueSetRenderer extends TerminologyRenderer {
ValueSetExpansionComponent vse = null;
if (!context.isNoSlowLookup()) { // && !getContext().getWorker().hasCache()) { removed GG 20220107 like what is this trying to do?
try {
ValueSetExpansionOutcome vso = getContext().getWorker().expandVS(inc, false, false);
ValueSet vs = new ValueSet();
vs.setUrl(source.getUrl()+"-inc-"+index);
vs.setStatus(PublicationStatus.ACTIVE);
vs.setCompose(new ValueSetComposeComponent());
vs.getCompose().setInactive(false);
vs.getCompose().getInclude().add(inc);
ValueSetExpansionOutcome vso = getContext().getWorker().expandVS(vs, true, false);
ValueSet valueset = vso.getValueset();
if (valueset == null)
throw new TerminologyServiceException("Error Expanding ValueSet: "+vso.getError());
vse = valueset.getExpansion();
} catch (TerminologyServiceException e1) {
} catch (Exception e1) {
return null;
}
}

View File

@ -123,6 +123,7 @@ import org.hl7.fhir.r5.terminologies.utilities.TerminologyOperationContext.Termi
import org.hl7.fhir.r5.terminologies.utilities.TerminologyServiceErrorClass;
import org.hl7.fhir.r5.terminologies.utilities.ValueSetProcessBase;
import org.hl7.fhir.r5.utils.ToolingExtensions;
import org.hl7.fhir.r5.utils.client.EFhirClientException;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.i18n.AcceptLanguageHeader;
@ -582,23 +583,23 @@ public class ValueSetExpander extends ValueSetProcessBase {
} catch (NoTerminologyServiceException e) {
// well, we couldn't expand, so we'll return an interface to a checker that can check membership of the set
// that might fail too, but it might not, later.
return new ValueSetExpansionOutcome(e.getMessage(), TerminologyServiceErrorClass.NOSERVICE, allErrors);
return new ValueSetExpansionOutcome(e.getMessage(), TerminologyServiceErrorClass.NOSERVICE, allErrors, false);
} catch (CodeSystemProviderExtension e) {
// well, we couldn't expand, so we'll return an interface to a checker that can check membership of the set
// that might fail too, but it might not, later.
return new ValueSetExpansionOutcome(e.getMessage(), TerminologyServiceErrorClass.INTERNAL_ERROR, allErrors);
return new ValueSetExpansionOutcome(e.getMessage(), TerminologyServiceErrorClass.INTERNAL_ERROR, allErrors, false);
} catch (TerminologyServiceProtectionException e) {
if (opContext.isOriginal()) {
return new ValueSetExpansionOutcome(e.getMessage(), e.getError(), allErrors);
return new ValueSetExpansionOutcome(e.getMessage(), e.getError(), allErrors, false);
} else {
throw e;
}
} catch (ETooCostly e) {
return new ValueSetExpansionOutcome(e.getMessage(), TerminologyServiceErrorClass.TOO_COSTLY, allErrors);
return new ValueSetExpansionOutcome(e.getMessage(), TerminologyServiceErrorClass.TOO_COSTLY, allErrors, false);
} catch (Exception e) {
// well, we couldn't expand, so we'll return an interface to a checker that can check membership of the set
// that might fail too, but it might not, later.
return new ValueSetExpansionOutcome(e.getMessage(), TerminologyServiceErrorClass.UNKNOWN, allErrors);
return new ValueSetExpansionOutcome(e.getMessage(), TerminologyServiceErrorClass.UNKNOWN, allErrors, e instanceof EFhirClientException || e instanceof TerminologyServiceException);
}
}
@ -705,7 +706,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
focus.getExpansion().setTotal(dwc.getTotal());
}
if (!requiredSupplements.isEmpty()) {
return new ValueSetExpansionOutcome(context.formatMessagePlural(requiredSupplements.size(), I18nConstants.VALUESET_SUPPLEMENT_MISSING, CommaSeparatedStringBuilder.build(requiredSupplements)), TerminologyServiceErrorClass.BUSINESS_RULE, allErrors);
return new ValueSetExpansionOutcome(context.formatMessagePlural(requiredSupplements.size(), I18nConstants.VALUESET_SUPPLEMENT_MISSING, CommaSeparatedStringBuilder.build(requiredSupplements)), TerminologyServiceErrorClass.BUSINESS_RULE, allErrors, false);
}
if (!expParams.hasParameter("includeDefinition") || !expParams.getParameterBool("includeDefinition")) {
focus.setCompose(null);

View File

@ -19,30 +19,34 @@ public class ValueSetExpansionOutcome {
private TerminologyServiceErrorClass errorClass;
private String txLink;
private List<String> allErrors = new ArrayList<>();
private boolean fromServer;
public ValueSetExpansionOutcome(ValueSet valueset) {
super();
this.valueset = valueset;
this.error = null;
}
public ValueSetExpansionOutcome(ValueSet valueset, String error, TerminologyServiceErrorClass errorClass) {
public ValueSetExpansionOutcome(ValueSet valueset, String error, TerminologyServiceErrorClass errorClass, boolean fromServer) {
super();
this.valueset = valueset;
this.error = error;
this.errorClass = errorClass;
this.fromServer = fromServer;
allErrors.add(error);
}
public ValueSetExpansionOutcome(String error, TerminologyServiceErrorClass errorClass) {
public ValueSetExpansionOutcome(String error, TerminologyServiceErrorClass errorClass, boolean fromServer) {
this.valueset = null;
this.error = error;
this.errorClass = errorClass;
this.fromServer = fromServer;
allErrors.add(error);
}
public ValueSetExpansionOutcome(String error, TerminologyServiceErrorClass errorClass, List<String> errList) {
public ValueSetExpansionOutcome(String error, TerminologyServiceErrorClass errorClass, List<String> errList, boolean fromServer) {
this.valueset = null;
this.error = error;
this.errorClass = errorClass;
this.fromServer = fromServer;
this.allErrors.addAll(errList);
if (!allErrors.contains(error)) {
allErrors.add(error);
@ -72,6 +76,9 @@ public class ValueSetExpansionOutcome {
return allErrors;
}
public boolean isFromServer() {
return fromServer;
}
public boolean isOk() {
return (allErrors.isEmpty() || (allErrors.size() == 1 && allErrors.get(0) == null)) && error == null;
}

View File

@ -451,7 +451,13 @@ public class LiquidEngine implements IEvaluationContext {
@Override
public void evaluate(StringBuilder b, Base resource, LiquidEngineContext ctxt) throws FHIRException {
if (includeResolver == null) {
throw new FHIRException("Includes are not supported in this context");
}
String src = includeResolver.fetchInclude(LiquidEngine.this, page);
if (src == null) {
throw new FHIRException("The include '"+page+"' could not be resolved");
}
LiquidParser parser = new LiquidParser(src);
LiquidDocument doc = parser.parse(page);
LiquidEngineContext nctxt = new LiquidEngineContext(ctxt.externalContext, ctxt);
@ -617,8 +623,8 @@ public class LiquidEngine implements IEvaluationContext {
int i = 1;
while (i < cnt.length() && !Character.isWhitespace(cnt.charAt(i)))
i++;
if (i == cnt.length() || i == 0)
throw new FHIRException(engine.getWorker().formatMessage(I18nConstants.LIQUID_SYNTAX_INCLUDE, name + ": Error reading include: " + cnt));
if (i == 0)
throw new FHIRException(engine.getWorker().formatMessage(I18nConstants.LIQUID_SYNTAX_INCLUDE, name, cnt));
LiquidInclude res = new LiquidInclude();
res.page = cnt.substring(0, i);
while (i < cnt.length() && Character.isWhitespace(cnt.charAt(i)))

View File

@ -92,7 +92,7 @@ public class ResourceLanguageFileBuilder {
private boolean isTranslatable(Property p, Base b, String id) {
if (new ContextUtilities(context).isPrimitiveDatatype(b.fhirType())) { // never any translations for non-primitives
if (context.isPrimitiveType(b.fhirType())) { // never any translations for non-primitives
ElementDefinition ed = null;
for (ElementDefinition t : profile.getSnapshot().getElement()) {
if (t.getId().equals(id)) {

View File

@ -19,7 +19,7 @@ public class CanonicalResourceManagerTests {
private CanonicalResource resource;
public DeferredLoadTestResource(CanonicalResource resource) {
super(resource.fhirType(), resource.getId(), resource.getUrl(), resource.getVersion(), resource instanceof CodeSystem ? ((CodeSystem) resource).getSupplements() : null);
super(resource.fhirType(), resource.getId(), resource.getUrl(), resource.getVersion(), resource instanceof CodeSystem ? ((CodeSystem) resource).getSupplements() : null, null);
this.resource = resource;
}

View File

@ -13,7 +13,7 @@ import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.PathEngineException;
import org.hl7.fhir.r5.elementmodel.Manager;
import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat;
import org.hl7.fhir.r5.elementmodel.ParserBase.NamedElement;
import org.hl7.fhir.r5.elementmodel.ValidatedFragment;
import org.hl7.fhir.r5.formats.JsonParser;
import org.hl7.fhir.r5.formats.XmlParser;
import org.hl7.fhir.r5.model.*;
@ -209,7 +209,7 @@ public class FHIRPathTests {
if (node != null) {
try {
if ("element".equals(test.getAttribute("mode"))) {
List<NamedElement> e = Manager.parse(fp.getWorker(), TestingUtilities.loadTestResourceStream("r5", input), input.endsWith(".json") ? FhirFormat.JSON : FhirFormat.XML);
List<ValidatedFragment> e = Manager.parse(fp.getWorker(), TestingUtilities.loadTestResourceStream("r5", input), input.endsWith(".json") ? FhirFormat.JSON : FhirFormat.XML);
outcome = fp.evaluate(e.get(0).getElement(), node);
} else {
outcome = fp.evaluate(res, node);

View File

@ -138,6 +138,15 @@ public class CommaSeparatedStringBuilder {
return self.toString();
}
public static String buildObjects(List<? extends Object> list) {
CommaSeparatedStringBuilder self = new CommaSeparatedStringBuilder();
for (Object s : list) {
self.append(s.toString());
}
return self.toString();
}
public static Set<String> toSet(String source) {
if (source == null) {
return null;

View File

@ -0,0 +1,105 @@
package org.hl7.fhir.utilities;
public class HL7WorkGroups {
public static class HL7WorkGroup {
private String link;
private String name;
private String code;
protected HL7WorkGroup(String code, String name, String link) {
super();
this.code = code;
this.name = name;
this.link = link;
}
public String getLink() {
return link;
}
public String getName() {
return name;
}
public String getCode() {
return code;
}
}
public static HL7WorkGroup find(String wg) {
String name = nameForWG(wg);
String url = urlForWG(wg);
if (name != null) {
return new HL7WorkGroup(wg, name, url);
} else {
return null;
}
}
private static 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 "cic" : return "http://www.hl7.org/Special/committees/cic";
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 static String nameForWG(String wg) {
switch (wg) {
case "cbcc": return "Community Based Collaborative Care";
case "cds": return "Clinical Decision Support";
case "cic" : return "Clinical Interoperability Council";
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;
}
}

View File

@ -8,8 +8,8 @@ public class JsonProperty {
boolean noComma; // parse in Json5 mode, but records this so the validator can complain
boolean unquotedName;
boolean unquotedValue;
private int tag; // used for status in validator - faster parsing
private int tag;
public JsonProperty(String name, JsonElement value) {
super();

View File

@ -113,6 +113,7 @@ public class NpmPackage {
private String filename;
private String supplements;
private String stype;
private String derivation;
public PackageResourceInformation(String root, JsonObject fi) throws IOException {
super();
@ -123,6 +124,7 @@ public class NpmPackage {
filename = Utilities.path(root, fi.asString("filename"));
supplements = fi.asString("supplements");
stype = fi.asString("type");
derivation = fi.asString("derivation");
}
public String getId() {
return id;
@ -148,6 +150,9 @@ public class NpmPackage {
public boolean hasId() {
return !Utilities.noString(id);
}
public String getDerivation() {
return derivation;
}
}
public class IndexVersionSorter implements Comparator<JsonObject> {
@ -223,13 +228,13 @@ public class NpmPackage {
List<String> res = new ArrayList<>();
if (folder != null) {
for (File f : folder.listFiles()) {
if (!f.isDirectory() && !Utilities.existsInList(f.getName(), "package.json", ".index.json")) {
if (!f.isDirectory() && !Utilities.existsInList(f.getName(), "package.json", ".index.json", ".index.db")) {
res.add(f.getName());
}
}
} else {
for (String s : content.keySet()) {
if (!Utilities.existsInList(s, "package.json", ".index.json")) {
if (!Utilities.existsInList(s, "package.json", ".index.json", ".index.db")) {
res.add(s);
}
}
@ -1095,12 +1100,12 @@ public class NpmPackage {
public void save(OutputStream stream) throws IOException {
assert !minimalMemory;
TarArchiveOutputStream tar;
ByteArrayOutputStream OutputStream;
BufferedOutputStream bufferedOutputStream;
// ByteArrayOutputStream OutputStream;
// BufferedOutputStream bufferedOutputStream;
GzipCompressorOutputStream gzipOutputStream;
OutputStream = new ByteArrayOutputStream();
bufferedOutputStream = new BufferedOutputStream(OutputStream);
// OutputStream = new ByteArrayOutputStream();
// bufferedOutputStream = new BufferedOutputStream(OutputStream);
GzipParameters gp = new GzipParameters();
gp.setCompressionLevel(Deflater.BEST_COMPRESSION);
gzipOutputStream = new GzipCompressorOutputStream(stream, gp);
@ -1122,7 +1127,7 @@ public class NpmPackage {
System.out.println(name+" is null");
} else {
indexer.seeFile(s, b);
if (!s.equals(".index.json") && !s.equals("package.json")) {
if (!s.equals(".index.json") && !s.equals(".index.db") && !s.equals("package.json")) {
TarArchiveEntry entry = new TarArchiveEntry(name);
entry.setSize(b.length);
tar.putArchiveEntry(entry);
@ -1158,10 +1163,10 @@ public class NpmPackage {
tar.finish();
tar.close();
gzipOutputStream.close();
bufferedOutputStream.close();
OutputStream.close();
byte[] b = OutputStream.toByteArray();
stream.write(b);
// bufferedOutputStream.close();
// OutputStream.close();
// byte[] b = OutputStream.toByteArray();
// stream.write(b);
}
/**

View File

@ -45,7 +45,7 @@ public class NpmPackageIndexBuilder {
new File(filename).delete();
conn = DriverManager.getConnection("jdbc:sqlite:"+filename);
Statement stmt = conn.createStatement();
stmt.execute("CREATE TABLE index (\r\n"+
stmt.execute("CREATE TABLE ResourceList (\r\n"+
"FileName nvarchar NOT NULL,\r\n"+
"ResourceType nvarchar NOT NULL,\r\n"+
"Id nvarchar NULL,\r\n"+
@ -55,10 +55,18 @@ public class NpmPackageIndexBuilder {
"Type nvarchar NULL,\r\n"+
"Supplements nvarchar NULL,\r\n"+
"Content nvarchar NULL,\r\n"+
"ValueSet nvarchar NULL,\r\n"+
"Derivation 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 (?, ?, ?, ?, ?, ?, ?, ?, ?)");
psql = conn.prepareStatement("Insert into ResourceList (FileName, ResourceType, Id, Url, Version, Kind, Type, Supplements, Content, ValueSet) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
} catch (Exception e) {
if (conn != null) {
try {
conn.close();
} catch (SQLException e1) {
}
}
conn = null;
}
}
@ -95,6 +103,12 @@ public class NpmPackageIndexBuilder {
if (json.hasPrimitive("content")) {
fi.add("content", json.asString("content"));
}
if (json.hasPrimitive("valueSet")) {
fi.add("valueSet", json.asString("valueSet"));
}
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");
@ -105,6 +119,8 @@ public class NpmPackageIndexBuilder {
psql.setString(7, json.asString("type")); // Type");
psql.setString(8, json.asString("supplements")); // Supplements");
psql.setString(9, json.asString("content")); // Content");
psql.setString(10, json.asString("valueSet")); // ValueSet");
psql.setString(10, json.asString("derivation")); // ValueSet");
psql.execute();
}
}

View File

@ -336,15 +336,32 @@ public class XhtmlNode extends XhtmlFluent implements IBaseXhtml {
public String allText() {
if (!hasChildren()) {
return getContent();
if (getContent() == null) {
return "";
} else {
return getContent();
}
}
StringBuilder b = new StringBuilder();
for (XhtmlNode n : childNodes)
if (n.getNodeType() == NodeType.Text)
b.append(n.getContent());
else if (n.getNodeType() == NodeType.Element)
for (XhtmlNode n : childNodes) {
if (n.getNodeType() == NodeType.Element && Utilities.existsInList(n.getName(), "li")) {
b.append("* ");
}
if (n.getNodeType() == NodeType.Text) {
if (n.getContent() != null) {
b.append(n.getContent());
}
}
if (n.getNodeType() == NodeType.Element) {
b.append(n.allText());
if (Utilities.existsInList(n.getName(), "p", "div", "tr", "th", "ul", "ol", "li", "h1", "h2", "h3", "h4", "h5", "h6")) {
b.append("\r\n");
} else if (Utilities.existsInList(n.getName(), "th", "td", "span")) {
b.append(" ");
}
}
}
return b.toString();
}

View File

@ -77,9 +77,9 @@ import org.hl7.fhir.r5.elementmodel.Manager;
import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat;
import org.hl7.fhir.r5.elementmodel.ObjectConverter;
import org.hl7.fhir.r5.elementmodel.ParserBase;
import org.hl7.fhir.r5.elementmodel.ParserBase.NamedElement;
import org.hl7.fhir.r5.elementmodel.ParserBase.ValidationPolicy;
import org.hl7.fhir.r5.elementmodel.ResourceParser;
import org.hl7.fhir.r5.elementmodel.ValidatedFragment;
import org.hl7.fhir.r5.elementmodel.XmlParser;
import org.hl7.fhir.r5.formats.FormatUtilities;
import org.hl7.fhir.r5.model.Address;
@ -173,6 +173,8 @@ import org.hl7.fhir.r5.utils.validation.constants.ContainedReferenceValidationPo
import org.hl7.fhir.r5.utils.validation.constants.IdStatus;
import org.hl7.fhir.r5.utils.validation.constants.ReferenceValidationPolicy;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
import org.hl7.fhir.utilities.HL7WorkGroups;
import org.hl7.fhir.utilities.HL7WorkGroups.HL7WorkGroup;
import org.hl7.fhir.utilities.MarkDownProcessor;
import org.hl7.fhir.utilities.SIDUtilities;
import org.hl7.fhir.utilities.StandardsStatus;
@ -517,7 +519,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
private Map<String, CanonicalResourceLookupResult> crLookups = new HashMap<>();
private boolean logProgress;
private CodingsObserver codingObserver;
public List<NamedElement> validatedContent;
public List<ValidatedFragment> validatedContent;
public boolean testMode;
public InstanceValidator(@Nonnull IWorkerContext theContext, @Nonnull IEvaluationContext hostServices, @Nonnull XVerExtensionManager xverManager) {
@ -747,7 +749,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
if (validatedContent != null && !validatedContent.isEmpty()) {
if (SAVE_INTERMEDIARIES) {
int index = 0;
for (NamedElement ne : validatedContent) {
for (ValidatedFragment ne : validatedContent) {
index++;
saveValidatedContent(ne, index);
}
@ -761,7 +763,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
profiles.add(sd);
}
}
for (NamedElement ne : validatedContent) {
for (ValidatedFragment ne : validatedContent) {
if (ne.getElement() != null) {
validate(appContext, ne.getErrors(), validatedContent.size() > 1 ? ne.getName() : null, ne.getElement(), profiles);
}
@ -771,7 +773,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
return (validatedContent == null || validatedContent.isEmpty()) ? null : validatedContent.get(0).getElement(); // todo: this is broken, but fixing it really complicates things elsewhere, so we do this for now
}
private void saveValidatedContent(NamedElement ne, int index) {
private void saveValidatedContent(ValidatedFragment ne, int index) {
String tgt = null;
try {
tgt = Utilities.path("[tmp]", "validator", "content");
@ -4309,8 +4311,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
}
public boolean isPrimitiveType(String code) {
StructureDefinition sd = context.fetchTypeDefinition(code);
return sd != null && sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE;
return context.isPrimitiveType(code);
}
private String getErrorMessage(String message) {
@ -5404,84 +5405,20 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
}
}
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;
HL7WorkGroup wgd = HL7WorkGroups.find(wg);
if (rule(errors, "2023-09-15", IssueType.BUSINESSRULE, element.line(), element.col(), stack.getLiteralPath(), wgd != null, I18nConstants.VALIDATION_HL7_WG_UNKNOWN, wg)) {
String rpub = "HL7 International / "+wgd.getName();
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);
Utilities.startsWithInList( wgd.getLink(), urls), I18nConstants.VALIDATION_HL7_WG_URL, wg, wgd.getLink());
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");

View File

@ -481,7 +481,7 @@ public class StructureDefinitionValidator extends BaseValidator {
if (v != null) {
ok = rule(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), typeCodes.contains(v.fhirType()), I18nConstants.SD_VALUE_TYPE_IILEGAL, element.getIdBase(), "fixed", v.fhirType(), typeCodes) && ok;
hint(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), !repeating, I18nConstants.SD_VALUE_TYPE_REPEAT_HINT, element.getIdBase(), "fixed");
if (isPrimitiveType(v.fhirType())) {
if (context.isPrimitiveType(v.fhirType())) {
warning(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), !repeating, I18nConstants.SD_VALUE_TYPE_REPEAT_WARNING_DOTNET, element.getIdBase(), "fixed");
} else {
warning(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), false, I18nConstants.SD_VALUE_COMPLEX_FIXED, v.fhirType());
@ -491,7 +491,7 @@ public class StructureDefinitionValidator extends BaseValidator {
if (v != null) {
ok = rule(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), typeCodes.contains(v.fhirType()), I18nConstants.SD_VALUE_TYPE_IILEGAL, element.getIdBase(), "pattern", v.fhirType(), typeCodes) && ok;
hint(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), !repeating, I18nConstants.SD_VALUE_TYPE_REPEAT_HINT, element.getIdBase(), "pattern");
if (isPrimitiveType(v.fhirType())) {
if (context.isPrimitiveType(v.fhirType())) {
warning(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), !repeating, I18nConstants.SD_VALUE_TYPE_REPEAT_WARNING_DOTNET, element.getIdBase(), "pattern");
}
}
@ -737,10 +737,6 @@ public class StructureDefinitionValidator extends BaseValidator {
return true;
}
private boolean isPrimitiveType(String fhirType) {
StructureDefinition sd = context.fetchTypeDefinition(fhirType);
return sd != null && sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE;
}
private String boundType(Set<String> typeCodes) {
for (String tc : typeCodes) {

View File

@ -22,6 +22,9 @@ public class FHIRPathExpressionFixer {
if ("txt-2".equals(key)) {
return "htmlChecks2()";
}
if ("dom-6".equals(key)) {
return "(%rootResource != $this) or text.`div`.exists()";
}
if ("generated='generated' implies source.empty()".equals(expr)) {
return "generation='generated' implies source.empty()";
}

View File

@ -119,7 +119,7 @@ public class NodeStack {
if (en.endsWith("[x]")) {
en = en.substring(0, en.length() - 3);
String t = n.substring(en.length());
if (isPrimitiveType(Utilities.uncapitalize(t)))
if (context.isPrimitiveType(Utilities.uncapitalize(t)))
t = Utilities.uncapitalize(t);
res.literalPath = res.literalPath.substring(0, res.literalPath.lastIndexOf(".")) + "." + en + ".ofType(" + t + ")";
} else {
@ -194,10 +194,6 @@ public class NodeStack {
return path.substring(path.lastIndexOf(".") + 1);
}
public boolean isPrimitiveType(String code) {
StructureDefinition sd = context.fetchTypeDefinition(code);
return sd != null && sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE;
}
public String getWorkingLang() {
return workingLang;