From d9c167455e88d4807e12b53d07394d3b488e3253 Mon Sep 17 00:00:00 2001 From: James Agnew Date: Tue, 27 Mar 2018 15:20:22 -0400 Subject: [PATCH] Make sure we correctly clean up resources --- .../DefaultProfileValidationSupport.java | 47 +- .../ctx/DefaultProfileValidationSupport.java | 43 +- .../DefaultProfileValidationSupport.java | 406 +++++++++--------- .../DefaultProfileValidationSupport.java | 51 ++- src/changes/changes.xml | 7 + 5 files changed, 295 insertions(+), 259 deletions(-) diff --git a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu2016may/hapi/validation/DefaultProfileValidationSupport.java b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu2016may/hapi/validation/DefaultProfileValidationSupport.java index ebbfbc2a0dd..fa98150221c 100644 --- a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu2016may/hapi/validation/DefaultProfileValidationSupport.java +++ b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu2016may/hapi/validation/DefaultProfileValidationSupport.java @@ -2,6 +2,7 @@ package org.hl7.fhir.dstu2016may.hapi.validation; import ca.uhn.fhir.context.FhirContext; import org.apache.commons.io.Charsets; +import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.Validate; import org.hl7.fhir.dstu2016may.model.*; import org.hl7.fhir.dstu2016may.model.Bundle.BundleEntryComponent; @@ -68,8 +69,8 @@ public class DefaultProfileValidationSupport implements IValidationSupport { Map codeSystems = myCodeSystems; Map valueSets = myValueSets; if (codeSystems == null) { - codeSystems = new HashMap(); - valueSets = new HashMap(); + codeSystems = new HashMap<>(); + valueSets = new HashMap<>(); loadCodeSystems(theContext, codeSystems, valueSets, "/org/hl7/fhir/dstu2016may/model/valueset/valuesets.xml"); loadCodeSystems(theContext, codeSystems, valueSets, "/org/hl7/fhir/dstu2016may/model/valueset/v2-tables.xml"); @@ -155,27 +156,33 @@ public class DefaultProfileValidationSupport implements IValidationSupport { private void loadCodeSystems(FhirContext theContext, Map theCodeSystems, Map theValueSets, String theClasspath) { ourLog.info("Loading CodeSystem/ValueSet from classpath: {}", theClasspath); - InputStream valuesetText = DefaultProfileValidationSupport.class.getResourceAsStream(theClasspath); - if (valuesetText != null) { - InputStreamReader reader = new InputStreamReader(valuesetText, Charsets.UTF_8); + InputStream inputStream = DefaultProfileValidationSupport.class.getResourceAsStream(theClasspath); + InputStreamReader reader = null; + if (inputStream != null) { + try { + reader = new InputStreamReader(inputStream, Charsets.UTF_8); - Bundle bundle = theContext.newXmlParser().parseResource(Bundle.class, reader); - for (BundleEntryComponent next : bundle.getEntry()) { - if (next.getResource() instanceof CodeSystem) { - CodeSystem nextValueSet = (CodeSystem) next.getResource(); - nextValueSet.getText().setDivAsString(""); - String system = nextValueSet.getUrl(); - if (isNotBlank(system)) { - theCodeSystems.put(system, nextValueSet); - } - } else if (next.getResource() instanceof ValueSet) { - ValueSet nextValueSet = (ValueSet) next.getResource(); - nextValueSet.getText().setDivAsString(""); - String system = nextValueSet.getUrl(); - if (isNotBlank(system)) { - theValueSets.put(system, nextValueSet); + Bundle bundle = theContext.newXmlParser().parseResource(Bundle.class, reader); + for (BundleEntryComponent next : bundle.getEntry()) { + if (next.getResource() instanceof CodeSystem) { + CodeSystem nextValueSet = (CodeSystem) next.getResource(); + nextValueSet.getText().setDivAsString(""); + String system = nextValueSet.getUrl(); + if (isNotBlank(system)) { + theCodeSystems.put(system, nextValueSet); + } + } else if (next.getResource() instanceof ValueSet) { + ValueSet nextValueSet = (ValueSet) next.getResource(); + nextValueSet.getText().setDivAsString(""); + String system = nextValueSet.getUrl(); + if (isNotBlank(system)) { + theValueSets.put(system, nextValueSet); + } } } + } finally { + IOUtils.closeQuietly(reader); + IOUtils.closeQuietly(inputStream); } } else { ourLog.warn("Unable to load resource: {}", theClasspath); diff --git a/hapi-fhir-structures-r4/src/main/java/org/hl7/fhir/r4/hapi/ctx/DefaultProfileValidationSupport.java b/hapi-fhir-structures-r4/src/main/java/org/hl7/fhir/r4/hapi/ctx/DefaultProfileValidationSupport.java index 120e25e8567..9e9637ca980 100644 --- a/hapi-fhir-structures-r4/src/main/java/org/hl7/fhir/r4/hapi/ctx/DefaultProfileValidationSupport.java +++ b/hapi-fhir-structures-r4/src/main/java/org/hl7/fhir/r4/hapi/ctx/DefaultProfileValidationSupport.java @@ -2,6 +2,7 @@ package org.hl7.fhir.r4.hapi.ctx; import ca.uhn.fhir.context.FhirContext; import org.apache.commons.io.Charsets; +import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import org.hl7.fhir.instance.model.api.IBaseResource; @@ -141,27 +142,33 @@ public class DefaultProfileValidationSupport implements IValidationSupport { private void loadCodeSystems(FhirContext theContext, Map theCodeSystems, Map theValueSets, String theClasspath) { ourLog.info("Loading CodeSystem/ValueSet from classpath: {}", theClasspath); - InputStream valuesetText = DefaultProfileValidationSupport.class.getResourceAsStream(theClasspath); - if (valuesetText != null) { - InputStreamReader reader = new InputStreamReader(valuesetText, Charsets.UTF_8); + InputStream inputStream = DefaultProfileValidationSupport.class.getResourceAsStream(theClasspath); + InputStreamReader reader = null; + if (inputStream != null) { + try { + reader = new InputStreamReader(inputStream, Charsets.UTF_8); - Bundle bundle = theContext.newXmlParser().parseResource(Bundle.class, reader); - for (BundleEntryComponent next : bundle.getEntry()) { - if (next.getResource() instanceof CodeSystem) { - CodeSystem nextValueSet = (CodeSystem) next.getResource(); - nextValueSet.getText().setDivAsString(""); - String system = nextValueSet.getUrl(); - if (isNotBlank(system)) { - theCodeSystems.put(system, nextValueSet); - } - } else if (next.getResource() instanceof ValueSet) { - ValueSet nextValueSet = (ValueSet) next.getResource(); - nextValueSet.getText().setDivAsString(""); - String system = nextValueSet.getUrl(); - if (isNotBlank(system)) { - theValueSets.put(system, nextValueSet); + Bundle bundle = theContext.newXmlParser().parseResource(Bundle.class, reader); + for (BundleEntryComponent next : bundle.getEntry()) { + if (next.getResource() instanceof CodeSystem) { + CodeSystem nextValueSet = (CodeSystem) next.getResource(); + nextValueSet.getText().setDivAsString(""); + String system = nextValueSet.getUrl(); + if (isNotBlank(system)) { + theCodeSystems.put(system, nextValueSet); + } + } else if (next.getResource() instanceof ValueSet) { + ValueSet nextValueSet = (ValueSet) next.getResource(); + nextValueSet.getText().setDivAsString(""); + String system = nextValueSet.getUrl(); + if (isNotBlank(system)) { + theValueSets.put(system, nextValueSet); + } } } + } finally { + IOUtils.closeQuietly(reader); + IOUtils.closeQuietly(inputStream); } } else { ourLog.warn("Unable to load resource: {}", theClasspath); diff --git a/hapi-fhir-validation/src/main/java/org/hl7/fhir/dstu3/hapi/validation/DefaultProfileValidationSupport.java b/hapi-fhir-validation/src/main/java/org/hl7/fhir/dstu3/hapi/validation/DefaultProfileValidationSupport.java index 70ff35e57b1..8bcc81dde0e 100644 --- a/hapi-fhir-validation/src/main/java/org/hl7/fhir/dstu3/hapi/validation/DefaultProfileValidationSupport.java +++ b/hapi-fhir-validation/src/main/java/org/hl7/fhir/dstu3/hapi/validation/DefaultProfileValidationSupport.java @@ -2,7 +2,7 @@ package org.hl7.fhir.dstu3.hapi.validation; import ca.uhn.fhir.context.FhirContext; import org.apache.commons.io.Charsets; -import org.apache.commons.lang.WordUtils; +import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport; @@ -24,243 +24,249 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank; public class DefaultProfileValidationSupport implements IValidationSupport { - private static final String URL_PREFIX_VALUE_SET = "http://hl7.org/fhir/ValueSet/"; - private static final String URL_PREFIX_STRUCTURE_DEFINITION = "http://hl7.org/fhir/StructureDefinition/"; - private static final String URL_PREFIX_STRUCTURE_DEFINITION_BASE = "http://hl7.org/fhir/"; + private static final String URL_PREFIX_VALUE_SET = "http://hl7.org/fhir/ValueSet/"; + private static final String URL_PREFIX_STRUCTURE_DEFINITION = "http://hl7.org/fhir/StructureDefinition/"; + private static final String URL_PREFIX_STRUCTURE_DEFINITION_BASE = "http://hl7.org/fhir/"; - private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(DefaultProfileValidationSupport.class); + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(DefaultProfileValidationSupport.class); - private Map myCodeSystems; - private Map myStructureDefinitions; - private Map myValueSets; + private Map myCodeSystems; + private Map myStructureDefinitions; + private Map myValueSets; - @Override - public ValueSetExpansionComponent expandValueSet(FhirContext theContext, ConceptSetComponent theInclude) { - ValueSetExpansionComponent retVal = new ValueSetExpansionComponent(); + @Override + public ValueSetExpansionComponent expandValueSet(FhirContext theContext, ConceptSetComponent theInclude) { + ValueSetExpansionComponent retVal = new ValueSetExpansionComponent(); - Set wantCodes = new HashSet(); - for (ConceptReferenceComponent next : theInclude.getConcept()) { - wantCodes.add(next.getCode()); - } + Set wantCodes = new HashSet<>(); + for (ConceptReferenceComponent next : theInclude.getConcept()) { + wantCodes.add(next.getCode()); + } - CodeSystem system = fetchCodeSystem(theContext, theInclude.getSystem()); - for (ConceptDefinitionComponent next : system.getConcept()) { - if (wantCodes.isEmpty() || wantCodes.contains(next.getCode())) { - retVal.addContains().setSystem(theInclude.getSystem()).setCode(next.getCode()).setDisplay(next.getDisplay()); - } - } + CodeSystem system = fetchCodeSystem(theContext, theInclude.getSystem()); + for (ConceptDefinitionComponent next : system.getConcept()) { + if (wantCodes.isEmpty() || wantCodes.contains(next.getCode())) { + retVal.addContains().setSystem(theInclude.getSystem()).setCode(next.getCode()).setDisplay(next.getDisplay()); + } + } - return retVal; - } + return retVal; + } - @Override - public List fetchAllConformanceResources(FhirContext theContext) { - ArrayList retVal = new ArrayList<>(); - retVal.addAll(myCodeSystems.values()); - retVal.addAll(myStructureDefinitions.values()); - retVal.addAll(myValueSets.values()); - return retVal; - } + @Override + public List fetchAllConformanceResources(FhirContext theContext) { + ArrayList retVal = new ArrayList<>(); + retVal.addAll(myCodeSystems.values()); + retVal.addAll(myStructureDefinitions.values()); + retVal.addAll(myValueSets.values()); + return retVal; + } - @Override - public List fetchAllStructureDefinitions(FhirContext theContext) { - return new ArrayList(provideStructureDefinitionMap(theContext).values()); - } + @Override + public List fetchAllStructureDefinitions(FhirContext theContext) { + return new ArrayList(provideStructureDefinitionMap(theContext).values()); + } - @Override - public CodeSystem fetchCodeSystem(FhirContext theContext, String theSystem) { - return (CodeSystem) fetchCodeSystemOrValueSet(theContext, theSystem, true); - } + @Override + public CodeSystem fetchCodeSystem(FhirContext theContext, String theSystem) { + return (CodeSystem) fetchCodeSystemOrValueSet(theContext, theSystem, true); + } - private DomainResource fetchCodeSystemOrValueSet(FhirContext theContext, String theSystem, boolean codeSystem) { - synchronized (this) { - Map codeSystems = myCodeSystems; - Map valueSets = myValueSets; - if (codeSystems == null || valueSets == null) { - codeSystems = new HashMap(); - valueSets = new HashMap(); + private DomainResource fetchCodeSystemOrValueSet(FhirContext theContext, String theSystem, boolean codeSystem) { + synchronized (this) { + Map codeSystems = myCodeSystems; + Map valueSets = myValueSets; + if (codeSystems == null || valueSets == null) { + codeSystems = new HashMap(); + valueSets = new HashMap(); - loadCodeSystems(theContext, codeSystems, valueSets, "/org/hl7/fhir/dstu3/model/valueset/valuesets.xml"); - loadCodeSystems(theContext, codeSystems, valueSets, "/org/hl7/fhir/dstu3/model/valueset/v2-tables.xml"); - loadCodeSystems(theContext, codeSystems, valueSets, "/org/hl7/fhir/dstu3/model/valueset/v3-codesystems.xml"); + loadCodeSystems(theContext, codeSystems, valueSets, "/org/hl7/fhir/dstu3/model/valueset/valuesets.xml"); + loadCodeSystems(theContext, codeSystems, valueSets, "/org/hl7/fhir/dstu3/model/valueset/v2-tables.xml"); + loadCodeSystems(theContext, codeSystems, valueSets, "/org/hl7/fhir/dstu3/model/valueset/v3-codesystems.xml"); - myCodeSystems = codeSystems; - myValueSets = valueSets; - } + myCodeSystems = codeSystems; + myValueSets = valueSets; + } - if (codeSystem) { - return codeSystems.get(theSystem); - } else { - return valueSets.get(theSystem); - } - } - } + if (codeSystem) { + return codeSystems.get(theSystem); + } else { + return valueSets.get(theSystem); + } + } + } - @SuppressWarnings("unchecked") - @Override - public T fetchResource(FhirContext theContext, Class theClass, String theUri) { - Validate.notBlank(theUri, "theUri must not be null or blank"); + @SuppressWarnings("unchecked") + @Override + public T fetchResource(FhirContext theContext, Class theClass, String theUri) { + Validate.notBlank(theUri, "theUri must not be null or blank"); - if (theClass.equals(StructureDefinition.class)) { - return (T) fetchStructureDefinition(theContext, theUri); - } + if (theClass.equals(StructureDefinition.class)) { + return (T) fetchStructureDefinition(theContext, theUri); + } - if (theClass.equals(ValueSet.class) || theUri.startsWith(URL_PREFIX_VALUE_SET)) { - return (T) fetchValueSet(theContext, theUri); - } + if (theClass.equals(ValueSet.class) || theUri.startsWith(URL_PREFIX_VALUE_SET)) { + return (T) fetchValueSet(theContext, theUri); + } - return null; - } + return null; + } - @Override - public StructureDefinition fetchStructureDefinition(FhirContext theContext, String theUrl) { - String url = theUrl; - if (url.startsWith(URL_PREFIX_STRUCTURE_DEFINITION)) { - // no change - } else if (url.indexOf('/') == -1) { - url = URL_PREFIX_STRUCTURE_DEFINITION + url; - } else if (StringUtils.countMatches(url, '/') == 1) { - url = URL_PREFIX_STRUCTURE_DEFINITION_BASE + url; - } - Map map = provideStructureDefinitionMap(theContext); - StructureDefinition retVal = map.get(url); + @Override + public StructureDefinition fetchStructureDefinition(FhirContext theContext, String theUrl) { + String url = theUrl; + if (url.startsWith(URL_PREFIX_STRUCTURE_DEFINITION)) { + // no change + } else if (url.indexOf('/') == -1) { + url = URL_PREFIX_STRUCTURE_DEFINITION + url; + } else if (StringUtils.countMatches(url, '/') == 1) { + url = URL_PREFIX_STRUCTURE_DEFINITION_BASE + url; + } + Map map = provideStructureDefinitionMap(theContext); + StructureDefinition retVal = map.get(url); - if (retVal == null && url.startsWith(URL_PREFIX_STRUCTURE_DEFINITION)) { - String tryUrl = URL_PREFIX_STRUCTURE_DEFINITION + StringUtils.capitalize(url.substring(URL_PREFIX_STRUCTURE_DEFINITION.length())); - retVal = map.get(tryUrl); - } + if (retVal == null && url.startsWith(URL_PREFIX_STRUCTURE_DEFINITION)) { + String tryUrl = URL_PREFIX_STRUCTURE_DEFINITION + StringUtils.capitalize(url.substring(URL_PREFIX_STRUCTURE_DEFINITION.length())); + retVal = map.get(tryUrl); + } - return retVal; - } + return retVal; + } - ValueSet fetchValueSet(FhirContext theContext, String theSystem) { - return (ValueSet) fetchCodeSystemOrValueSet(theContext, theSystem, false); - } + ValueSet fetchValueSet(FhirContext theContext, String theSystem) { + return (ValueSet) fetchCodeSystemOrValueSet(theContext, theSystem, false); + } - public void flush() { - myCodeSystems = null; - myStructureDefinitions = null; - } + public void flush() { + myCodeSystems = null; + myStructureDefinitions = null; + } - @Override - public boolean isCodeSystemSupported(FhirContext theContext, String theSystem) { - CodeSystem cs = fetchCodeSystem(theContext, theSystem); - return cs != null && cs.getContent() != CodeSystemContentMode.NOTPRESENT; - } + @Override + public boolean isCodeSystemSupported(FhirContext theContext, String theSystem) { + CodeSystem cs = fetchCodeSystem(theContext, theSystem); + return cs != null && cs.getContent() != CodeSystemContentMode.NOTPRESENT; + } - private void loadCodeSystems(FhirContext theContext, Map theCodeSystems, Map theValueSets, String theClasspath) { - ourLog.info("Loading CodeSystem/ValueSet from classpath: {}", theClasspath); - InputStream valuesetText = DefaultProfileValidationSupport.class.getResourceAsStream(theClasspath); - if (valuesetText != null) { - InputStreamReader reader = new InputStreamReader(valuesetText, Charsets.UTF_8); + private void loadCodeSystems(FhirContext theContext, Map theCodeSystems, Map theValueSets, String theClasspath) { + ourLog.info("Loading CodeSystem/ValueSet from classpath: {}", theClasspath); + InputStream inputStream = DefaultProfileValidationSupport.class.getResourceAsStream(theClasspath); + InputStreamReader reader = null; + if (inputStream != null) { + try { + reader = new InputStreamReader(inputStream, Charsets.UTF_8); - Bundle bundle = theContext.newXmlParser().parseResource(Bundle.class, reader); - for (BundleEntryComponent next : bundle.getEntry()) { - if (next.getResource() instanceof CodeSystem) { - CodeSystem nextValueSet = (CodeSystem) next.getResource(); - nextValueSet.getText().setDivAsString(""); - String system = nextValueSet.getUrl(); - if (isNotBlank(system)) { - theCodeSystems.put(system, nextValueSet); - } - } else if (next.getResource() instanceof ValueSet) { - ValueSet nextValueSet = (ValueSet) next.getResource(); - nextValueSet.getText().setDivAsString(""); - String system = nextValueSet.getUrl(); - if (isNotBlank(system)) { - theValueSets.put(system, nextValueSet); - } - } - } - } else { - ourLog.warn("Unable to load resource: {}", theClasspath); - } - } + Bundle bundle = theContext.newXmlParser().parseResource(Bundle.class, reader); + for (BundleEntryComponent next : bundle.getEntry()) { + if (next.getResource() instanceof CodeSystem) { + CodeSystem nextValueSet = (CodeSystem) next.getResource(); + nextValueSet.getText().setDivAsString(""); + String system = nextValueSet.getUrl(); + if (isNotBlank(system)) { + theCodeSystems.put(system, nextValueSet); + } + } else if (next.getResource() instanceof ValueSet) { + ValueSet nextValueSet = (ValueSet) next.getResource(); + nextValueSet.getText().setDivAsString(""); + String system = nextValueSet.getUrl(); + if (isNotBlank(system)) { + theValueSets.put(system, nextValueSet); + } + } + } + } finally { + IOUtils.closeQuietly(reader); + IOUtils.closeQuietly(inputStream); + } + } else { + ourLog.warn("Unable to load resource: {}", theClasspath); + } + } - private void loadStructureDefinitions(FhirContext theContext, Map theCodeSystems, String theClasspath) { - ourLog.info("Loading structure definitions from classpath: {}", theClasspath); - InputStream valuesetText = DefaultProfileValidationSupport.class.getResourceAsStream(theClasspath); - if (valuesetText != null) { - InputStreamReader reader = new InputStreamReader(valuesetText, Charsets.UTF_8); + private void loadStructureDefinitions(FhirContext theContext, Map theCodeSystems, String theClasspath) { + ourLog.info("Loading structure definitions from classpath: {}", theClasspath); + InputStream valuesetText = DefaultProfileValidationSupport.class.getResourceAsStream(theClasspath); + if (valuesetText != null) { + InputStreamReader reader = new InputStreamReader(valuesetText, Charsets.UTF_8); - Bundle bundle = theContext.newXmlParser().parseResource(Bundle.class, reader); - for (BundleEntryComponent next : bundle.getEntry()) { - if (next.getResource() instanceof StructureDefinition) { - StructureDefinition nextSd = (StructureDefinition) next.getResource(); - nextSd.getText().setDivAsString(""); - String system = nextSd.getUrl(); - if (isNotBlank(system)) { - theCodeSystems.put(system, nextSd); - } - } - } - } else { - ourLog.warn("Unable to load resource: {}", theClasspath); - } - } + Bundle bundle = theContext.newXmlParser().parseResource(Bundle.class, reader); + for (BundleEntryComponent next : bundle.getEntry()) { + if (next.getResource() instanceof StructureDefinition) { + StructureDefinition nextSd = (StructureDefinition) next.getResource(); + nextSd.getText().setDivAsString(""); + String system = nextSd.getUrl(); + if (isNotBlank(system)) { + theCodeSystems.put(system, nextSd); + } + } + } + } else { + ourLog.warn("Unable to load resource: {}", theClasspath); + } + } - private Map provideStructureDefinitionMap(FhirContext theContext) { - Map structureDefinitions = myStructureDefinitions; - if (structureDefinitions == null) { - structureDefinitions = new HashMap(); + private Map provideStructureDefinitionMap(FhirContext theContext) { + Map structureDefinitions = myStructureDefinitions; + if (structureDefinitions == null) { + structureDefinitions = new HashMap(); - loadStructureDefinitions(theContext, structureDefinitions, "/org/hl7/fhir/dstu3/model/profile/profiles-resources.xml"); - loadStructureDefinitions(theContext, structureDefinitions, "/org/hl7/fhir/dstu3/model/profile/profiles-types.xml"); - loadStructureDefinitions(theContext, structureDefinitions, "/org/hl7/fhir/dstu3/model/profile/profiles-others.xml"); + loadStructureDefinitions(theContext, structureDefinitions, "/org/hl7/fhir/dstu3/model/profile/profiles-resources.xml"); + loadStructureDefinitions(theContext, structureDefinitions, "/org/hl7/fhir/dstu3/model/profile/profiles-types.xml"); + loadStructureDefinitions(theContext, structureDefinitions, "/org/hl7/fhir/dstu3/model/profile/profiles-others.xml"); - myStructureDefinitions = structureDefinitions; - } - return structureDefinitions; - } + myStructureDefinitions = structureDefinitions; + } + return structureDefinitions; + } - private CodeValidationResult testIfConceptIsInList(String theCode, List conceptList, boolean theCaseSensitive) { - String code = theCode; - if (theCaseSensitive == false) { - code = code.toUpperCase(); - } + private CodeValidationResult testIfConceptIsInList(String theCode, List conceptList, boolean theCaseSensitive) { + String code = theCode; + if (theCaseSensitive == false) { + code = code.toUpperCase(); + } - return testIfConceptIsInListInner(conceptList, theCaseSensitive, code); - } + return testIfConceptIsInListInner(conceptList, theCaseSensitive, code); + } - private CodeValidationResult testIfConceptIsInListInner(List conceptList, boolean theCaseSensitive, String code) { - CodeValidationResult retVal = null; - for (ConceptDefinitionComponent next : conceptList) { - String nextCandidate = next.getCode(); - if (theCaseSensitive == false) { - nextCandidate = nextCandidate.toUpperCase(); - } - if (nextCandidate.equals(code)) { - retVal = new CodeValidationResult(next); - break; - } + private CodeValidationResult testIfConceptIsInListInner(List conceptList, boolean theCaseSensitive, String code) { + CodeValidationResult retVal = null; + for (ConceptDefinitionComponent next : conceptList) { + String nextCandidate = next.getCode(); + if (theCaseSensitive == false) { + nextCandidate = nextCandidate.toUpperCase(); + } + if (nextCandidate.equals(code)) { + retVal = new CodeValidationResult(next); + break; + } - // recurse - retVal = testIfConceptIsInList(code, next.getConcept(), theCaseSensitive); - if (retVal != null) { - break; - } - } + // recurse + retVal = testIfConceptIsInList(code, next.getConcept(), theCaseSensitive); + if (retVal != null) { + break; + } + } - return retVal; - } + return retVal; + } - @Override - public CodeValidationResult validateCode(FhirContext theContext, String theCodeSystem, String theCode, String theDisplay) { - CodeSystem cs = fetchCodeSystem(theContext, theCodeSystem); - if (cs != null) { - boolean caseSensitive = true; - if (cs.hasCaseSensitive()) { - caseSensitive = cs.getCaseSensitive(); - } + @Override + public CodeValidationResult validateCode(FhirContext theContext, String theCodeSystem, String theCode, String theDisplay) { + CodeSystem cs = fetchCodeSystem(theContext, theCodeSystem); + if (cs != null) { + boolean caseSensitive = true; + if (cs.hasCaseSensitive()) { + caseSensitive = cs.getCaseSensitive(); + } - CodeValidationResult retVal = testIfConceptIsInList(theCode, cs.getConcept(), caseSensitive); + CodeValidationResult retVal = testIfConceptIsInList(theCode, cs.getConcept(), caseSensitive); - if (retVal != null) { - return retVal; - } - } + if (retVal != null) { + return retVal; + } + } - return new CodeValidationResult(IssueSeverity.WARNING, "Unknown code: " + theCodeSystem + " / " + theCode); - } + return new CodeValidationResult(IssueSeverity.WARNING, "Unknown code: " + theCodeSystem + " / " + theCode); + } } diff --git a/hapi-fhir-validation/src/main/java/org/hl7/fhir/instance/hapi/validation/DefaultProfileValidationSupport.java b/hapi-fhir-validation/src/main/java/org/hl7/fhir/instance/hapi/validation/DefaultProfileValidationSupport.java index 24dcf7945a1..0523b22963c 100644 --- a/hapi-fhir-validation/src/main/java/org/hl7/fhir/instance/hapi/validation/DefaultProfileValidationSupport.java +++ b/hapi-fhir-validation/src/main/java/org/hl7/fhir/instance/hapi/validation/DefaultProfileValidationSupport.java @@ -2,6 +2,7 @@ package org.hl7.fhir.instance.hapi.validation; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; +import org.apache.commons.io.IOUtils; import org.hl7.fhir.instance.model.Bundle; import org.hl7.fhir.instance.model.Bundle.BundleEntryComponent; import org.hl7.fhir.instance.model.CodeType; @@ -44,9 +45,9 @@ public class DefaultProfileValidationSupport implements IValidationSupport { if (valueSets == null) { valueSets = new HashMap(); - loadCodeSystems(theContext, valueSets, "/org/hl7/fhir/instance/model/valueset/valuesets.xml"); - loadCodeSystems(theContext, valueSets, "/org/hl7/fhir/instance/model/valueset/v2-tables.xml"); - loadCodeSystems(theContext, valueSets, "/org/hl7/fhir/instance/model/valueset/v3-codesystems.xml"); + loadValueSets(theContext, valueSets, "/org/hl7/fhir/instance/model/valueset/valuesets.xml"); + loadValueSets(theContext, valueSets, "/org/hl7/fhir/instance/model/valueset/v2-tables.xml"); + loadValueSets(theContext, valueSets, "/org/hl7/fhir/instance/model/valueset/v3-codesystems.xml"); myCodeSystems = valueSets; } @@ -108,26 +109,34 @@ public class DefaultProfileValidationSupport implements IValidationSupport { return false; } - private void loadCodeSystems(FhirContext theContext, Map codeSystems, String file) { - InputStream valuesetText = DefaultProfileValidationSupport.class.getResourceAsStream(file); - if (valuesetText != null) { - InputStreamReader reader; - try { - reader = new InputStreamReader(valuesetText, "UTF-8"); - } catch (UnsupportedEncodingException e) { - // Shouldn't happen! - throw new InternalErrorException("UTF-8 encoding not supported on this platform", e); - } + private void loadValueSets(FhirContext theContext, Map theValueSets, String theFile) { + InputStream valuesetText = DefaultProfileValidationSupport.class.getResourceAsStream(theFile); + try { + if (valuesetText != null) { + InputStreamReader reader = null; + try { + reader = new InputStreamReader(valuesetText, "UTF-8"); - FhirContext ctx = FhirInstanceValidator.getHl7OrgDstu2Ctx(theContext); - Bundle bundle = ctx.newXmlParser().parseResource(Bundle.class, reader); - for (BundleEntryComponent next : bundle.getEntry()) { - ValueSet nextValueSet = (ValueSet) next.getResource(); - String system = nextValueSet.getCodeSystem().getSystem(); - if (isNotBlank(system)) { - codeSystems.put(system, nextValueSet); + FhirContext ctx = FhirInstanceValidator.getHl7OrgDstu2Ctx(theContext); + Bundle bundle = ctx.newXmlParser().parseResource(Bundle.class, reader); + for (BundleEntryComponent next : bundle.getEntry()) { + ValueSet nextValueSet = (ValueSet) next.getResource(); + String system = nextValueSet.getCodeSystem().getSystem(); + if (isNotBlank(system)) { + theValueSets.put(system, nextValueSet); + } + } + + } catch (UnsupportedEncodingException e) { + // Shouldn't happen! + throw new InternalErrorException("UTF-8 encoding not supported on this platform", e); + } finally { + IOUtils.closeQuietly(reader); } + } + } finally { + IOUtils.closeQuietly(valuesetText); } } @@ -136,7 +145,7 @@ public class DefaultProfileValidationSupport implements IValidationSupport { ValueSet vs = fetchCodeSystem(theContext, theCodeSystem); if (vs != null) { for (ValueSet.ConceptDefinitionComponent nextConcept : vs.getCodeSystem().getConcept()) { - if (nextConcept.getCode().equals(theCode)){ + if (nextConcept.getCode().equals(theCode)) { ValueSet.ConceptDefinitionComponent component = new ValueSet.ConceptDefinitionComponent(new CodeType(theCode)); return new CodeValidationResult(component); } diff --git a/src/changes/changes.xml b/src/changes/changes.xml index c81de4b20f3..deb332e5c0a 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -297,6 +297,13 @@ Suport for the :contains string search parameter modifier has been added to the JPA server. Thanks to Anthony Sute for the pull request! + + All instances of DefaultProfileValidationSupport (i.e. one for + each version of FHIR) have been fixed so that they explicitly + close any InputStreams they open in order to read the built-in + profile resources. Leaving these open caused resource starvation + in some cases under heavy load. +