View Javadoc
1   package ca.uhn.fhir.jpa.term.loinc;
2   
3   /*-
4    * #%L
5    * HAPI FHIR JPA Server
6    * %%
7    * Copyright (C) 2014 - 2018 University Health Network
8    * %%
9    * Licensed under the Apache License, Version 2.0 (the "License");
10   * you may not use this file except in compliance with the License.
11   * You may obtain a copy of the License at
12   * 
13   *      http://www.apache.org/licenses/LICENSE-2.0
14   * 
15   * Unless required by applicable law or agreed to in writing, software
16   * distributed under the License is distributed on an "AS IS" BASIS,
17   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18   * See the License for the specific language governing permissions and
19   * limitations under the License.
20   * #L%
21   */
22  
23  import ca.uhn.fhir.jpa.entity.TermConcept;
24  import ca.uhn.fhir.jpa.term.IRecordHandler;
25  import org.hl7.fhir.r4.model.ConceptMap;
26  import org.hl7.fhir.r4.model.ContactPoint;
27  import org.hl7.fhir.r4.model.Enumerations;
28  import org.hl7.fhir.r4.model.ValueSet;
29  
30  import java.util.HashMap;
31  import java.util.List;
32  import java.util.Map;
33  import java.util.Properties;
34  
35  import static org.apache.commons.lang3.StringUtils.*;
36  
37  public abstract class BaseLoincHandler implements IRecordHandler {
38  
39  	public static final String LOINC_COPYRIGHT_STATEMENT = "This content from LOINC® is copyright © 1995 Regenstrief Institute, Inc. and the LOINC Committee, and available at no cost under the license at https://loinc.org/license/";
40  	/**
41  	 * This is <b>NOT</b> the LOINC CodeSystem URI! It is just
42  	 * the website URL to LOINC.
43  	 */
44  	public static final String LOINC_WEBSITE_URL = "https://loinc.org";
45  	public static final String REGENSTRIEF_INSTITUTE_INC = "Regenstrief Institute, Inc.";
46  	private final List<ConceptMap> myConceptMaps;
47  	private final Map<String, ConceptMap> myIdToConceptMaps = new HashMap<>();
48  	private final List<ValueSet> myValueSets;
49  	private final Map<String, ValueSet> myIdToValueSet = new HashMap<>();
50  	private final Map<String, TermConcept> myCode2Concept;
51  	private final Properties myUploadProperties;
52  
53  	BaseLoincHandler(Map<String, TermConcept> theCode2Concept, List<ValueSet> theValueSets, List<ConceptMap> theConceptMaps, Properties theUploadProperties) {
54  		myValueSets = theValueSets;
55  		myCode2Concept = theCode2Concept;
56  		myConceptMaps = theConceptMaps;
57  		myUploadProperties = theUploadProperties;
58  	}
59  
60  	void addCodeAsIncludeToValueSet(ValueSet theVs, String theCodeSystemUrl, String theCode, String theDisplayName) {
61  		ValueSet.ConceptSetComponent include = null;
62  		for (ValueSet.ConceptSetComponent next : theVs.getCompose().getInclude()) {
63  			if (next.getSystem().equals(theCodeSystemUrl)) {
64  				include = next;
65  				break;
66  			}
67  		}
68  		if (include == null) {
69  			include = theVs.getCompose().addInclude();
70  			include.setSystem(theCodeSystemUrl);
71  		}
72  
73  		boolean found = false;
74  		for (ValueSet.ConceptReferenceComponent next : include.getConcept()) {
75  			if (next.getCode().equals(theCode)) {
76  				found = true;
77  			}
78  		}
79  		if (!found) {
80  
81  			String displayName = theDisplayName;
82  			if (isBlank(displayName)) {
83  				for (TermConcept next : myCode2Concept.values()) {
84  					if (next.getCode().equals(theCode)) {
85  						displayName = next.getDisplay();
86  					}
87  				}
88  			}
89  
90  			include
91  				.addConcept()
92  				.setCode(theCode)
93  				.setDisplay(displayName);
94  
95  		}
96  	}
97  
98  
99  	void addConceptMapEntry(ConceptMapping theMapping, String theCopyright) {
100 		if (isBlank(theMapping.getSourceCode())) {
101 			return;
102 		}
103 		if (isBlank(theMapping.getTargetCode())) {
104 			return;
105 		}
106 
107 		ConceptMap conceptMap;
108 		if (!myIdToConceptMaps.containsKey(theMapping.getConceptMapId())) {
109 			conceptMap = new ConceptMap();
110 			conceptMap.setId(theMapping.getConceptMapId());
111 			conceptMap.setUrl(theMapping.getConceptMapUri());
112 			conceptMap.setName(theMapping.getConceptMapName());
113 			conceptMap.setVersion(myUploadProperties.getProperty("conceptmap.version"));
114 			conceptMap.setPublisher(REGENSTRIEF_INSTITUTE_INC);
115 			conceptMap.addContact()
116 				.setName(REGENSTRIEF_INSTITUTE_INC)
117 				.addTelecom()
118 				.setSystem(ContactPoint.ContactPointSystem.URL)
119 				.setValue(LOINC_WEBSITE_URL);
120 			String copyright = theCopyright;
121 			if (!copyright.contains("LOINC")) {
122 				copyright = LOINC_COPYRIGHT_STATEMENT + ". " + copyright;
123 			}
124 			conceptMap.setCopyright(copyright);
125 			myIdToConceptMaps.put(theMapping.getConceptMapId(), conceptMap);
126 			myConceptMaps.add(conceptMap);
127 		} else {
128 			conceptMap = myIdToConceptMaps.get(theMapping.getConceptMapId());
129 		}
130 
131 		if (isBlank(theMapping.getCopyright())) {
132 			conceptMap.setCopyright(theMapping.getCopyright());
133 		}
134 
135 		ConceptMap.SourceElementComponent source = null;
136 		ConceptMap.ConceptMapGroupComponent group = null;
137 
138 		for (ConceptMap.ConceptMapGroupComponent next : conceptMap.getGroup()) {
139 			if (next.getSource().equals(theMapping.getSourceCodeSystem())) {
140 				if (next.getTarget().equals(theMapping.getTargetCodeSystem())) {
141 					if (!defaultString(theMapping.getTargetCodeSystemVersion()).equals(defaultString(next.getTargetVersion()))) {
142 						continue;
143 					}
144 					group = next;
145 					break;
146 				}
147 			}
148 		}
149 		if (group == null) {
150 			group = conceptMap.addGroup();
151 			group.setSource(theMapping.getSourceCodeSystem());
152 			group.setTarget(theMapping.getTargetCodeSystem());
153 			group.setTargetVersion(defaultIfBlank(theMapping.getTargetCodeSystemVersion(), null));
154 		}
155 
156 		for (ConceptMap.SourceElementComponent next : group.getElement()) {
157 			if (next.getCode().equals(theMapping.getSourceCode())) {
158 				source = next;
159 			}
160 		}
161 		if (source == null) {
162 			source = group.addElement();
163 			source.setCode(theMapping.getSourceCode());
164 			source.setDisplay(theMapping.getSourceDisplay());
165 		}
166 
167 		boolean found = false;
168 		for (ConceptMap.TargetElementComponent next : source.getTarget()) {
169 			if (next.getCode().equals(theMapping.getTargetCode())) {
170 				found = true;
171 			}
172 		}
173 		if (!found) {
174 			source
175 				.addTarget()
176 				.setCode(theMapping.getTargetCode())
177 				.setDisplay(theMapping.getTargetDisplay())
178 				.setEquivalence(theMapping.getEquivalence());
179 		}
180 	}
181 
182 	ValueSet getValueSet(String theValueSetId, String theValueSetUri, String theValueSetName, String theVersionPropertyName) {
183 
184 		String version = null;
185 		if (isNotBlank(theVersionPropertyName)) {
186 			version = myUploadProperties.getProperty(theVersionPropertyName);
187 		}
188 
189 		ValueSet vs;
190 		if (!myIdToValueSet.containsKey(theValueSetId)) {
191 			vs = new ValueSet();
192 			vs.setUrl(theValueSetUri);
193 			vs.setId(theValueSetId);
194 			vs.setVersion(version);
195 			vs.setName(theValueSetName);
196 			vs.setStatus(Enumerations.PublicationStatus.ACTIVE);
197 			vs.setPublisher(REGENSTRIEF_INSTITUTE_INC);
198 			vs.addContact()
199 				.setName(REGENSTRIEF_INSTITUTE_INC)
200 				.addTelecom()
201 				.setSystem(ContactPoint.ContactPointSystem.URL)
202 				.setValue(LOINC_WEBSITE_URL);
203 			vs.setCopyright(LOINC_COPYRIGHT_STATEMENT);
204 			myIdToValueSet.put(theValueSetId, vs);
205 			myValueSets.add(vs);
206 		} else {
207 			vs = myIdToValueSet.get(theValueSetId);
208 		}
209 		return vs;
210 	}
211 
212 
213 	static class ConceptMapping {
214 
215 		private String myCopyright;
216 		private String myConceptMapId;
217 		private String myConceptMapUri;
218 		private String myConceptMapName;
219 		private String mySourceCodeSystem;
220 		private String mySourceCode;
221 		private String mySourceDisplay;
222 		private String myTargetCodeSystem;
223 		private String myTargetCode;
224 		private String myTargetDisplay;
225 		private Enumerations.ConceptMapEquivalence myEquivalence;
226 		private String myTargetCodeSystemVersion;
227 
228 		String getConceptMapId() {
229 			return myConceptMapId;
230 		}
231 
232 		ConceptMapping setConceptMapId(String theConceptMapId) {
233 			myConceptMapId = theConceptMapId;
234 			return this;
235 		}
236 
237 		String getConceptMapName() {
238 			return myConceptMapName;
239 		}
240 
241 		ConceptMapping setConceptMapName(String theConceptMapName) {
242 			myConceptMapName = theConceptMapName;
243 			return this;
244 		}
245 
246 		String getConceptMapUri() {
247 			return myConceptMapUri;
248 		}
249 
250 		ConceptMapping setConceptMapUri(String theConceptMapUri) {
251 			myConceptMapUri = theConceptMapUri;
252 			return this;
253 		}
254 
255 		String getCopyright() {
256 			return myCopyright;
257 		}
258 
259 		ConceptMapping setCopyright(String theCopyright) {
260 			myCopyright = theCopyright;
261 			return this;
262 		}
263 
264 		Enumerations.ConceptMapEquivalence getEquivalence() {
265 			return myEquivalence;
266 		}
267 
268 		ConceptMapping setEquivalence(Enumerations.ConceptMapEquivalence theEquivalence) {
269 			myEquivalence = theEquivalence;
270 			return this;
271 		}
272 
273 		String getSourceCode() {
274 			return mySourceCode;
275 		}
276 
277 		ConceptMapping setSourceCode(String theSourceCode) {
278 			mySourceCode = theSourceCode;
279 			return this;
280 		}
281 
282 		String getSourceCodeSystem() {
283 			return mySourceCodeSystem;
284 		}
285 
286 		ConceptMapping setSourceCodeSystem(String theSourceCodeSystem) {
287 			mySourceCodeSystem = theSourceCodeSystem;
288 			return this;
289 		}
290 
291 		String getSourceDisplay() {
292 			return mySourceDisplay;
293 		}
294 
295 		ConceptMapping setSourceDisplay(String theSourceDisplay) {
296 			mySourceDisplay = theSourceDisplay;
297 			return this;
298 		}
299 
300 		String getTargetCode() {
301 			return myTargetCode;
302 		}
303 
304 		ConceptMapping setTargetCode(String theTargetCode) {
305 			myTargetCode = theTargetCode;
306 			return this;
307 		}
308 
309 		String getTargetCodeSystem() {
310 			return myTargetCodeSystem;
311 		}
312 
313 		ConceptMapping setTargetCodeSystem(String theTargetCodeSystem) {
314 			myTargetCodeSystem = theTargetCodeSystem;
315 			return this;
316 		}
317 
318 		String getTargetCodeSystemVersion() {
319 			return myTargetCodeSystemVersion;
320 		}
321 
322 		ConceptMapping setTargetCodeSystemVersion(String theTargetCodeSystemVersion) {
323 			myTargetCodeSystemVersion = theTargetCodeSystemVersion;
324 			return this;
325 		}
326 
327 		String getTargetDisplay() {
328 			return myTargetDisplay;
329 		}
330 
331 		ConceptMapping setTargetDisplay(String theTargetDisplay) {
332 			myTargetDisplay = theTargetDisplay;
333 			return this;
334 		}
335 
336 	}
337 }