001package org.hl7.fhir.r5.context;
002
003import java.io.FileNotFoundException;
004import java.io.IOException;
005import java.io.InputStream;
006import java.util.ArrayList;
007import java.util.Collection;
008import java.util.Date;
009
010/*
011  Copyright (c) 2011+, HL7, Inc.
012  All rights reserved.
013
014  Redistribution and use in source and binary forms, with or without modification, 
015  are permitted provided that the following conditions are met:
016
017 * Redistributions of source code must retain the above copyright notice, this 
018     list of conditions and the following disclaimer.
019 * Redistributions in binary form must reproduce the above copyright notice, 
020     this list of conditions and the following disclaimer in the documentation 
021     and/or other materials provided with the distribution.
022 * Neither the name of HL7 nor the names of its contributors may be used to 
023     endorse or promote products derived from this software without specific 
024     prior written permission.
025
026  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
027  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
028  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
029  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
030  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
031  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
032  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
033  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
034  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
035  POSSIBILITY OF SUCH DAMAGE.
036
037 */
038
039
040
041import java.util.List;
042import java.util.Locale;
043import java.util.Map;
044import java.util.Set;
045
046import org.fhir.ucum.UcumService;
047import org.hl7.fhir.exceptions.DefinitionException;
048import org.hl7.fhir.exceptions.FHIRException;
049import org.hl7.fhir.exceptions.TerminologyServiceException;
050import org.hl7.fhir.r5.context.TerminologyCache.CacheToken;
051import org.hl7.fhir.r5.elementmodel.Element;
052import org.hl7.fhir.r5.formats.IParser;
053import org.hl7.fhir.r5.formats.ParserType;
054import org.hl7.fhir.r5.model.Bundle;
055import org.hl7.fhir.r5.model.CanonicalResource;
056import org.hl7.fhir.r5.model.CodeSystem;
057import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent;
058import org.hl7.fhir.r5.model.CodeableConcept;
059import org.hl7.fhir.r5.model.Coding;
060import org.hl7.fhir.r5.model.ConceptMap;
061import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingComponent;
062import org.hl7.fhir.r5.model.OperationOutcome.OperationOutcomeIssueComponent;
063import org.hl7.fhir.r5.model.NamingSystem;
064import org.hl7.fhir.r5.model.PackageInformation;
065import org.hl7.fhir.r5.model.Parameters;
066import org.hl7.fhir.r5.model.Resource;
067import org.hl7.fhir.r5.model.StructureDefinition;
068import org.hl7.fhir.r5.model.StructureMap;
069import org.hl7.fhir.r5.model.ValueSet;
070import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent;
071import org.hl7.fhir.r5.profilemodel.PEDefinition;
072import org.hl7.fhir.r5.profilemodel.PEBuilder.PEElementPropertiesPolicy;
073import org.hl7.fhir.r5.profilemodel.PEBuilder;
074import org.hl7.fhir.r5.terminologies.expansion.ValueSetExpansionOutcome;
075import org.hl7.fhir.r5.terminologies.utilities.TerminologyServiceErrorClass;
076import org.hl7.fhir.r5.utils.validation.IResourceValidator;
077import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier;
078import org.hl7.fhir.utilities.TimeTracker;
079import org.hl7.fhir.utilities.TranslationServices;
080import org.hl7.fhir.utilities.npm.BasePackageCacheManager;
081import org.hl7.fhir.utilities.npm.NpmPackage;
082import org.hl7.fhir.utilities.npm.NpmPackage.PackageResourceInformation;
083import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
084import org.hl7.fhir.utilities.validation.ValidationMessage;
085import org.hl7.fhir.utilities.validation.ValidationOptions;
086
087import com.google.gson.JsonSyntaxException;
088
089import javax.annotation.Nonnull;
090
091
092/**
093 * This is the standard interface used for access to underlying FHIR
094 * services through the tools and utilities provided by the reference
095 * implementation. 
096 * 
097 * The functionality it provides is 
098 *  - get access to canonical resources,terminology services, and validator
099 *    (you can't create a validator directly because it needs access 
100 *    to the right context for their information)
101 *    
102 *  - find resources that the tools need to carry out their tasks
103 *  
104 *  - provide access to terminology services they need. 
105 *    (typically, these terminology service requests are just
106 *    passed through to the local implementation's terminology
107 *    service)    
108 *  
109 * @author Grahame
110 */
111
112public interface IWorkerContext {
113
114  class ValidationResult {
115    private ConceptDefinitionComponent definition;
116    private String preferredDisplay;
117    private String system;
118    private String version;
119    private IssueSeverity severity;
120    private String message;
121    private TerminologyServiceErrorClass errorClass;
122    private String txLink;
123    private String diagnostics;
124    private List<OperationOutcomeIssueComponent> issues = new ArrayList<>();
125    private CodeableConcept codeableConcept;
126    private Set<String> unknownSystems;
127
128    @Override
129    public String toString() {
130      return "ValidationResult [definition=" + definition + ", system=" + system + ", severity=" + severity + ", message=" + message + ", errorClass="
131          + errorClass + ", txLink=" + txLink + "]";
132    }
133
134    public ValidationResult(IssueSeverity severity, String message, List<OperationOutcomeIssueComponent> issues) {
135      this.severity = severity;
136      this.message = message;
137      if (issues != null) {
138        this.issues.addAll(issues);
139      }
140    }
141
142    public ValidationResult(String system, String version, ConceptDefinitionComponent definition, String preferredDisplay) {
143      this.system = system;
144      this.version = version;
145      this.definition = definition;
146      this.preferredDisplay = preferredDisplay;
147    }
148
149    public ValidationResult(IssueSeverity severity, String message, String system, String version, ConceptDefinitionComponent definition, String preferredDisplay, List<OperationOutcomeIssueComponent>  issues) {
150      this.severity = severity;
151      this.message = message;
152      this.system = system;
153      this.version = version;
154      this.definition = definition;
155      this.preferredDisplay = preferredDisplay;
156      if (issues != null) {
157        this.issues.addAll(issues);
158      }
159    }
160
161    public ValidationResult(IssueSeverity severity, String message, TerminologyServiceErrorClass errorClass, List<OperationOutcomeIssueComponent>  issues) {
162      this.severity = severity;
163      this.message = message;
164      this.errorClass = errorClass;
165      if (issues != null) {
166        this.issues.addAll(issues);
167      }
168    }
169
170    public boolean isOk() {
171      return severity == null || severity == IssueSeverity.INFORMATION || severity == IssueSeverity.WARNING;
172    }
173
174    public String getSystem() {
175      return system;
176    }
177
178    public String getVersion() {
179      return version;
180    }
181
182    public String getDisplay() {
183      if (preferredDisplay != null) {
184        return preferredDisplay; 
185      } else {
186        return definition == null ? null : definition.getDisplay();
187      }
188    }
189
190    public void setDisplay(String display) {
191      this.preferredDisplay = display;
192    }
193
194    public void setSystem(String system) {
195      this.system = system;
196    }
197
198    public void setVersion(String version) {
199      this.version = version;
200    }
201
202    public String getCode() {
203      return definition == null ? null : definition.getCode();
204    }
205
206    public String getDefinition() {
207      return definition == null ? null : definition.getDefinition();
208    }
209
210    public void setDefinition(ConceptDefinitionComponent definition) {
211      this.definition = definition;
212    }
213
214    public ConceptDefinitionComponent asConceptDefinition() {
215      return definition;
216    }
217
218    public IssueSeverity getSeverity() {
219      return severity;
220    }
221
222    public String getMessage() {
223      return message;
224    }
225
226    public boolean IsNoService() {
227      return errorClass == TerminologyServiceErrorClass.NOSERVICE;
228    }
229
230    public TerminologyServiceErrorClass getErrorClass() {
231      return errorClass;
232    }
233
234    public ValidationResult setSeverity(IssueSeverity severity) {
235      this.severity = severity;
236      return this;
237    }
238
239    public ValidationResult setMessage(String message) {
240      this.message = message;
241      return this;
242    }
243    
244    public ValidationResult addToMessage(String message) {
245      this.message = this.message == null ? message : this.message +"; "+ message; 
246      return this;
247    }
248    
249    public ValidationResult setErrorClass(TerminologyServiceErrorClass errorClass) {
250      this.errorClass = errorClass;
251      return this;
252    }
253
254    public String getTxLink() {
255      return txLink;
256    }
257
258    public ValidationResult setTxLink(String txLink) {
259      this.txLink = txLink;
260      return this;
261    }
262
263    public boolean hasMessage() {
264      return message != null;
265    }
266
267    public String getDiagnostics() {
268      return diagnostics;
269    }
270
271    public void setDiagnostics(String diagnostics) {
272      this.diagnostics = diagnostics;
273    }
274
275    public Coding asCoding() {
276      if (isOk() && definition != null && definition.getCode() != null) {
277        return new Coding(system, definition.getCode(), definition.getDisplay());
278      } else {
279        return null;
280      }
281    }
282
283    public List<OperationOutcomeIssueComponent> getIssues() {
284      return issues;
285    }
286
287    public ValidationResult addCodeableConcept(CodeableConcept vcc) {
288      if (!vcc.isEmpty()) {
289        codeableConcept = vcc;
290      }
291      return this;
292    }
293
294    public CodeableConcept getCodeableConcept() {
295      return codeableConcept;
296    }
297
298    public Set<String> getUnknownSystems() {
299      return unknownSystems;
300    }
301
302    public ValidationResult setUnknownSystems(Set<String> unknownSystems) {
303      this.unknownSystems = unknownSystems;
304      return this;
305    }
306
307    public String unknownSystems() {
308      if (unknownSystems == null) {
309        return null;
310      }
311      if (unknownSystems.size() == 1) {
312        return unknownSystems.iterator().next();        
313      } else {
314        return String.join(",", unknownSystems);
315      }
316    }
317
318  }
319
320  public class CodingValidationRequest {
321    private Coding coding;
322    private ValidationResult result;
323    private CacheToken cacheToken;
324
325    public CodingValidationRequest(Coding coding) {
326      super();
327      this.coding = coding;
328    }
329
330    public ValidationResult getResult() {
331      return result;
332    }
333
334    public void setResult(ValidationResult result) {
335      this.result = result;
336    }
337
338    public Coding getCoding() {
339      return coding;
340    }
341
342    public boolean hasResult() {
343      return result != null;
344    }
345
346    /**
347     * internal logic; external users of batch validation should ignore this property
348     * 
349     * @return
350     */
351    public CacheToken getCacheToken() {
352      return cacheToken;
353    }
354
355    /**
356     * internal logic; external users of batch validation should ignore this property
357     * 
358     * @param cacheToken
359     */
360    public void setCacheToken(CacheToken cacheToken) {
361      this.cacheToken = cacheToken;
362    }
363
364
365  }
366
367
368  public interface IContextResourceLoader {
369    /** 
370     * @return List of the resource types that should be loaded
371     */
372    List<String> getTypes();
373
374    /**
375     * Request to actually load the resources and do whatever is required
376     *  
377     * @param stream
378     * @param isJson
379     * @return A bundle because some single resources become multiple resources after loading
380     * @throws FHIRException
381     * @throws IOException
382     */
383    Bundle loadBundle(InputStream stream, boolean isJson) throws FHIRException, IOException;
384
385    /**
386     * Load a single resources (lazy load)
387     * 
388     * @param stream
389     * @param isJson
390     * @return
391     * @throws FHIRException - throw this if you a single resource can't be returned - can't lazy load in this circumstance   
392     * @throws IOException
393     */
394    Resource loadResource(InputStream stream, boolean isJson) throws FHIRException, IOException;
395
396    /** 
397     * get the path for references to this resource.
398     * @param resource
399     * @return null if not tracking paths
400     */
401    String getResourcePath(Resource resource);
402
403    /**
404     * called when a new package is being loaded
405     * 
406     * this is called by loadPackageAndDependencies when a new package is loaded
407     * @param npm
408     * @return
409     * @throws IOException 
410     * @throws JsonSyntaxException 
411     */
412    IContextResourceLoader getNewLoader(NpmPackage npm) throws JsonSyntaxException, IOException;
413
414    /**
415     * called when processing R2 for implicit code systems in ValueSets 
416     * 
417     * @return
418     */
419    List<CodeSystem> getCodeSystems();  
420    
421    /**
422     * if this is true, then the loader will patch canonical URLs and cross-links 
423     * to add /X.X/ into the URL so that different versions can be loaded safely 
424     * 
425     * default is false
426     */
427    void setPatchUrls(boolean value);
428
429    /**
430     * patch the URL if necessary
431     * 
432     * @param url
433     * @return
434     */
435    String patchUrl(String url, String resourceType);
436    
437    /** 
438     * set this to false (default is true) if you don't want profiles loaded
439     * @param value
440     * @return
441     */
442    IContextResourceLoader setLoadProfiles(boolean value);
443    
444    /**
445     * Called during the loading process - the loader can decide which resources to load. 
446     * At this point, only the .index.json is being read 
447     *  
448     * @param pi
449     * @param pri
450     * @return
451     */
452    boolean wantLoad(NpmPackage pi, PackageResourceInformation pri);
453  }
454
455  /**
456   * Get the version of the definitions loaded in context
457   * This *does not* have to be 5.0 (R5) - the context can load other versions
458   * 
459   * @return
460   */
461  public String getVersion();
462
463  /**
464   * Get the UCUM service that provides access to units of measure reasoning services 
465   * 
466   * This service might not be available 
467   * 
468   * @return
469   */
470  public UcumService getUcumService();
471  public void setUcumService(UcumService ucumService);
472
473  /**
474   * Get a validator that can check whether a resource is valid 
475   * 
476   * @return a prepared generator
477   * @throws FHIRException 
478   * @
479   */
480  public IResourceValidator newValidator() throws FHIRException;
481
482  // -- resource fetchers ---------------------------------------------------
483
484  /**
485   * Find an identified resource. The most common use of this is to access the the 
486   * standard conformance resources that are part of the standard - structure 
487   * definitions, value sets, concept maps, etc.
488   * 
489   * Also, the narrative generator uses this, and may access any kind of resource
490   * 
491   * The URI is called speculatively for things that might exist, so not finding 
492   * a matching resource, return null, not an error
493   * 
494   * The URI can have one of 3 formats:
495   *  - a full URL e.g. http://acme.org/fhir/ValueSet/[id]
496   *  - a relative URL e.g. ValueSet/[id]
497   *  - a logical id e.g. [id]
498   *  
499   * It's an error if the second form doesn't agree with class_. It's an 
500   * error if class_ is null for the last form
501   * 
502   * class can be Resource, DomainResource or CanonicalResource, which means resource of all kinds
503   * 
504   * @param resource
505   * @param Reference
506   * @return
507   * @throws FHIRException 
508   * @throws Exception
509   */
510  public <T extends Resource> T fetchResource(Class<T> class_, String uri);
511  public <T extends Resource> T fetchResourceWithException(Class<T> class_, String uri) throws FHIRException;
512  public <T extends Resource> T fetchResourceWithException(Class<T> class_, String uri, Resource sourceOfReference) throws FHIRException;
513  public <T extends Resource> T fetchResource(Class<T> class_, String uri, String version);
514
515  /** has the same functionality as fetchResource, but passes in information about the source of the 
516   * reference (this may affect resolution of version)
517   *  
518   * @param <T>
519   * @param class_
520   * @param uri
521   * @param canonicalForSource
522   * @return
523   */
524  public <T extends Resource> T fetchResource(Class<T> class_, String uri, Resource sourceOfReference);
525
526  /** 
527   * Fetch all the resources of a particular type. if class == (null | Resource | DomainResource | CanonicalResource) return everything
528   *  
529   * @param <T>
530   * @param class_
531   * @param uri
532   * @param canonicalForSource
533   * @return
534   */
535  public <T extends Resource> List<T> fetchResourcesByType(Class<T> class_);
536
537  /**
538   * Variation of fetchResource when you have a string type, and don't need the right class
539   * 
540   * The URI can have one of 3 formats:
541   *  - a full URL e.g. http://acme.org/fhir/ValueSet/[id]
542   *  - a relative URL e.g. ValueSet/[id]
543   *  - a logical id e.g. [id]
544   *  
545   * if type == null, the URI can't be a simple logical id
546   * 
547   * @param type
548   * @param uri
549   * @return
550   */
551  public Resource fetchResourceById(String type, String uri);
552
553  /**
554   * find whether a resource is available. 
555   * 
556   * Implementations of the interface can assume that if hasResource ruturns 
557   * true, the resource will usually be fetched subsequently
558   * 
559   * @param class_
560   * @param uri
561   * @return
562   */
563  public <T extends Resource> boolean hasResource(Class<T> class_, String uri);
564
565  /**
566   * cache a resource for later retrieval using fetchResource.
567   * 
568   * Note that various context implementations will have their own ways of loading
569   * rseources, and not all need implement cacheResource.
570   * 
571   * If the resource is loaded out of a package, call cacheResourceFromPackage instead
572   * @param res
573   * @throws FHIRException 
574   */
575  public void cacheResource(Resource res) throws FHIRException;
576
577  /**
578   * cache a resource for later retrieval using fetchResource.
579   * 
580   * The package information is used to help manage the cache internally, and to 
581   * help with reference resolution. Packages should be define using cachePackage (but don't have to be)
582   *    
583   * Note that various context implementations will have their own ways of loading
584   * rseources, and not all need implement cacheResource
585   * 
586   * @param res
587   * @throws FHIRException 
588   */
589  public void cacheResourceFromPackage(Resource res, PackageInformation packageInfo) throws FHIRException;
590
591  /**
592   * Inform the cache about package dependencies. This can be used to help resolve references
593   * 
594   * Note that the cache doesn't load dependencies
595   *  
596   * @param packageInfo
597   */
598  public void cachePackage(PackageInformation packageInfo);
599
600  // -- profile services ---------------------------------------------------------
601
602  /**
603   * @return a list of the resource names defined for this version
604   */
605  public List<String> getResourceNames();
606  /**
607   * @return a set of the resource names defined for this version
608   */
609  public Set<String> getResourceNamesAsSet();
610
611  // -- Terminology services ------------------------------------------------------
612
613  /**
614   * Set the expansion parameters passed through the terminology server when txServer calls are made
615   * 
616   * Note that the Validation Options override these when they are specified on validateCode
617   */
618  public Parameters getExpansionParameters();
619
620  /**
621   * Get the expansion parameters passed through the terminology server when txServer calls are made
622   * 
623   * Note that the Validation Options override these when they are specified on validateCode
624   */
625  public void setExpansionProfile(Parameters expParameters);
626
627  // these are the terminology services used internally by the tools
628  /**
629   * Find the code system definition for the nominated system uri. 
630   * return null if there isn't one (then the tool might try 
631   * supportsSystem)
632   * 
633   * This is a short cut for fetchResource(CodeSystem.class...)
634   * 
635   * @param system
636   * @return
637   */
638  public CodeSystem fetchCodeSystem(String system);
639  public CodeSystem fetchCodeSystem(String system, String version);
640
641  /**
642   * Like fetchCodeSystem, except that the context will find any CodeSysetm supplements and merge them into the
643   * @param system
644   * @return
645   */
646  public CodeSystem fetchSupplementedCodeSystem(String system);
647  public CodeSystem fetchSupplementedCodeSystem(String system, String version);
648
649  /**
650   * True if the underlying terminology service provider will do 
651   * expansion and code validation for the terminology. Corresponds
652   * to the extension 
653   * 
654   * http://hl7.org/fhir/StructureDefinition/capabilitystatement-supported-system
655   * 
656   * in the Conformance resource
657   * 
658   * Not that not all supported code systems have an available CodeSystem resource
659   * 
660   * @param system
661   * @return
662   * @throws Exception 
663   */
664  public boolean supportsSystem(String system) throws TerminologyServiceException;
665
666  /**
667   * ValueSet Expansion - see $expand
668   *  
669   * @param source
670   * @return
671   */
672  public ValueSetExpansionOutcome expandVS(ValueSet source, boolean cacheOk, boolean heiarchical);
673
674  /**
675   * ValueSet Expansion - see $expand
676   *  
677   * @param source
678   * @return
679   */
680  public ValueSetExpansionOutcome expandVS(ValueSet source, boolean cacheOk, boolean heiarchical, boolean incompleteOk);
681
682  /**
683   * ValueSet Expansion - see $expand, but resolves the binding first
684   *  
685   * @param source
686   * @return
687   * @throws FHIRException 
688   */
689  public ValueSetExpansionOutcome expandVS(Resource src, ElementDefinitionBindingComponent binding, boolean cacheOk, boolean heiarchical) throws FHIRException;
690
691  /**
692   * Value set expanion inside the internal expansion engine - used 
693   * for references to supported system (see "supportsSystem") for
694   * which there is no value set. 
695   * 
696   * @param inc
697   * @return
698   * @throws FHIRException 
699   */
700  ValueSetExpansionOutcome expandVS(ConceptSetComponent inc, boolean hierarchical, boolean noInactive) throws TerminologyServiceException;
701
702  /**
703   * get/set the locale used when creating messages
704   * 
705   * todo: what's the difference?
706   * 
707   * @return
708   */
709  Locale getLocale();
710  void setLocale(Locale locale);
711  void setValidationMessageLanguage(Locale locale);
712
713  /**
714   * Access to the contexts internationalised error messages
715   *  
716   * @param theMessage
717   * @param theMessageArguments
718   * @return
719   */
720  String formatMessage(String theMessage, Object... theMessageArguments);
721  String formatMessagePlural(Integer pluralNum, String theMessage, Object... theMessageArguments);
722
723  /**
724   * Validation of a code - consult the terminology infrstructure and/or service 
725   * to see whether it is known. If known, return a description of it
726   * 
727   * note: always return a result, with either an error or a code description
728   *  
729   * corresponds to 2 terminology service calls: $validate-code and $lookup
730   * 
731   * in this case, the system will be inferred from the value set. It's an error to call this one without the value set
732   * 
733   * @param options - validation options (required)
734   * @param code he code to validate (required)
735   * @param vs the applicable valueset (required)
736   * @return
737   */
738  public ValidationResult validateCode(ValidationOptions options, String code, ValueSet vs);
739
740  /**
741   * Validation of a code - consult the terminology infrstructure and/or service 
742   * to see whether it is known. If known, return a description of it
743   * 
744   * note: always return a result, with either an error or a code description
745   *  
746   * corresponds to 2 terminology service calls: $validate-code and $lookup
747   * 
748   * @param options - validation options (required)
749   * @param system - equals Coding.system (required)
750   * @param code - equals Coding.code (required)
751   * @param display - equals Coding.display (optional)
752   * @return
753   */
754  public ValidationResult validateCode(ValidationOptions options, String system, String version, String code, String display);
755
756  /**
757   * Validation of a code - consult the terminology infrstructure and/or service 
758   * to see whether it is known. If known, return a description of it
759   * 
760   * note: always return a result, with either an error or a code description
761   *  
762   * corresponds to 2 terminology service calls: $validate-code and $lookup
763   * 
764   * @param options - validation options (required)
765   * @param system - equals Coding.system (required)
766   * @param code - equals Coding.code (required)
767   * @param display - equals Coding.display (optional)
768   * @param vs the applicable valueset (optional)
769   * @return
770   */
771  public ValidationResult validateCode(ValidationOptions options, String system, String version, String code, String display, ValueSet vs);
772
773  /**
774   * Validation of a code - consult the terminology infrstructure and/or service 
775   * to see whether it is known. If known, return a description of it
776   * 
777   * note: always return a result, with either an error or a code description
778   *  
779   * corresponds to 2 terminology service calls: $validate-code and $lookup
780   * 
781   * Note that this doesn't validate binding strength (e.g. is just text allowed?)
782   * 
783   * @param options - validation options (required)
784   * @param code - CodeableConcept to validate
785   * @param vs the applicable valueset (optional)
786   * @return
787   */
788  public ValidationResult validateCode(ValidationOptions options, CodeableConcept code, ValueSet vs);
789
790  /**
791   * Validation of a code - consult the terminology infrstructure and/or service 
792   * to see whether it is known. If known, return a description of it
793   * 
794   * note: always return a result, with either an error or a code description
795   *  
796   * corresponds to 2 terminology service calls: $validate-code and $lookup
797   * 
798   * in this case, the system will be inferred from the value set. It's an error to call this one without the value set
799   * 
800   * @param options - validation options (required)
801   * @param code - Coding to validate
802   * @param vs the applicable valueset (optional)
803   * @return
804   */
805  public ValidationResult validateCode(ValidationOptions options, Coding code, ValueSet vs);
806
807  /** 
808   * See comments in ValidationContextCarrier. This is called when there might be additional value sets etc 
809   * available in the context, but we don't want to pre-process them. 
810   * 
811   * @param options
812   * @param code
813   * @param vs
814   * @param ctxt
815   * @return
816   */
817  public ValidationResult validateCode(ValidationOptions options, Coding code, ValueSet vs, ValidationContextCarrier ctxt);
818
819  /**
820   * Batch validate code - reduce latency and do a bunch of codes in a single server call. 
821   * Each is the same as a validateCode
822   * 
823   * @param options
824   * @param codes
825   * @param vs
826   */
827  public void validateCodeBatch(ValidationOptions options, List<? extends CodingValidationRequest> codes, ValueSet vs);
828
829
830  // todo: figure these out
831  public Map<String, NamingSystem> getNSUrlMap();
832  public TranslationServices translator();
833
834  public interface ILoggingService {
835    public enum LogCategory {
836      INIT, 
837      PROGRESS,
838      TX, 
839      CONTEXT, 
840      GENERATE,
841      HTML 
842    }
843    public void logMessage(String message); // status messages, always display
844    public void logDebugMessage(LogCategory category, String message); // verbose; only when debugging 
845    public boolean isDebugLogging(); // whether to log debug information
846  }
847  public void setLogger(@Nonnull ILoggingService logger);
848  public ILoggingService getLogger();
849
850  public boolean isNoTerminologyServer();
851  public Set<String> getCodeSystemsUsed();
852  public int getClientRetryCount();
853  public IWorkerContext setClientRetryCount(int value);
854
855  public TimeTracker clock();
856
857  /**
858   * This is a short cut for fetchResource(StructureDefinition.class, ...)
859   * but it accepts a typename - that is, it resolves based on StructureDefinition.type 
860   * or StructureDefinition.url. This only resolves to http://hl7.org/fhir/StructureDefinition/{typename}
861   * 
862   * @param typeName
863   * @return
864   */
865  public StructureDefinition fetchTypeDefinition(String typeName);
866
867  /**
868   * This finds all the structure definitions that have the given typeName
869   * 
870   * @param typeName
871   * @return
872   */
873  public List<StructureDefinition> fetchTypeDefinitions(String n);
874
875
876  /**
877   * Returns a set of keys that can be used to get binaries from this context.
878   * The binaries come from the loaded packages (mostly the pubpack)
879   *
880   * @return a set of binaries or null
881   */
882  public Set<String> getBinaryKeysAsSet();
883
884  /**
885   * Returns true if this worker context contains a binary for this key.
886   *
887   * @param binaryKey
888   * @return true if binary is available for this key
889   */
890  public boolean hasBinaryKey(String binaryKey);
891
892  /**
893   * Returns the binary for the key
894   * @param binaryKey
895   * @return
896   */
897  public byte[] getBinaryForKey(String binaryKey);
898
899  /*
900   * Todo: move these loaders out to IWorkerContextManager
901   * 
902   */
903  /**
904   * Load relevant resources of the appropriate types (as specified by the loader) from the nominated package
905   * 
906   * note that the package system uses lazy loading; the loader will be called later when the classes that use the context need the relevant resource
907   * 
908   * @param pi - the package to load
909   * @param loader - an implemenation of IContextResourceLoader that knows how to read the resources in the package (e.g. for the appropriate version).
910   * @return the number of resources loaded
911   */
912  int loadFromPackage(NpmPackage pi, IContextResourceLoader loader) throws FileNotFoundException, IOException, FHIRException;
913
914  /**
915   * Load relevant resources of the appropriate types (as specified by the loader) from the nominated package
916   * 
917   * note that the package system uses lazy loading; the loader will be called later when the classes that use the context need the relevant resource
918   *
919   * Deprecated - use the simpler method where the types come from the loader.
920   * 
921   * @param pi - the package to load
922   * @param loader - an implemenation of IContextResourceLoader that knows how to read the resources in the package (e.g. for the appropriate version).
923   * @param types - which types of resources to load
924   * @return the number of resources loaded
925   */
926  @Deprecated
927  int loadFromPackage(NpmPackage pi, IContextResourceLoader loader, List<String> types) throws FileNotFoundException, IOException, FHIRException;
928
929  /**
930   * Load relevant resources of the appropriate types (as specified by the loader) from the nominated package
931   * 
932   * note that the package system uses lazy loading; the loader will be called later when the classes that use the context need the relevant resource
933   *
934   * This method also loads all the packages that the package depends on (recursively)
935   * 
936   * @param pi - the package to load
937   * @param loader - an implemenation of IContextResourceLoader that knows how to read the resources in the package (e.g. for the appropriate version).
938   * @param pcm - used to find and load additional dependencies
939   * @return the number of resources loaded
940   */
941  int loadFromPackageAndDependencies(NpmPackage pi, IContextResourceLoader loader, BasePackageCacheManager pcm) throws FileNotFoundException, IOException, FHIRException;
942
943  public boolean hasPackage(String id, String ver);
944  public boolean hasPackage(PackageInformation pack);
945  public PackageInformation getPackage(String id, String ver);
946  public PackageInformation getPackageForUrl(String url);
947
948  public IWorkerContextManager.IPackageLoadingTracker getPackageTracker();
949  public IWorkerContext setPackageTracker(IWorkerContextManager.IPackageLoadingTracker packageTracker);
950
951  public String getSpecUrl();
952
953  public PEBuilder getProfiledElementBuilder(PEElementPropertiesPolicy elementProps, boolean fixedProps);
954  
955  public boolean isForPublication();
956  public void setForPublication(boolean value);
957}