Merge pull request #972 from hapifhir/do-terminology-cache-filewpipechar
Fix pipes in terminologyCache files
This commit is contained in:
commit
d19ff2e1f6
|
@ -1,33 +1,33 @@
|
|||
package org.hl7.fhir.r4.context;
|
||||
|
||||
/*
|
||||
Copyright (c) 2011+, HL7, Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of HL7 nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
/*
|
||||
Copyright (c) 2011+, HL7, Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of HL7 nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
@ -84,16 +84,88 @@ public class TerminologyCache {
|
|||
private static final String ENTRY_MARKER = "-------------------------------------------------------------------------------------";
|
||||
private static final String BREAK = "####";
|
||||
|
||||
private SystemNameKeyGenerator systemNameKeyGenerator = new SystemNameKeyGenerator();
|
||||
|
||||
protected SystemNameKeyGenerator getSystemNameKeyGenerator() {
|
||||
return systemNameKeyGenerator;
|
||||
}
|
||||
|
||||
public class SystemNameKeyGenerator {
|
||||
public static final String SNOMED_SCT_CODESYSTEM_URL = "http://snomed.info/sct";
|
||||
public static final String RXNORM_CODESYSTEM_URL = "http://www.nlm.nih.gov/research/umls/rxnorm";
|
||||
public static final String LOINC_CODESYSTEM_URL = "http://loinc.org";
|
||||
public static final String UCUM_CODESYSTEM_URL = "http://unitsofmeasure.org";
|
||||
|
||||
public static final String HL7_TERMINOLOGY_CODESYSTEM_BASE_URL = "http://terminology.hl7.org/CodeSystem/";
|
||||
public static final String HL7_SID_CODESYSTEM_BASE_URL = "http://hl7.org/fhir/sid/";
|
||||
public static final String HL7_FHIR_CODESYSTEM_BASE_URL = "http://hl7.org/fhir/";
|
||||
|
||||
public static final String ISO_CODESYSTEM_URN = "urn:iso:std:iso:";
|
||||
public static final String LANG_CODESYSTEM_URN = "urn:ietf:bcp:47";
|
||||
public static final String MIMETYPES_CODESYSTEM_URN = "urn:ietf:bcp:13";
|
||||
|
||||
public static final String _11073_CODESYSTEM_URN = "urn:iso:std:iso:11073:10101";
|
||||
public static final String DICOM_CODESYSTEM_URL = "http://dicom.nema.org/resources/ontology/DCM";
|
||||
|
||||
public String getNameForSystem(String system) {
|
||||
final int lastPipe = system.lastIndexOf('|');
|
||||
final String systemBaseName = lastPipe == -1 ? system : system.substring(0,lastPipe);
|
||||
final String systemVersion = lastPipe == -1 ? null : system.substring(lastPipe + 1);
|
||||
|
||||
if (systemBaseName.equals(SNOMED_SCT_CODESYSTEM_URL))
|
||||
return getVersionedSystem("snomed", systemVersion);
|
||||
if (systemBaseName.equals(RXNORM_CODESYSTEM_URL))
|
||||
return getVersionedSystem("rxnorm", systemVersion);
|
||||
if (systemBaseName.equals(LOINC_CODESYSTEM_URL))
|
||||
return getVersionedSystem("loinc", systemVersion);
|
||||
if (systemBaseName.equals(UCUM_CODESYSTEM_URL))
|
||||
return getVersionedSystem("ucum", systemVersion);
|
||||
if (systemBaseName.startsWith(HL7_SID_CODESYSTEM_BASE_URL))
|
||||
return getVersionedSystem(normalizeBaseURL(HL7_SID_CODESYSTEM_BASE_URL, systemBaseName), systemVersion);
|
||||
if (systemBaseName.equals(_11073_CODESYSTEM_URN))
|
||||
return getVersionedSystem("11073", systemVersion);
|
||||
if (systemBaseName.startsWith(ISO_CODESYSTEM_URN))
|
||||
return getVersionedSystem("iso"+systemBaseName.substring(ISO_CODESYSTEM_URN.length()).replace(":", ""), systemVersion);
|
||||
if (systemBaseName.startsWith(HL7_TERMINOLOGY_CODESYSTEM_BASE_URL))
|
||||
return getVersionedSystem(normalizeBaseURL(HL7_TERMINOLOGY_CODESYSTEM_BASE_URL, systemBaseName), systemVersion);
|
||||
if (systemBaseName.startsWith(HL7_FHIR_CODESYSTEM_BASE_URL))
|
||||
return getVersionedSystem(normalizeBaseURL(HL7_FHIR_CODESYSTEM_BASE_URL, systemBaseName), systemVersion);
|
||||
if (systemBaseName.equals(LANG_CODESYSTEM_URN))
|
||||
return getVersionedSystem("lang", systemVersion);
|
||||
if (systemBaseName.equals(MIMETYPES_CODESYSTEM_URN))
|
||||
return getVersionedSystem("mimetypes", systemVersion);
|
||||
if (systemBaseName.equals(DICOM_CODESYSTEM_URL))
|
||||
return getVersionedSystem("dicom", systemVersion);
|
||||
return getVersionedSystem(systemBaseName.replace("/", "_").replace(":", "_").replace("?", "X").replace("#", "X"), systemVersion);
|
||||
}
|
||||
|
||||
public String normalizeBaseURL(String baseUrl, String fullUrl) {
|
||||
return fullUrl.substring(baseUrl.length()).replace("/", "");
|
||||
}
|
||||
|
||||
public String getVersionedSystem(String baseSystem, String version) {
|
||||
if (version != null) {
|
||||
return baseSystem + "_" + version;
|
||||
}
|
||||
return baseSystem;
|
||||
}
|
||||
}
|
||||
|
||||
public class CacheToken {
|
||||
private String name;
|
||||
private String key;
|
||||
private String request;
|
||||
public void setName(String n) {
|
||||
String systemName = getSystemNameKeyGenerator().getNameForSystem(n);
|
||||
if (name == null)
|
||||
name = n;
|
||||
else if (!n.equals(name))
|
||||
name = systemName;
|
||||
else if (!systemName.equals(name))
|
||||
name = NAME_FOR_NO_SYSTEM;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
private class CacheEntry {
|
||||
|
@ -126,7 +198,7 @@ public class TerminologyCache {
|
|||
public CacheToken generateValidationToken(ValidationOptions options, Coding code, ValueSet vs) {
|
||||
CacheToken ct = new CacheToken();
|
||||
if (code.hasSystem())
|
||||
ct.name = getNameForSystem(code.getSystem());
|
||||
ct.name = getSystemNameKeyGenerator().getNameForSystem(code.getSystem());
|
||||
else
|
||||
ct.name = NAME_FOR_NO_SYSTEM;
|
||||
JsonParser json = new JsonParser();
|
||||
|
@ -145,7 +217,7 @@ public class TerminologyCache {
|
|||
CacheToken ct = new CacheToken();
|
||||
for (Coding c : code.getCoding()) {
|
||||
if (c.hasSystem())
|
||||
ct.setName(getNameForSystem(c.getSystem()));
|
||||
ct.setName(c.getSystem());
|
||||
}
|
||||
JsonParser json = new JsonParser();
|
||||
json.setOutputStyle(OutputStyle.PRETTY);
|
||||
|
@ -176,13 +248,13 @@ public class TerminologyCache {
|
|||
ValueSet vsc = getVSEssense(vs);
|
||||
for (ConceptSetComponent inc : vs.getCompose().getInclude())
|
||||
if (inc.hasSystem())
|
||||
ct.setName(getNameForSystem(inc.getSystem()));
|
||||
ct.setName(inc.getSystem());
|
||||
for (ConceptSetComponent inc : vs.getCompose().getExclude())
|
||||
if (inc.hasSystem())
|
||||
ct.setName(getNameForSystem(inc.getSystem()));
|
||||
ct.setName(inc.getSystem());
|
||||
for (ValueSetExpansionContainsComponent inc : vs.getExpansion().getContains())
|
||||
if (inc.hasSystem())
|
||||
ct.setName(getNameForSystem(inc.getSystem()));
|
||||
ct.setName(inc.getSystem());
|
||||
JsonParser json = new JsonParser();
|
||||
json.setOutputStyle(OutputStyle.PRETTY);
|
||||
try {
|
||||
|
@ -194,34 +266,6 @@ public class TerminologyCache {
|
|||
return ct;
|
||||
}
|
||||
|
||||
private String getNameForSystem(String system) {
|
||||
if (system.equals("http://snomed.info/sct"))
|
||||
return "snomed";
|
||||
if (system.equals("http://www.nlm.nih.gov/research/umls/rxnorm"))
|
||||
return "rxnorm";
|
||||
if (system.equals("http://loinc.org"))
|
||||
return "loinc";
|
||||
if (system.equals("http://unitsofmeasure.org"))
|
||||
return "ucum";
|
||||
if (system.startsWith("http://hl7.org/fhir/sid/"))
|
||||
return system.substring(24).replace("/", "");
|
||||
if (system.startsWith("urn:iso:std:iso:"))
|
||||
return "iso"+system.substring(16).replace(":", "");
|
||||
if (system.startsWith("http://terminology.hl7.org/CodeSystem/"))
|
||||
return system.substring(38).replace("/", "");
|
||||
if (system.startsWith("http://hl7.org/fhir/"))
|
||||
return system.substring(20).replace("/", "");
|
||||
if (system.equals("urn:ietf:bcp:47"))
|
||||
return "lang";
|
||||
if (system.equals("urn:ietf:bcp:13"))
|
||||
return "mimetypes";
|
||||
if (system.equals("urn:iso:std:iso:11073:10101"))
|
||||
return "11073";
|
||||
if (system.equals("http://dicom.nema.org/resources/ontology/DCM"))
|
||||
return "dicom";
|
||||
return system.replace("/", "_").replace(":", "_");
|
||||
}
|
||||
|
||||
public NamedCache getNamedCache(CacheToken cacheToken) {
|
||||
NamedCache nc = caches.get(cacheToken.name);
|
||||
if (nc == null) {
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
package org.hl7.fhir.r4.context;
|
||||
|
||||
import org.hl7.fhir.utilities.validation.ValidationOptions;
|
||||
|
||||
public class CacheTestUtils {
|
||||
public static final ValidationOptions validationOptions = new ValidationOptions().guessSystem().setVersionFlexible(false);
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package org.hl7.fhir.r4.context;
|
||||
|
||||
|
||||
import org.hl7.fhir.r4.model.Coding;
|
||||
import org.hl7.fhir.r4.model.ValueSet;
|
||||
|
||||
import org.hl7.fhir.utilities.tests.ResourceLoaderTests;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.CsvSource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
|
||||
public class TerminologyCacheTests implements ResourceLoaderTests {
|
||||
|
||||
private TerminologyCache createTerminologyCache() throws IOException {
|
||||
Object lock = new Object();
|
||||
TerminologyCache terminologyCache = new TerminologyCache(lock, null);
|
||||
return terminologyCache;
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource({
|
||||
"http://terminology.hl7.org/CodeSystem/id,id",
|
||||
"http://hl7.org/fhir/id,id",
|
||||
"http://hl7.org/fhir/sid/id,id",
|
||||
"http://www.nlm.nih.gov/research/umls/rxnorm,rxnorm",
|
||||
"http://snomed.info/sct,snomed",
|
||||
"http://www.nlm.nih.gov/research/umls/rxnorm,rxnorm",
|
||||
"http://loinc.org,loinc",
|
||||
"http://unitsofmeasure.org,ucum",
|
||||
"urn:iso:std:iso:id,isoid",
|
||||
"urn:ietf:bcp:47,lang",
|
||||
"urn:ietf:bcp:13,mimetypes",
|
||||
"urn:iso:std:iso:11073:10101,11073",
|
||||
"my://random/system?with#chars,my___random_systemXwithXchars",
|
||||
"http://dicom.nema.org/resources/ontology/DCM,dicom"
|
||||
})
|
||||
public void testCacheTokenGeneration(String system, String expectedName) throws IOException, URISyntaxException {
|
||||
|
||||
TerminologyCache terminologyCache = createTerminologyCache();
|
||||
ValueSet valueSet = new ValueSet();
|
||||
{
|
||||
Coding coding = new Coding();
|
||||
coding.setSystem(system);
|
||||
TerminologyCache.CacheToken cacheToken = terminologyCache.generateValidationToken(CacheTestUtils.validationOptions,
|
||||
coding, valueSet);
|
||||
assertEquals(expectedName, cacheToken.getName());
|
||||
}
|
||||
{
|
||||
Coding coding = new Coding();
|
||||
coding.setSystem(system + "|dummyVersion");
|
||||
TerminologyCache.CacheToken cacheToken = terminologyCache.generateValidationToken(CacheTestUtils.validationOptions,
|
||||
coding, valueSet);
|
||||
assertEquals(expectedName + "_dummyVersion", cacheToken.getName());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,33 +1,33 @@
|
|||
package org.hl7.fhir.r4b.context;
|
||||
|
||||
/*
|
||||
Copyright (c) 2011+, HL7, Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of HL7 nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
/*
|
||||
Copyright (c) 2011+, HL7, Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of HL7 nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
@ -84,16 +84,88 @@ public class TerminologyCache {
|
|||
private static final String ENTRY_MARKER = "-------------------------------------------------------------------------------------";
|
||||
private static final String BREAK = "####";
|
||||
|
||||
private SystemNameKeyGenerator systemNameKeyGenerator = new SystemNameKeyGenerator();
|
||||
|
||||
protected SystemNameKeyGenerator getSystemNameKeyGenerator() {
|
||||
return systemNameKeyGenerator;
|
||||
}
|
||||
|
||||
public class SystemNameKeyGenerator {
|
||||
public static final String SNOMED_SCT_CODESYSTEM_URL = "http://snomed.info/sct";
|
||||
public static final String RXNORM_CODESYSTEM_URL = "http://www.nlm.nih.gov/research/umls/rxnorm";
|
||||
public static final String LOINC_CODESYSTEM_URL = "http://loinc.org";
|
||||
public static final String UCUM_CODESYSTEM_URL = "http://unitsofmeasure.org";
|
||||
|
||||
public static final String HL7_TERMINOLOGY_CODESYSTEM_BASE_URL = "http://terminology.hl7.org/CodeSystem/";
|
||||
public static final String HL7_SID_CODESYSTEM_BASE_URL = "http://hl7.org/fhir/sid/";
|
||||
public static final String HL7_FHIR_CODESYSTEM_BASE_URL = "http://hl7.org/fhir/";
|
||||
|
||||
public static final String ISO_CODESYSTEM_URN = "urn:iso:std:iso:";
|
||||
public static final String LANG_CODESYSTEM_URN = "urn:ietf:bcp:47";
|
||||
public static final String MIMETYPES_CODESYSTEM_URN = "urn:ietf:bcp:13";
|
||||
|
||||
public static final String _11073_CODESYSTEM_URN = "urn:iso:std:iso:11073:10101";
|
||||
public static final String DICOM_CODESYSTEM_URL = "http://dicom.nema.org/resources/ontology/DCM";
|
||||
|
||||
public String getNameForSystem(String system) {
|
||||
final int lastPipe = system.lastIndexOf('|');
|
||||
final String systemBaseName = lastPipe == -1 ? system : system.substring(0,lastPipe);
|
||||
final String systemVersion = lastPipe == -1 ? null : system.substring(lastPipe + 1);
|
||||
|
||||
if (systemBaseName.equals(SNOMED_SCT_CODESYSTEM_URL))
|
||||
return getVersionedSystem("snomed", systemVersion);
|
||||
if (systemBaseName.equals(RXNORM_CODESYSTEM_URL))
|
||||
return getVersionedSystem("rxnorm", systemVersion);
|
||||
if (systemBaseName.equals(LOINC_CODESYSTEM_URL))
|
||||
return getVersionedSystem("loinc", systemVersion);
|
||||
if (systemBaseName.equals(UCUM_CODESYSTEM_URL))
|
||||
return getVersionedSystem("ucum", systemVersion);
|
||||
if (systemBaseName.startsWith(HL7_SID_CODESYSTEM_BASE_URL))
|
||||
return getVersionedSystem(normalizeBaseURL(HL7_SID_CODESYSTEM_BASE_URL, systemBaseName), systemVersion);
|
||||
if (systemBaseName.equals(_11073_CODESYSTEM_URN))
|
||||
return getVersionedSystem("11073", systemVersion);
|
||||
if (systemBaseName.startsWith(ISO_CODESYSTEM_URN))
|
||||
return getVersionedSystem("iso"+systemBaseName.substring(ISO_CODESYSTEM_URN.length()).replace(":", ""), systemVersion);
|
||||
if (systemBaseName.startsWith(HL7_TERMINOLOGY_CODESYSTEM_BASE_URL))
|
||||
return getVersionedSystem(normalizeBaseURL(HL7_TERMINOLOGY_CODESYSTEM_BASE_URL, systemBaseName), systemVersion);
|
||||
if (systemBaseName.startsWith(HL7_FHIR_CODESYSTEM_BASE_URL))
|
||||
return getVersionedSystem(normalizeBaseURL(HL7_FHIR_CODESYSTEM_BASE_URL, systemBaseName), systemVersion);
|
||||
if (systemBaseName.equals(LANG_CODESYSTEM_URN))
|
||||
return getVersionedSystem("lang", systemVersion);
|
||||
if (systemBaseName.equals(MIMETYPES_CODESYSTEM_URN))
|
||||
return getVersionedSystem("mimetypes", systemVersion);
|
||||
if (systemBaseName.equals(DICOM_CODESYSTEM_URL))
|
||||
return getVersionedSystem("dicom", systemVersion);
|
||||
return getVersionedSystem(systemBaseName.replace("/", "_").replace(":", "_").replace("?", "X").replace("#", "X"), systemVersion);
|
||||
}
|
||||
|
||||
public String normalizeBaseURL(String baseUrl, String fullUrl) {
|
||||
return fullUrl.substring(baseUrl.length()).replace("/", "");
|
||||
}
|
||||
|
||||
public String getVersionedSystem(String baseSystem, String version) {
|
||||
if (version != null) {
|
||||
return baseSystem + "_" + version;
|
||||
}
|
||||
return baseSystem;
|
||||
}
|
||||
}
|
||||
|
||||
public class CacheToken {
|
||||
private String name;
|
||||
private String key;
|
||||
private String request;
|
||||
public void setName(String n) {
|
||||
String systemName = getSystemNameKeyGenerator().getNameForSystem(n);
|
||||
if (name == null)
|
||||
name = n;
|
||||
else if (!n.equals(name))
|
||||
name = systemName;
|
||||
else if (!systemName.equals(name))
|
||||
name = NAME_FOR_NO_SYSTEM;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
private class CacheEntry {
|
||||
|
@ -130,7 +202,7 @@ public class TerminologyCache {
|
|||
public CacheToken generateValidationToken(ValidationOptions options, Coding code, ValueSet vs) {
|
||||
CacheToken ct = new CacheToken();
|
||||
if (code.hasSystem())
|
||||
ct.name = getNameForSystem(code.getSystem());
|
||||
ct.name = getSystemNameKeyGenerator().getNameForSystem(code.getSystem());
|
||||
else
|
||||
ct.name = NAME_FOR_NO_SYSTEM;
|
||||
JsonParser json = new JsonParser();
|
||||
|
@ -159,7 +231,7 @@ public class TerminologyCache {
|
|||
CacheToken ct = new CacheToken();
|
||||
for (Coding c : code.getCoding()) {
|
||||
if (c.hasSystem())
|
||||
ct.setName(getNameForSystem(c.getSystem()));
|
||||
ct.setName(c.getSystem());
|
||||
}
|
||||
JsonParser json = new JsonParser();
|
||||
json.setOutputStyle(OutputStyle.PRETTY);
|
||||
|
@ -190,13 +262,13 @@ public class TerminologyCache {
|
|||
ValueSet vsc = getVSEssense(vs);
|
||||
for (ConceptSetComponent inc : vs.getCompose().getInclude())
|
||||
if (inc.hasSystem())
|
||||
ct.setName(getNameForSystem(inc.getSystem()));
|
||||
ct.setName(inc.getSystem());
|
||||
for (ConceptSetComponent inc : vs.getCompose().getExclude())
|
||||
if (inc.hasSystem())
|
||||
ct.setName(getNameForSystem(inc.getSystem()));
|
||||
ct.setName(inc.getSystem());
|
||||
for (ValueSetExpansionContainsComponent inc : vs.getExpansion().getContains())
|
||||
if (inc.hasSystem())
|
||||
ct.setName(getNameForSystem(inc.getSystem()));
|
||||
ct.setName(inc.getSystem());
|
||||
JsonParser json = new JsonParser();
|
||||
json.setOutputStyle(OutputStyle.PRETTY);
|
||||
try {
|
||||
|
@ -208,33 +280,7 @@ public class TerminologyCache {
|
|||
return ct;
|
||||
}
|
||||
|
||||
private String getNameForSystem(String system) {
|
||||
if (system.equals("http://snomed.info/sct"))
|
||||
return "snomed";
|
||||
if (system.equals("http://www.nlm.nih.gov/research/umls/rxnorm"))
|
||||
return "rxnorm";
|
||||
if (system.equals("http://loinc.org"))
|
||||
return "loinc";
|
||||
if (system.equals("http://unitsofmeasure.org"))
|
||||
return "ucum";
|
||||
if (system.startsWith("http://hl7.org/fhir/sid/"))
|
||||
return system.substring(24).replace("/", "");
|
||||
if (system.startsWith("urn:iso:std:iso:"))
|
||||
return "iso"+system.substring(16).replace(":", "");
|
||||
if (system.startsWith("http://terminology.hl7.org/CodeSystem/"))
|
||||
return system.substring(38).replace("/", "");
|
||||
if (system.startsWith("http://hl7.org/fhir/"))
|
||||
return system.substring(20).replace("/", "");
|
||||
if (system.equals("urn:ietf:bcp:47"))
|
||||
return "lang";
|
||||
if (system.equals("urn:ietf:bcp:13"))
|
||||
return "mimetypes";
|
||||
if (system.equals("urn:iso:std:iso:11073:10101"))
|
||||
return "11073";
|
||||
if (system.equals("http://dicom.nema.org/resources/ontology/DCM"))
|
||||
return "dicom";
|
||||
return system.replace("/", "_").replace(":", "_").replace("?", "X").replace("#", "X");
|
||||
}
|
||||
|
||||
|
||||
public NamedCache getNamedCache(CacheToken cacheToken) {
|
||||
NamedCache nc = caches.get(cacheToken.name);
|
||||
|
@ -520,7 +566,7 @@ public class TerminologyCache {
|
|||
|
||||
public void removeCS(String url) {
|
||||
synchronized (lock) {
|
||||
String name = getNameForSystem(url);
|
||||
String name = getSystemNameKeyGenerator().getNameForSystem(url);
|
||||
if (caches.containsKey(name)) {
|
||||
caches.remove(name);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
package org.hl7.fhir.r4b.context;
|
||||
|
||||
import org.hl7.fhir.utilities.validation.ValidationOptions;
|
||||
|
||||
public class CacheTestUtils {
|
||||
public static final ValidationOptions validationOptions = new ValidationOptions().guessSystem().setVersionFlexible(false);
|
||||
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
package org.hl7.fhir.r4b.context;
|
||||
|
||||
|
||||
import org.hl7.fhir.r4b.model.Coding;
|
||||
import org.hl7.fhir.r4b.model.ValueSet;
|
||||
import org.hl7.fhir.utilities.tests.ResourceLoaderTests;
|
||||
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
|
||||
import org.junit.jupiter.params.provider.CsvSource;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
|
||||
public class TerminologyCacheTests implements ResourceLoaderTests {
|
||||
|
||||
|
||||
|
||||
private TerminologyCache createTerminologyCache() throws IOException {
|
||||
Object lock = new Object();
|
||||
TerminologyCache terminologyCache = new TerminologyCache(lock, null);
|
||||
return terminologyCache;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource({
|
||||
"http://terminology.hl7.org/CodeSystem/id,id",
|
||||
"http://hl7.org/fhir/id,id",
|
||||
"http://hl7.org/fhir/sid/id,id",
|
||||
"http://www.nlm.nih.gov/research/umls/rxnorm,rxnorm",
|
||||
"http://snomed.info/sct,snomed",
|
||||
"http://www.nlm.nih.gov/research/umls/rxnorm,rxnorm",
|
||||
"http://loinc.org,loinc",
|
||||
"http://unitsofmeasure.org,ucum",
|
||||
"urn:iso:std:iso:id,isoid",
|
||||
"urn:ietf:bcp:47,lang",
|
||||
"urn:ietf:bcp:13,mimetypes",
|
||||
"urn:iso:std:iso:11073:10101,11073",
|
||||
"my://random/system?with#chars,my___random_systemXwithXchars",
|
||||
"http://dicom.nema.org/resources/ontology/DCM,dicom"
|
||||
})
|
||||
public void testCacheTokenGeneration(String system, String expectedName) throws IOException, URISyntaxException {
|
||||
|
||||
TerminologyCache terminologyCache = createTerminologyCache();
|
||||
ValueSet valueSet = new ValueSet();
|
||||
{
|
||||
Coding coding = new Coding();
|
||||
coding.setSystem(system);
|
||||
TerminologyCache.CacheToken cacheToken = terminologyCache.generateValidationToken(CacheTestUtils.validationOptions,
|
||||
coding, valueSet);
|
||||
assertEquals(expectedName, cacheToken.getName());
|
||||
}
|
||||
{
|
||||
Coding coding = new Coding();
|
||||
coding.setSystem(system + "|dummyVersion");
|
||||
TerminologyCache.CacheToken cacheToken = terminologyCache.generateValidationToken(CacheTestUtils.validationOptions,
|
||||
coding, valueSet);
|
||||
assertEquals(expectedName + "_dummyVersion", cacheToken.getName());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -38,7 +38,6 @@ import java.io.IOException;
|
|||
import java.io.OutputStreamWriter;
|
||||
import java.util.*;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
|
@ -85,6 +84,9 @@ public class TerminologyCache {
|
|||
private static final String CAPABILITY_STATEMENT_TITLE = ".capabilityStatement";
|
||||
private static final String TERMINOLOGY_CAPABILITIES_TITLE = ".terminologyCapabilities";
|
||||
|
||||
|
||||
private SystemNameKeyGenerator systemNameKeyGenerator = new SystemNameKeyGenerator();
|
||||
|
||||
public class CacheToken {
|
||||
@Getter
|
||||
private String name;
|
||||
|
@ -96,13 +98,79 @@ public class TerminologyCache {
|
|||
private boolean hasVersion;
|
||||
|
||||
public void setName(String n) {
|
||||
String systemName = getSystemNameKeyGenerator().getNameForSystem(n);
|
||||
if (name == null)
|
||||
name = n;
|
||||
else if (!n.equals(name))
|
||||
name = systemName;
|
||||
else if (!systemName.equals(name))
|
||||
name = NAME_FOR_NO_SYSTEM;
|
||||
}
|
||||
}
|
||||
|
||||
protected SystemNameKeyGenerator getSystemNameKeyGenerator() {
|
||||
return systemNameKeyGenerator;
|
||||
}
|
||||
public class SystemNameKeyGenerator {
|
||||
public static final String SNOMED_SCT_CODESYSTEM_URL = "http://snomed.info/sct";
|
||||
public static final String RXNORM_CODESYSTEM_URL = "http://www.nlm.nih.gov/research/umls/rxnorm";
|
||||
public static final String LOINC_CODESYSTEM_URL = "http://loinc.org";
|
||||
public static final String UCUM_CODESYSTEM_URL = "http://unitsofmeasure.org";
|
||||
|
||||
public static final String HL7_TERMINOLOGY_CODESYSTEM_BASE_URL = "http://terminology.hl7.org/CodeSystem/";
|
||||
public static final String HL7_SID_CODESYSTEM_BASE_URL = "http://hl7.org/fhir/sid/";
|
||||
public static final String HL7_FHIR_CODESYSTEM_BASE_URL = "http://hl7.org/fhir/";
|
||||
|
||||
public static final String ISO_CODESYSTEM_URN = "urn:iso:std:iso:";
|
||||
public static final String LANG_CODESYSTEM_URN = "urn:ietf:bcp:47";
|
||||
public static final String MIMETYPES_CODESYSTEM_URN = "urn:ietf:bcp:13";
|
||||
|
||||
public static final String _11073_CODESYSTEM_URN = "urn:iso:std:iso:11073:10101";
|
||||
public static final String DICOM_CODESYSTEM_URL = "http://dicom.nema.org/resources/ontology/DCM";
|
||||
|
||||
public String getNameForSystem(String system) {
|
||||
final int lastPipe = system.lastIndexOf('|');
|
||||
final String systemBaseName = lastPipe == -1 ? system : system.substring(0,lastPipe);
|
||||
final String systemVersion = lastPipe == -1 ? null : system.substring(lastPipe + 1);
|
||||
|
||||
if (systemBaseName.equals(SNOMED_SCT_CODESYSTEM_URL))
|
||||
return getVersionedSystem("snomed", systemVersion);
|
||||
if (systemBaseName.equals(RXNORM_CODESYSTEM_URL))
|
||||
return getVersionedSystem("rxnorm", systemVersion);
|
||||
if (systemBaseName.equals(LOINC_CODESYSTEM_URL))
|
||||
return getVersionedSystem("loinc", systemVersion);
|
||||
if (systemBaseName.equals(UCUM_CODESYSTEM_URL))
|
||||
return getVersionedSystem("ucum", systemVersion);
|
||||
if (systemBaseName.startsWith(HL7_SID_CODESYSTEM_BASE_URL))
|
||||
return getVersionedSystem(normalizeBaseURL(HL7_SID_CODESYSTEM_BASE_URL, systemBaseName), systemVersion);
|
||||
if (systemBaseName.equals(_11073_CODESYSTEM_URN))
|
||||
return getVersionedSystem("11073", systemVersion);
|
||||
if (systemBaseName.startsWith(ISO_CODESYSTEM_URN))
|
||||
return getVersionedSystem("iso"+systemBaseName.substring(ISO_CODESYSTEM_URN.length()).replace(":", ""), systemVersion);
|
||||
if (systemBaseName.startsWith(HL7_TERMINOLOGY_CODESYSTEM_BASE_URL))
|
||||
return getVersionedSystem(normalizeBaseURL(HL7_TERMINOLOGY_CODESYSTEM_BASE_URL, systemBaseName), systemVersion);
|
||||
if (systemBaseName.startsWith(HL7_FHIR_CODESYSTEM_BASE_URL))
|
||||
return getVersionedSystem(normalizeBaseURL(HL7_FHIR_CODESYSTEM_BASE_URL, systemBaseName), systemVersion);
|
||||
if (systemBaseName.equals(LANG_CODESYSTEM_URN))
|
||||
return getVersionedSystem("lang", systemVersion);
|
||||
if (systemBaseName.equals(MIMETYPES_CODESYSTEM_URN))
|
||||
return getVersionedSystem("mimetypes", systemVersion);
|
||||
if (systemBaseName.equals(DICOM_CODESYSTEM_URL))
|
||||
return getVersionedSystem("dicom", systemVersion);
|
||||
return getVersionedSystem(systemBaseName.replace("/", "_").replace(":", "_").replace("?", "X").replace("#", "X"), systemVersion);
|
||||
}
|
||||
|
||||
public String normalizeBaseURL(String baseUrl, String fullUrl) {
|
||||
return fullUrl.substring(baseUrl.length()).replace("/", "");
|
||||
}
|
||||
|
||||
public String getVersionedSystem(String baseSystem, String version) {
|
||||
if (version != null) {
|
||||
return baseSystem + "_" + version;
|
||||
}
|
||||
return baseSystem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class CacheEntry {
|
||||
private String request;
|
||||
private boolean persistent;
|
||||
|
@ -185,7 +253,7 @@ public class TerminologyCache {
|
|||
public CacheToken generateValidationToken(ValidationOptions options, Coding code, ValueSet vs) {
|
||||
CacheToken ct = new CacheToken();
|
||||
if (code.hasSystem()) {
|
||||
ct.name = getNameForSystem(code.getSystem());
|
||||
ct.setName(code.getSystem());
|
||||
ct.hasVersion = code.hasVersion();
|
||||
}
|
||||
else
|
||||
|
@ -226,7 +294,7 @@ public class TerminologyCache {
|
|||
CacheToken ct = new CacheToken();
|
||||
for (Coding c : code.getCoding()) {
|
||||
if (c.hasSystem()) {
|
||||
ct.setName(getNameForSystem(c.getSystem()));
|
||||
ct.setName(c.getSystem());
|
||||
ct.hasVersion = c.hasVersion();
|
||||
}
|
||||
}
|
||||
|
@ -287,53 +355,31 @@ public class TerminologyCache {
|
|||
if (vs != null) {
|
||||
for (ConceptSetComponent inc : vs.getCompose().getInclude()) {
|
||||
if (inc.hasSystem()) {
|
||||
ct.setName(getNameForSystem(inc.getSystem()));
|
||||
ct.setName(inc.getSystem());
|
||||
ct.hasVersion = inc.hasVersion();
|
||||
}
|
||||
}
|
||||
for (ConceptSetComponent inc : vs.getCompose().getExclude()) {
|
||||
if (inc.hasSystem()) {
|
||||
ct.setName(getNameForSystem(inc.getSystem()));
|
||||
ct.setName(inc.getSystem());
|
||||
ct.hasVersion = inc.hasVersion();
|
||||
}
|
||||
}
|
||||
for (ValueSetExpansionContainsComponent inc : vs.getExpansion().getContains()) {
|
||||
if (inc.hasSystem()) {
|
||||
ct.setName(getNameForSystem(inc.getSystem()));
|
||||
ct.setName(inc.getSystem());
|
||||
ct.hasVersion = inc.hasVersion();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getNameForSystem(String system) {
|
||||
if (system.equals("http://snomed.info/sct"))
|
||||
return "snomed";
|
||||
if (system.equals("http://www.nlm.nih.gov/research/umls/rxnorm"))
|
||||
return "rxnorm";
|
||||
if (system.equals("http://loinc.org"))
|
||||
return "loinc";
|
||||
if (system.equals("http://unitsofmeasure.org"))
|
||||
return "ucum";
|
||||
if (system.startsWith("http://hl7.org/fhir/sid/"))
|
||||
return system.substring(24).replace("/", "");
|
||||
if (system.startsWith("urn:iso:std:iso:"))
|
||||
return "iso"+system.substring(16).replace(":", "");
|
||||
if (system.startsWith("http://terminology.hl7.org/CodeSystem/"))
|
||||
return system.substring(38).replace("/", "");
|
||||
if (system.startsWith("http://hl7.org/fhir/"))
|
||||
return system.substring(20).replace("/", "");
|
||||
if (system.equals("urn:ietf:bcp:47"))
|
||||
return "lang";
|
||||
if (system.equals("urn:ietf:bcp:13"))
|
||||
return "mimetypes";
|
||||
if (system.equals("urn:iso:std:iso:11073:10101"))
|
||||
return "11073";
|
||||
if (system.equals("http://dicom.nema.org/resources/ontology/DCM"))
|
||||
return "dicom";
|
||||
return system.replace("/", "_").replace(":", "_").replace("?", "X").replace("#", "X");
|
||||
private String normalizeSystemPath(String path) {
|
||||
return path.replace("/", "").replace('|','X');
|
||||
}
|
||||
|
||||
|
||||
|
||||
public NamedCache getNamedCache(CacheToken cacheToken) {
|
||||
|
||||
final String cacheName = cacheToken.name == null ? "null" : cacheToken.name;
|
||||
|
@ -687,7 +733,7 @@ public class TerminologyCache {
|
|||
|
||||
public void removeCS(String url) {
|
||||
synchronized (lock) {
|
||||
String name = getNameForSystem(url);
|
||||
String name = getSystemNameKeyGenerator().getNameForSystem(url);
|
||||
if (caches.containsKey(name)) {
|
||||
caches.remove(name);
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ import org.hl7.fhir.utilities.validation.ValidationMessage;
|
|||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.CsvSource;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
|
@ -238,6 +239,8 @@ public class TerminologyCacheTests implements ResourceLoaderTests {
|
|||
assertTrue(cacheToken.hasVersion());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testCodableConceptCacheTokenGeneration() throws IOException, URISyntaxException {
|
||||
|
||||
|
@ -453,4 +456,41 @@ public class TerminologyCacheTests implements ResourceLoaderTests {
|
|||
|
||||
assertEquals("http://dummy.org", extracted);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource({
|
||||
"http://terminology.hl7.org/CodeSystem/id,id",
|
||||
"http://hl7.org/fhir/id,id",
|
||||
"http://hl7.org/fhir/sid/id,id",
|
||||
"http://www.nlm.nih.gov/research/umls/rxnorm,rxnorm",
|
||||
"http://snomed.info/sct,snomed",
|
||||
"http://www.nlm.nih.gov/research/umls/rxnorm,rxnorm",
|
||||
"http://loinc.org,loinc",
|
||||
"http://unitsofmeasure.org,ucum",
|
||||
"urn:iso:std:iso:id,isoid",
|
||||
"urn:ietf:bcp:47,lang",
|
||||
"urn:ietf:bcp:13,mimetypes",
|
||||
"urn:iso:std:iso:11073:10101,11073",
|
||||
"my://random/system?with#chars,my___random_systemXwithXchars",
|
||||
"http://dicom.nema.org/resources/ontology/DCM,dicom"
|
||||
})
|
||||
public void testCacheTokenGeneration(String system, String expectedName) throws IOException, URISyntaxException {
|
||||
|
||||
TerminologyCache terminologyCache = createTerminologyCache();
|
||||
ValueSet valueSet = new ValueSet();
|
||||
{
|
||||
Coding coding = new Coding();
|
||||
coding.setSystem(system);
|
||||
TerminologyCache.CacheToken cacheToken = terminologyCache.generateValidationToken(CacheTestUtils.validationOptions,
|
||||
coding, valueSet);
|
||||
assertEquals(expectedName, cacheToken.getName());
|
||||
}
|
||||
{
|
||||
Coding coding = new Coding();
|
||||
coding.setSystem(system + "|dummyVersion");
|
||||
TerminologyCache.CacheToken cacheToken = terminologyCache.generateValidationToken(CacheTestUtils.validationOptions,
|
||||
coding, valueSet);
|
||||
assertEquals(expectedName + "_dummyVersion", cacheToken.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
-------------------------------------------------------------------------------------
|
||||
{"code" : {
|
||||
"system" : "http://terminology.hl7.org/CodeSystem/v2-0360|2.7",
|
||||
"code" : "BS",
|
||||
"display" : "Bachelor of Science"
|
||||
}, "valueSet" :null, "lang":"null", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"ALL_CHECKS", "versionFlexible":"true"}####
|
||||
v: {
|
||||
"display" : "Bachelor of Science",
|
||||
"code" : "BS",
|
||||
"system" : "http://terminology.hl7.org/CodeSystem/v2-0360|2.7"
|
||||
}
|
||||
-------------------------------------------------------------------------------------
|
Loading…
Reference in New Issue