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