001package org.hl7.fhir.r4.elementmodel;
002
003/*-
004 * #%L
005 * org.hl7.fhir.r4
006 * %%
007 * Copyright (C) 2014 - 2019 Health Level 7
008 * %%
009 * Licensed under the Apache License, Version 2.0 (the "License");
010 * you may not use this file except in compliance with the License.
011 * You may obtain a copy of the License at
012 * 
013 *      http://www.apache.org/licenses/LICENSE-2.0
014 * 
015 * Unless required by applicable law or agreed to in writing, software
016 * distributed under the License is distributed on an "AS IS" BASIS,
017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018 * See the License for the specific language governing permissions and
019 * limitations under the License.
020 * #L%
021 */
022
023
024import java.io.IOException;
025import java.io.InputStream;
026import java.io.OutputStream;
027import java.util.List;
028
029import org.hl7.fhir.exceptions.DefinitionException;
030import org.hl7.fhir.exceptions.FHIRException;
031import org.hl7.fhir.exceptions.FHIRFormatError;
032import org.hl7.fhir.r4.context.IWorkerContext;
033import org.hl7.fhir.r4.formats.FormatUtilities;
034import org.hl7.fhir.r4.formats.IParser.OutputStyle;
035import org.hl7.fhir.r4.model.StructureDefinition;
036import org.hl7.fhir.r4.model.StructureDefinition.TypeDerivationRule;
037import org.hl7.fhir.r4.utils.ToolingExtensions;
038import org.hl7.fhir.utilities.Utilities;
039import org.hl7.fhir.utilities.validation.ValidationMessage;
040import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
041import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
042import org.hl7.fhir.utilities.validation.ValidationMessage.Source;
043
044public abstract class ParserBase {
045
046  public interface ILinkResolver {
047    String resolveType(String type);
048    String resolveProperty(Property property);
049    String resolvePage(String string);
050  }
051  
052  public enum ValidationPolicy { NONE, QUICK, EVERYTHING }
053
054  public boolean isPrimitive(String code) {
055    return Utilities.existsInList(code, "boolean", "integer", "string", "decimal", "uri", "base64Binary", "instant", "date", "dateTime", "time", "code", "oid", "id", "markdown", "unsignedInt", "positiveInt", "xhtml", "url", "canonical");
056    
057//    StructureDefinition sd = context.fetchTypeDefinition(code);
058//    return sd != null && sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE;
059        }
060
061        protected IWorkerContext context;
062        protected ValidationPolicy policy;
063  protected List<ValidationMessage> errors;
064  protected ILinkResolver linkResolver;
065  protected boolean showDecorations;
066  
067        public ParserBase(IWorkerContext context) {
068                super();
069                this.context = context;
070                policy = ValidationPolicy.NONE;
071        }
072
073        public void setupValidation(ValidationPolicy policy, List<ValidationMessage> errors) {
074          this.policy = policy;
075          this.errors = errors;
076        }
077
078  public abstract Element parse(InputStream stream) throws IOException, FHIRFormatError, DefinitionException, FHIRException;
079
080        public abstract void compose(Element e, OutputStream destination, OutputStyle style, String base)  throws FHIRException, IOException;
081
082        
083        public void logError(int line, int col, String path, IssueType type, String message, IssueSeverity level) throws FHIRFormatError {
084          if (policy == ValidationPolicy.EVERYTHING) {
085            ValidationMessage msg = new ValidationMessage(Source.InstanceValidator, type, line, col, path, message, level);
086            errors.add(msg);
087          } else if (level == IssueSeverity.FATAL || (level == IssueSeverity.ERROR && policy == ValidationPolicy.QUICK))
088            throw new FHIRFormatError(message+String.format(" at line %d col %d", line, col));
089        }
090        
091        
092        protected StructureDefinition getDefinition(int line, int col, String ns, String name) throws FHIRFormatError {
093    if (ns == null) {
094      logError(line, col, name, IssueType.STRUCTURE, "This cannot be parsed as a FHIR object (no namespace)", IssueSeverity.FATAL);
095      return null;
096    }
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          for (StructureDefinition sd : context.allStructures()) {
102            if (sd.getDerivation() == TypeDerivationRule.SPECIALIZATION && !sd.getUrl().startsWith("http://hl7.org/fhir/StructureDefinition/de-")) {
103              if(name.equals(sd.getType()) && (ns == null || ns.equals(FormatUtilities.FHIR_NS)) && !ToolingExtensions.hasExtension(sd, "http://hl7.org/fhir/StructureDefinition/elementdefinition-namespace"))
104                return sd;
105              String sns = ToolingExtensions.readStringExtension(sd, "http://hl7.org/fhir/StructureDefinition/elementdefinition-namespace");
106              if (name.equals(sd.getType()) && ns != null && ns.equals(sns))
107                return sd;
108            }
109          }
110          logError(line, col, name, IssueType.STRUCTURE, "This does not appear to be a FHIR resource (unknown namespace/name '"+ns+"::"+name+"')", IssueSeverity.FATAL);
111          return null;
112  }
113
114        protected StructureDefinition getDefinition(int line, int col, String name) throws FHIRFormatError {
115    if (name == null) {
116      logError(line, col, name, IssueType.STRUCTURE, "This cannot be parsed as a FHIR object (no name)", IssueSeverity.FATAL);
117      return null;
118        }
119    // first pass: only look at base definitions
120          for (StructureDefinition sd : context.getStructures()) {
121            if (sd.getUrl().equals("http://hl7.org/fhir/StructureDefinition/"+name)) {
122              context.generateSnapshot(sd); 
123              return sd;
124            }
125          }
126    for (StructureDefinition sd : context.getStructures()) {
127      if (name.equals(sd.getType()) && sd.getDerivation() == TypeDerivationRule.SPECIALIZATION) {
128        context.generateSnapshot(sd); 
129        return sd;
130      }
131    }
132          logError(line, col, name, IssueType.STRUCTURE, "This does not appear to be a FHIR resource (unknown name '"+name+"')", IssueSeverity.FATAL);
133          return null;
134  }
135
136  public ILinkResolver getLinkResolver() {
137    return linkResolver;
138  }
139
140  public ParserBase setLinkResolver(ILinkResolver linkResolver) {
141    this.linkResolver = linkResolver;
142    return this;
143  }
144
145  public boolean isShowDecorations() {
146    return showDecorations;
147  }
148
149  public void setShowDecorations(boolean showDecorations) {
150    this.showDecorations = showDecorations;
151  }
152
153
154}