001package org.hl7.fhir.r4.elementmodel;
002
003import java.io.IOException;
004import java.io.InputStream;
005import java.io.OutputStream;
006import java.util.HashMap;
007import java.util.List;
008import java.util.Map;
009
010import org.hl7.fhir.r4.context.IWorkerContext;
011import org.hl7.fhir.r4.formats.FormatUtilities;
012import org.hl7.fhir.r4.formats.IParser.OutputStyle;
013import org.hl7.fhir.r4.model.StructureDefinition;
014import org.hl7.fhir.r4.model.StructureDefinition.StructureDefinitionKind;
015import org.hl7.fhir.r4.model.StructureDefinition.TypeDerivationRule;
016import org.hl7.fhir.r4.utils.ToolingExtensions;
017import org.hl7.fhir.exceptions.DefinitionException;
018import org.hl7.fhir.exceptions.FHIRException;
019import org.hl7.fhir.exceptions.FHIRFormatError;
020import org.hl7.fhir.utilities.Utilities;
021import org.hl7.fhir.utilities.validation.ValidationMessage;
022import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
023import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
024import org.hl7.fhir.utilities.validation.ValidationMessage.Source;
025
026public abstract class ParserBase {
027
028  public interface ILinkResolver {
029    String resolveType(String type);
030    String resolveProperty(Property property);
031    String resolvePage(String string);
032  }
033  
034  public enum ValidationPolicy { NONE, QUICK, EVERYTHING }
035
036  public boolean isPrimitive(String code) {
037    return Utilities.existsInList(code, "boolean", "integer", "string", "decimal", "uri", "base64Binary", "instant", "date", "dateTime", "time", "code", "oid", "id", "markdown", "unsignedInt", "positiveInt", "xhtml", "url", "canonical");
038    
039//    StructureDefinition sd = context.fetchTypeDefinition(code);
040//    return sd != null && sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE;
041        }
042
043        protected IWorkerContext context;
044        protected ValidationPolicy policy;
045  protected List<ValidationMessage> errors;
046  protected ILinkResolver linkResolver;
047  protected boolean showDecorations;
048  
049        public ParserBase(IWorkerContext context) {
050                super();
051                this.context = context;
052                policy = ValidationPolicy.NONE;
053        }
054
055        public void setupValidation(ValidationPolicy policy, List<ValidationMessage> errors) {
056          this.policy = policy;
057          this.errors = errors;
058        }
059
060  public abstract Element parse(InputStream stream) throws IOException, FHIRFormatError, DefinitionException, FHIRException;
061
062        public abstract void compose(Element e, OutputStream destination, OutputStyle style, String base)  throws FHIRException, IOException;
063
064        
065        public void logError(int line, int col, String path, IssueType type, String message, IssueSeverity level) throws FHIRFormatError {
066          if (policy == ValidationPolicy.EVERYTHING) {
067            ValidationMessage msg = new ValidationMessage(Source.InstanceValidator, type, line, col, path, message, level);
068            errors.add(msg);
069          } else if (level == IssueSeverity.FATAL || (level == IssueSeverity.ERROR && policy == ValidationPolicy.QUICK))
070            throw new FHIRFormatError(message+String.format(" at line %d col %d", line, col));
071        }
072        
073        
074        protected StructureDefinition getDefinition(int line, int col, String ns, String name) throws FHIRFormatError {
075    if (ns == null) {
076      logError(line, col, name, IssueType.STRUCTURE, "This cannot be parsed as a FHIR object (no namespace)", IssueSeverity.FATAL);
077      return null;
078    }
079    if (name == null) {
080      logError(line, col, name, IssueType.STRUCTURE, "This cannot be parsed as a FHIR object (no name)", IssueSeverity.FATAL);
081      return null;
082        }
083          for (StructureDefinition sd : context.allStructures()) {
084            if (name.equals(sd.getType()) && sd.getDerivation() == TypeDerivationRule.SPECIALIZATION && !sd.getUrl().startsWith("http://hl7.org/fhir/StructureDefinition/de-")) {
085              if((ns == null || ns.equals(FormatUtilities.FHIR_NS)) && !ToolingExtensions.hasExtension(sd, "http://hl7.org/fhir/StructureDefinition/elementdefinition-namespace"))
086                return sd;
087              String sns = ToolingExtensions.readStringExtension(sd, "http://hl7.org/fhir/StructureDefinition/elementdefinition-namespace");
088              if (ns != null && ns.equals(sns))
089                return sd;
090            }
091          }
092          logError(line, col, name, IssueType.STRUCTURE, "This does not appear to be a FHIR resource (unknown namespace/name '"+ns+"::"+name+"')", IssueSeverity.FATAL);
093          return null;
094  }
095
096        protected StructureDefinition getDefinition(int line, int col, String name) throws FHIRFormatError {
097    if (name == null) {
098      logError(line, col, name, IssueType.STRUCTURE, "This cannot be parsed as a FHIR object (no name)", IssueSeverity.FATAL);
099      return null;
100        }
101    // first pass: only look at base definitions
102          for (StructureDefinition sd : context.allStructures()) {
103            if (sd.getUrl().equals("http://hl7.org/fhir/StructureDefinition/"+name)) {
104              return sd;
105            }
106          }
107    for (StructureDefinition sd : context.allStructures()) {
108      if (name.equals(sd.getType()) && sd.getDerivation() == TypeDerivationRule.SPECIALIZATION) {
109        return sd;
110      }
111    }
112          logError(line, col, name, IssueType.STRUCTURE, "This does not appear to be a FHIR resource (unknown name '"+name+"')", IssueSeverity.FATAL);
113          return null;
114  }
115
116  public ILinkResolver getLinkResolver() {
117    return linkResolver;
118  }
119
120  public ParserBase setLinkResolver(ILinkResolver linkResolver) {
121    this.linkResolver = linkResolver;
122    return this;
123  }
124
125  public boolean isShowDecorations() {
126    return showDecorations;
127  }
128
129  public void setShowDecorations(boolean showDecorations) {
130    this.showDecorations = showDecorations;
131  }
132
133
134}