001package org.hl7.fhir.r4.context;
002
003/*-
004 * #%L
005 * org.hl7.fhir.r4
006 * %%
007 * Copyright (C) 2014 - 2019 Health Level 7
008 * %%
009 * Licensed under the Apache License, Version 2.0 (the "License");
010 * you may not use this file except in compliance with the License.
011 * You may obtain a copy of the License at
012 * 
013 *      http://www.apache.org/licenses/LICENSE-2.0
014 * 
015 * Unless required by applicable law or agreed to in writing, software
016 * distributed under the License is distributed on an "AS IS" BASIS,
017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018 * See the License for the specific language governing permissions and
019 * limitations under the License.
020 * #L%
021 */
022
023
024import java.util.List;
025import java.util.Map;
026import java.util.Set;
027
028import org.fhir.ucum.UcumService;
029import org.hl7.fhir.exceptions.DefinitionException;
030import org.hl7.fhir.exceptions.FHIRException;
031import org.hl7.fhir.exceptions.TerminologyServiceException;
032import org.hl7.fhir.r4.formats.IParser;
033import org.hl7.fhir.r4.formats.ParserType;
034import org.hl7.fhir.r4.model.CodeSystem;
035import org.hl7.fhir.r4.model.CodeSystem.ConceptDefinitionComponent;
036import org.hl7.fhir.r4.model.CodeableConcept;
037import org.hl7.fhir.r4.model.Coding;
038import org.hl7.fhir.r4.model.ConceptMap;
039import org.hl7.fhir.r4.model.ElementDefinition.ElementDefinitionBindingComponent;
040import org.hl7.fhir.r4.model.MetadataResource;
041import org.hl7.fhir.r4.model.Parameters;
042import org.hl7.fhir.r4.model.Resource;
043import org.hl7.fhir.r4.model.StructureDefinition;
044import org.hl7.fhir.r4.model.StructureMap;
045import org.hl7.fhir.r4.model.ValueSet;
046import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent;
047import org.hl7.fhir.r4.terminologies.ValueSetExpander.TerminologyServiceErrorClass;
048import org.hl7.fhir.r4.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
049import org.hl7.fhir.r4.utils.INarrativeGenerator;
050import org.hl7.fhir.r4.utils.IResourceValidator;
051import org.hl7.fhir.utilities.TerminologyServiceOptions;
052import org.hl7.fhir.utilities.TranslationServices;
053import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
054
055
056/**
057 * This is the standard interface used for access to underlying FHIR
058 * services through the tools and utilities provided by the reference
059 * implementation. 
060 * 
061 * The functionality it provides is 
062 *  - get access to parsers, validators, narrative builders etc
063 *    (you can't create these directly because they need access 
064 *    to the right context for their information)
065 *    
066 *  - find resources that the tools need to carry out their tasks
067 *  
068 *  - provide access to terminology services they need. 
069 *    (typically, these terminology service requests are just
070 *    passed through to the local implementation's terminology
071 *    service)    
072 *  
073 * @author Grahame
074 */
075public interface IWorkerContext {
076
077  /**
078   * Get the versions of the definitions loaded in context
079   * @return
080   */
081  public String getVersion();
082  
083  // get the UCUM service (might not be available)
084  public UcumService getUcumService();
085  
086  // -- Parsers (read and write instances) ----------------------------------------
087
088
089  /**
090   * Get a parser to read/write instances. Use the defined type (will be extended 
091   * as further types are added, though the only currently anticipate type is RDF)
092   * 
093   * XML/JSON - the standard renderers
094   * XHTML - render the narrative only (generate it if necessary)
095   * 
096   * @param type
097   * @return
098   */
099  public IParser getParser(ParserType type);
100
101  /**
102   * Get a parser to read/write instances. Determine the type 
103   * from the stated type. Supported value for type:
104   * - the recommended MIME types
105   * - variants of application/xml and application/json
106   * - _format values xml, json
107   * 
108   * @param type
109   * @return
110   */   
111  public IParser getParser(String type);
112
113  /**
114   * Get a JSON parser
115   * 
116   * @return
117   */
118  public IParser newJsonParser();
119
120  /**
121   * Get an XML parser
122   * 
123   * @return
124   */
125  public IParser newXmlParser();
126
127  /**
128   * Get a generator that can generate narrative for the instance
129   * 
130   * @return a prepared generator
131   */
132  public INarrativeGenerator getNarrativeGenerator(String prefix, String basePath);
133
134  /**
135   * Get a validator that can check whether a resource is valid 
136   * 
137   * @return a prepared generator
138   * @throws FHIRException 
139   * @
140   */
141  public IResourceValidator newValidator() throws FHIRException;
142
143  // -- resource fetchers ---------------------------------------------------
144
145  /**
146   * Find an identified resource. The most common use of this is to access the the 
147   * standard conformance resources that are part of the standard - structure 
148   * definitions, value sets, concept maps, etc.
149   * 
150   * Also, the narrative generator uses this, and may access any kind of resource
151   * 
152   * The URI is called speculatively for things that might exist, so not finding 
153   * a matching resouce, return null, not an error
154   * 
155   * The URI can have one of 3 formats:
156   *  - a full URL e.g. http://acme.org/fhir/ValueSet/[id]
157   *  - a relative URL e.g. ValueSet/[id]
158   *  - a logical id e.g. [id]
159   *  
160   * It's an error if the second form doesn't agree with class_. It's an 
161   * error if class_ is null for the last form
162   * 
163   * @param resource
164   * @param Reference
165   * @return
166   * @throws FHIRException 
167   * @throws Exception
168   */
169  public <T extends Resource> T fetchResource(Class<T> class_, String uri);
170  public <T extends Resource> T fetchResourceWithException(Class<T> class_, String uri) throws FHIRException;
171
172  /**
173   * Variation of fetchResource when you have a string type, and don't need the right class
174   * 
175   * The URI can have one of 3 formats:
176   *  - a full URL e.g. http://acme.org/fhir/ValueSet/[id]
177   *  - a relative URL e.g. ValueSet/[id]
178   *  - a logical id e.g. [id]
179   *  
180   * if type == null, the URI can't be a simple logical id
181   * 
182   * @param type
183   * @param uri
184   * @return
185   */
186  public Resource fetchResourceById(String type, String uri);
187  
188  /**
189   * find whether a resource is available. 
190   * 
191   * Implementations of the interface can assume that if hasResource ruturns 
192   * true, the resource will usually be fetched subsequently
193   * 
194   * @param class_
195   * @param uri
196   * @return
197   */
198  public <T extends Resource> boolean hasResource(Class<T> class_, String uri);
199
200  /**
201   * cache a resource for later retrieval using fetchResource.
202   * 
203   * Note that various context implementations will have their own ways of loading
204   * rseources, and not all need implement cacheResource 
205   * @param res
206   * @throws FHIRException 
207   */
208  public void cacheResource(Resource res) throws FHIRException;
209  
210  // -- profile services ---------------------------------------------------------
211  
212  public List<String> getResourceNames();
213  public Set<String> getResourceNamesAsSet();
214  public List<String> getTypeNames();
215  public List<StructureDefinition> allStructures(); // ensure snapshot exists...
216  public List<StructureDefinition> getStructures();
217  public List<MetadataResource> allConformanceResources();
218  public void generateSnapshot(StructureDefinition p) throws DefinitionException, FHIRException;
219  
220  // -- Terminology services ------------------------------------------------------
221
222  public Parameters getExpansionParameters();
223  public void setExpansionProfile(Parameters expParameters);
224
225  // these are the terminology services used internally by the tools
226  /**
227   * Find the code system definition for the nominated system uri. 
228   * return null if there isn't one (then the tool might try 
229   * supportsSystem)
230   * 
231   * @param system
232   * @return
233   */
234  public CodeSystem fetchCodeSystem(String system);
235
236  /**
237   * True if the underlying terminology service provider will do 
238   * expansion and code validation for the terminology. Corresponds
239   * to the extension 
240   * 
241   * http://hl7.org/fhir/StructureDefinition/capabilitystatement-supported-system
242   * 
243   * in the Conformance resource
244   * 
245   * @param system
246   * @return
247   * @throws Exception 
248   */
249  public boolean supportsSystem(String system) throws TerminologyServiceException;
250
251  /**
252   * find concept maps for a source
253   * @param url
254   * @return
255   * @throws FHIRException 
256   */
257  public List<ConceptMap> findMapsForSource(String url) throws FHIRException;  
258
259  /**
260   * ValueSet Expansion - see $expand
261   *  
262   * @param source
263   * @return
264   */
265  public ValueSetExpansionOutcome expandVS(ValueSet source, boolean cacheOk, boolean heiarchical);
266  
267  /**
268   * ValueSet Expansion - see $expand, but resolves the binding first
269   *  
270   * @param source
271   * @return
272   * @throws FHIRException 
273   */
274  public ValueSetExpansionOutcome expandVS(ElementDefinitionBindingComponent binding, boolean cacheOk, boolean heiarchical) throws FHIRException;
275  /**
276   * Value set expanion inside the internal expansion engine - used 
277   * for references to supported system (see "supportsSystem") for
278   * which there is no value set. 
279   * 
280   * @param inc
281   * @return
282   * @throws FHIRException 
283   */
284  public ValueSetExpansionOutcome expandVS(ConceptSetComponent inc, boolean heirarchical) throws TerminologyServiceException;
285  
286  public class ValidationResult {
287    private ConceptDefinitionComponent definition;
288    private IssueSeverity severity;
289    private String message;
290    private TerminologyServiceErrorClass errorClass;
291    private String txLink;
292    
293    public ValidationResult(IssueSeverity severity, String message) {
294      this.severity = severity;
295      this.message = message;
296    }
297    
298    public ValidationResult(ConceptDefinitionComponent definition) {
299      this.definition = definition;
300    }
301
302    public ValidationResult(IssueSeverity severity, String message, ConceptDefinitionComponent definition) {
303      this.severity = severity;
304      this.message = message;
305      this.definition = definition;
306    }
307    
308    public ValidationResult(IssueSeverity severity, String message, TerminologyServiceErrorClass errorClass) {
309      this.severity = severity;
310      this.message = message;
311      this.errorClass = errorClass;
312    }
313
314    public boolean isOk() {
315      return severity == null || severity == IssueSeverity.INFORMATION || severity == IssueSeverity.WARNING;
316    }
317
318    public String getDisplay() {
319// We don't want to return question-marks because that prevents something more useful from being displayed (e.g. the code) if there's no display value
320//      return definition == null ? "??" : definition.getDisplay();
321      return definition == null ? null : definition.getDisplay();
322    }
323
324    public ConceptDefinitionComponent asConceptDefinition() {
325      return definition;
326    }
327
328    public IssueSeverity getSeverity() {
329      return severity;
330    }
331
332    public String getMessage() {
333      return message;
334    }
335
336    public boolean IsNoService() {
337      return errorClass == TerminologyServiceErrorClass.NOSERVICE;
338    }
339
340    public TerminologyServiceErrorClass getErrorClass() {
341      return errorClass;
342    }
343
344    public ValidationResult setSeverity(IssueSeverity severity) {
345      this.severity = severity;
346      return this;
347    }
348
349    public ValidationResult setMessage(String message) {
350      this.message = message;
351      return this;
352    }
353
354    public String getTxLink() {
355      return txLink;
356    }
357
358    public ValidationResult setTxLink(String txLink) {
359      this.txLink = txLink;
360      return this;
361    }
362    
363    
364  }
365
366  /**
367   * Validation of a code - consult the terminology service 
368   * to see whether it is known. If known, return a description of it
369   * 
370   *  note: always return a result, with either an error or a code description
371   *  
372   * corresponds to 2 terminology service calls: $validate-code and $lookup
373   * 
374   * @param system
375   * @param code
376   * @param display
377   * @return
378   */
379  public ValidationResult validateCode(TerminologyServiceOptions options, String system, String code, String display);
380
381  /**
382   * Validation of a code - consult the terminology service 
383   * to see whether it is known. If known, return a description of it
384   * Also, check whether it's in the provided value set
385   * 
386   * note: always return a result, with either an error or a code description, or both (e.g. known code, but not in the value set)
387   *  
388   * corresponds to 2 terminology service calls: $validate-code and $lookup
389   * 
390   * @param system
391   * @param code
392   * @param display
393   * @return
394   */
395  public ValidationResult validateCode(TerminologyServiceOptions options, String system, String code, String display, ValueSet vs);
396  public ValidationResult validateCode(TerminologyServiceOptions options, String code, ValueSet vs);
397  public ValidationResult validateCode(TerminologyServiceOptions options, Coding code, ValueSet vs);
398  public ValidationResult validateCode(TerminologyServiceOptions options, CodeableConcept code, ValueSet vs);
399  
400  /**
401   * Validation of a code - consult the terminology service 
402   * to see whether it is known. If known, return a description of it
403   * Also, check whether it's in the provided value set fragment (for supported systems with no value set definition)
404   * 
405   * note: always return a result, with either an error or a code description, or both (e.g. known code, but not in the value set)
406   *  
407   * corresponds to 2 terminology service calls: $validate-code and $lookup
408   * 
409   * @param system
410   * @param code
411   * @param display
412   * @return
413   */
414  public ValidationResult validateCode(TerminologyServiceOptions options, String system, String code, String display, ConceptSetComponent vsi);
415
416  /**
417   * returns the recommended tla for the type 
418   * 
419   * @param name
420   * @return
421   */
422  public String getAbbreviation(String name);
423
424  // return a set of types that have tails
425  public Set<String> typeTails();
426
427        public String oid2Uri(String code);
428
429  public boolean hasCache();
430
431  public interface ILoggingService {
432    public enum LogCategory {
433      PROGRESS, TX, INIT, CONTEXT, HTML 
434    }
435    public void logMessage(String message); // status messages, always display
436    public void logDebugMessage(LogCategory category, String message); // verbose; only when debugging 
437  }
438
439  public void setLogger(ILoggingService logger);
440  public ILoggingService getLogger();
441
442  public boolean isNoTerminologyServer();
443
444  public TranslationServices translator();
445  public List<StructureMap> listTransforms();
446  public StructureMap getTransform(String url);
447
448  public String getOverrideVersionNs();
449  public void setOverrideVersionNs(String value);
450
451  public StructureDefinition fetchTypeDefinition(String typeName);
452
453  public void setUcumService(UcumService ucumService);
454
455  public String getLinkForUrl(String corePath, String s);
456}