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