001package org.hl7.fhir.dstu3.context;
002
003/*
004  Copyright (c) 2011+, HL7, Inc.
005  All rights reserved.
006  
007  Redistribution and use in source and binary forms, with or without modification, 
008  are permitted provided that the following conditions are met:
009    
010   * Redistributions of source code must retain the above copyright notice, this 
011     list of conditions and the following disclaimer.
012   * Redistributions in binary form must reproduce the above copyright notice, 
013     this list of conditions and the following disclaimer in the documentation 
014     and/or other materials provided with the distribution.
015   * Neither the name of HL7 nor the names of its contributors may be used to 
016     endorse or promote products derived from this software without specific 
017     prior written permission.
018  
019  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
020  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
021  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
022  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
023  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
024  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
025  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
026  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
027  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
028  POSSIBILITY OF SUCH DAMAGE.
029  
030 */
031
032
033
034import java.util.List;
035import java.util.Locale;
036import java.util.Set;
037
038import org.hl7.fhir.dstu3.formats.IParser;
039import org.hl7.fhir.dstu3.formats.ParserType;
040import org.hl7.fhir.dstu3.model.*;
041import org.hl7.fhir.dstu3.model.CodeSystem.ConceptDefinitionComponent;
042import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent;
043import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionComponent;
044import org.hl7.fhir.exceptions.FHIRException;
045import org.hl7.fhir.exceptions.TerminologyServiceException;
046import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
047
048
049/**
050 * This is the standard interface used for access to underlying FHIR
051 * services through the tools and utilities provided by the reference
052 * implementation. 
053 * 
054 * The functionality it provides is 
055 *  - get access to parsers, validators, narrative builders etc
056 *    (you can't create these directly because they need access 
057 *    to the right context for their information)
058 *    
059 *  - find resources that the tools need to carry out their tasks
060 *  
061 *  - provide access to terminology services they need. 
062 *    (typically, these terminology service requests are just
063 *    passed through to the local implementation's terminology
064 *    service)    
065 *  
066 * @author Grahame
067 */
068
069public interface IWorkerContext {
070
071  /**
072   * Get the versions of the definitions loaded in context
073   * @return
074   */
075  public String getVersion();
076  
077  // -- Parsers (read and write instances) ----------------------------------------
078
079
080  /**
081   * Get a parser to read/write instances. Use the defined type (will be extended 
082   * as further types are added, though the only currently anticipate type is RDF)
083   * 
084   * XML/JSON - the standard renderers
085   * XHTML - render the narrative only (generate it if necessary)
086   * 
087   * @param type
088   * @return
089   */
090  public IParser getParser(ParserType type);
091
092  /**
093   * Get a parser to read/write instances. Determine the type 
094   * from the stated type. Supported value for type:
095   * - the recommended MIME types
096   * - variants of application/xml and application/json
097   * - _format values xml, json
098   * 
099   * @param type
100   * @return
101   */   
102  public IParser getParser(String type);
103
104  /**
105   * Get a JSON parser
106   * 
107   * @return
108   */
109  public IParser newJsonParser();
110
111  /**
112   * Get an XML parser
113   * 
114   * @return
115   */
116  public IParser newXmlParser();
117
118  // -- resource fetchers ---------------------------------------------------
119
120  /**
121   * Find an identified resource. The most common use of this is to access the the 
122   * standard conformance resources that are part of the standard - structure 
123   * definitions, value sets, concept maps, etc.
124   * 
125   * Also, the narrative generator uses this, and may access any kind of resource
126   * 
127   * The URI is called speculatively for things that might exist, so not finding 
128   * a matching resouce, return null, not an error
129   * 
130   * The URI can have one of 3 formats:
131   *  - a full URL e.g. http://acme.org/fhir/ValueSet/[id]
132   *  - a relative URL e.g. ValueSet/[id]
133   *  - a logical id e.g. [id]
134   *  
135   * It's an error if the second form doesn't agree with class_. It's an 
136   * error if class_ is null for the last form
137   * 
138   * @param resource
139   * @param Reference
140   * @return
141   * @throws FHIRException 
142   * @throws Exception
143   */
144  public <T extends Resource> T fetchResource(Class<T> class_, String uri);
145  public <T extends Resource> T fetchResourceWithException(Class<T> class_, String uri) throws FHIRException;
146
147  /**
148   * find whether a resource is available. 
149   * 
150   * Implementations of the interface can assume that if hasResource ruturns 
151   * true, the resource will usually be fetched subsequently
152   * 
153   * @param class_
154   * @param uri
155   * @return
156   */
157  public <T extends Resource> boolean hasResource(Class<T> class_, String uri);
158
159  // -- profile services ---------------------------------------------------------
160  
161  public List<String> getResourceNames();
162  public Set<String> getResourceNamesAsSet();
163  public List<String> getTypeNames();
164  public List<StructureDefinition> allStructures();
165  public List<MetadataResource> allConformanceResources();
166  
167  // -- Terminology services ------------------------------------------------------
168
169  public ExpansionProfile getExpansionProfile();
170  public void setExpansionProfile(ExpansionProfile expProfile);
171
172  // these are the terminology services used internally by the tools
173  /**
174   * Find the code system definition for the nominated system uri. 
175   * return null if there isn't one (then the tool might try 
176   * supportsSystem)
177   * 
178   * @param system
179   * @return
180   */
181  public CodeSystem fetchCodeSystem(String system);
182
183  /**
184   * True if the underlying terminology service provider will do 
185   * expansion and code validation for the terminology. Corresponds
186   * to the extension 
187   * 
188   * http://hl7.org/fhir/StructureDefinition/capabilitystatement-supported-system
189   * 
190   * in the Conformance resource
191   * 
192   * @param system
193   * @return
194   * @throws Exception 
195   */
196  public boolean supportsSystem(String system) throws TerminologyServiceException;
197
198  /**
199   * find concept maps for a source
200   * @param url
201   * @return
202   */
203  public List<ConceptMap> findMapsForSource(String url);  
204
205  /**
206   * ValueSet Expansion - see $expand
207   *  
208   * @param source
209   * @return
210   */
211  public ValueSetExpansionOutcome expandVS(ValueSet source, boolean cacheOk, boolean heiarchical);
212  
213  /**
214   * Value set expanion inside the internal expansion engine - used 
215   * for references to supported system (see "supportsSystem") for
216   * which there is no value set. 
217   * 
218   * @param inc
219   * @return
220   * @throws FHIRException 
221   */
222  public ValueSetExpansionComponent expandVS(ConceptSetComponent inc, boolean heiarchical) throws TerminologyServiceException;
223
224  Locale getLocale();
225
226  void setLocale(Locale locale);
227
228  String formatMessage(String theMessage, Object... theMessageArguments);
229
230  void setValidationMessageLanguage(Locale locale);
231
232  public class ValidationResult {
233    private ConceptDefinitionComponent definition;
234    private IssueSeverity severity;
235    private String message;
236    private TerminologyServiceErrorClass errorClass;
237    
238    public ValidationResult(IssueSeverity severity, String message) {
239      this.severity = severity;
240      this.message = message;
241    }
242    
243    public ValidationResult(ConceptDefinitionComponent definition) {
244      this.definition = definition;
245    }
246
247    public ValidationResult(IssueSeverity severity, String message, ConceptDefinitionComponent definition) {
248      this.severity = severity;
249      this.message = message;
250      this.definition = definition;
251    }
252    
253    public ValidationResult(IssueSeverity severity, String message, TerminologyServiceErrorClass errorClass) {
254      this.severity = severity;
255      this.message = message;
256      this.errorClass = errorClass;
257    }
258
259    public boolean isOk() {
260      return definition != null;
261    }
262
263    public String getDisplay() {
264// 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
265//      return definition == null ? "??" : definition.getDisplay();
266      return definition == null ? null : definition.getDisplay();
267    }
268
269    public ConceptDefinitionComponent asConceptDefinition() {
270      return definition;
271    }
272
273    public IssueSeverity getSeverity() {
274      return severity;
275    }
276
277    public String getMessage() {
278      return message;
279    }
280
281    public boolean IsNoService() {
282      return errorClass == TerminologyServiceErrorClass.NOSERVICE;
283    }
284
285    public TerminologyServiceErrorClass getErrorClass() {
286      return errorClass;
287    }
288
289
290
291    public Parameters getOrMakeParameters() {
292      Parameters p = new Parameters();
293      p.addParameter().setName("result").setValue(new BooleanType(isOk()));
294      if (getMessage() != null) {
295        p.addParameter().setName("message").setValue(new StringType(getMessage()));
296      }
297      if (getDisplay() != null) {
298        p.addParameter().setName("display").setValue(new StringType(getDisplay()));
299      }
300      return p;
301    }
302  }
303
304  /**
305   * Validation of a code - consult the terminology service 
306   * to see whether it is known. If known, return a description of it
307   * 
308   *  note: always return a result, with either an error or a code description
309   *  
310   * corresponds to 2 terminology service calls: $validate-code and $lookup
311   * 
312   * @param system
313   * @param code
314   * @param display
315   * @return
316   */
317  public ValidationResult validateCode(String system, String code, String display);
318
319  /**
320   * Validation of a code - consult the terminology service 
321   * to see whether it is known. If known, return a description of it
322   * Also, check whether it's in the provided value set
323   * 
324   * 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)
325   *  
326   * corresponds to 2 terminology service calls: $validate-code and $lookup
327   * 
328   * @param system
329   * @param code
330   * @param display
331   * @return
332   */
333  public ValidationResult validateCode(String system, String code, String display, ValueSet vs);
334  public ValidationResult validateCode(Coding code, ValueSet vs);
335  public ValidationResult validateCode(CodeableConcept code, ValueSet vs);
336  
337  /**
338   * Validation of a code - consult the terminology service 
339   * to see whether it is known. If known, return a description of it
340   * Also, check whether it's in the provided value set fragment (for supported systems with no value set definition)
341   * 
342   * 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)
343   *  
344   * corresponds to 2 terminology service calls: $validate-code and $lookup
345   * 
346   * @param system
347   * @param code
348   * @param display
349   * @return
350   */
351  public ValidationResult validateCode(String system, String code, String display, ConceptSetComponent vsi);
352
353  /**
354   * returns the recommended tla for the type 
355   * 
356   * @param name
357   * @return
358   */
359  public String getAbbreviation(String name);
360
361  // return a set of types that have tails
362  public Set<String> typeTails();
363
364        public String oid2Uri(String code);
365
366  public boolean hasCache();
367
368  public interface ILoggingService {
369    public enum LogCategory {
370      PROGRESS, TX, INIT, CONTEXT, HTML 
371    }
372    public void logMessage(String message); // status messages, always display
373    public void logDebugMessage(LogCategory category, String message); // verbose; only when debugging 
374  }
375
376  public void setLogger(ILoggingService logger);
377
378  public boolean isNoTerminologyServer();
379  public StructureDefinition fetchTypeDefinition(String typeName);
380
381
382  /**
383   * Some value sets are just too big to expand. Instead of an expanded value set,
384   * you get back an interface that can test membership - usually on a server somewhere
385   *
386   * @author Grahame
387   */
388  public class ValueSetExpansionOutcome {
389    private ValueSet valueset;
390    private Object service; // actually a ValueSetChecker, but we shouldn't need this?
391    private String error;
392    private TerminologyServiceErrorClass errorClass;
393
394    public ValueSetExpansionOutcome(ValueSet valueset) {
395      super();
396      this.valueset = valueset;
397      this.service = null;
398      this.error = null;
399    }
400    public ValueSetExpansionOutcome(ValueSet valueset, String error, TerminologyServiceErrorClass errorClass) {
401      super();
402      this.valueset = valueset;
403      this.service = null;
404      this.error = error;
405      this.errorClass = errorClass;
406    }
407    public ValueSetExpansionOutcome(Object service, String error, TerminologyServiceErrorClass errorClass) {
408      super();
409      this.valueset = null;
410      this.service = service;
411      this.error = error;
412      this.errorClass = errorClass;
413    }
414    public ValueSetExpansionOutcome(String error, TerminologyServiceErrorClass errorClass) {
415      this.valueset = null;
416      this.service = null;
417      this.error = error;
418      this.errorClass = errorClass;
419    }
420    public ValueSet getValueset() {
421      return valueset;
422    }
423    public Object getService() {
424      return service;
425    }
426    public String getError() {
427      return error;
428    }
429    public TerminologyServiceErrorClass getErrorClass() {
430      return errorClass;
431    }
432
433    public boolean isOk() {
434      return error == null;
435    }
436  }
437
438  public enum TerminologyServiceErrorClass {
439    UNKNOWN, NOSERVICE, SERVER_ERROR, VALUESET_UNSUPPORTED;
440
441    public boolean isInfrastructure() {
442      return this == NOSERVICE || this == SERVER_ERROR || this == VALUESET_UNSUPPORTED;
443    }
444  }
445}