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}