001package org.hl7.fhir.r5.formats;
002
003
004
005
006
007/*
008  Copyright (c) 2011+, HL7, Inc.
009  All rights reserved.
010  
011  Redistribution and use in source and binary forms, with or without modification, 
012  are permitted provided that the following conditions are met:
013  
014   * Redistributions of source code must retain the above copyright notice, this 
015     list of conditions and the following disclaimer.
016   * Redistributions in binary form must reproduce the above copyright notice, 
017     this list of conditions and the following disclaimer in the documentation 
018     and/or other materials provided with the distribution.
019   * Neither the name of HL7 nor the names of its contributors may be used to 
020     endorse or promote products derived from this software without specific 
021     prior written permission.
022  
023  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
024  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
025  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
026  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
027  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
028  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
029  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
030  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
031  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
032  POSSIBILITY OF SUCH DAMAGE.
033  
034*/
035
036
037import java.io.ByteArrayInputStream;
038import java.io.ByteArrayOutputStream;
039import java.io.IOException;
040import java.io.InputStream;
041import java.math.BigDecimal;
042import java.nio.charset.StandardCharsets;
043import java.text.ParseException;
044import java.util.HashMap;
045import java.util.Map;
046
047import org.apache.commons.codec.binary.Base64;
048import org.hl7.fhir.exceptions.FHIRFormatError;
049import org.hl7.fhir.r5.model.DataType;
050import org.hl7.fhir.r5.model.Resource;
051import org.hl7.fhir.r5.model.StringType;
052import org.hl7.fhir.utilities.Utilities;
053import org.hl7.fhir.utilities.xml.IXMLWriter;
054
055public abstract class ParserBase extends FormatUtilities implements IParser {
056
057  protected static Map<String, IParserFactory> customResourceHandlers = new HashMap<>();
058
059  public interface IParserFactory {
060    public JsonParserBase composerJson(JsonCreator json);
061    public JsonParserBase parserJson(boolean allowUnknownContent, boolean allowComments);
062    public XmlParserBase composerXml(IXMLWriter xml);
063    public XmlParserBase parserXml(boolean allowUnknownContent);
064  }
065  // -- implementation of variant type methods from the interface --------------------------------
066  
067  public Resource parse(String input) throws FHIRFormatError, IOException {
068        return parse(input.getBytes(StandardCharsets.UTF_8));
069  }
070  
071  public Resource parse(byte[] bytes) throws FHIRFormatError, IOException {
072        ByteArrayInputStream bi = new ByteArrayInputStream(bytes);
073        return parse(bi);
074  }
075
076  public DataType parseType(String input, String typeName) throws FHIRFormatError, IOException {
077    return parseType(input.getBytes(StandardCharsets.UTF_8), typeName);
078  }
079  
080  public DataType parseAnyType(String input, String typeName) throws FHIRFormatError, IOException {
081    return parseAnyType(input.getBytes(StandardCharsets.UTF_8), typeName);
082  }
083  
084  public DataType parseType(byte[] bytes, String typeName) throws FHIRFormatError, IOException {
085    ByteArrayInputStream bi = new ByteArrayInputStream(bytes);
086    return parseType(bi, typeName);
087  }
088
089  public DataType parseAnyType(byte[] bytes, String typeName) throws FHIRFormatError, IOException {
090    ByteArrayInputStream bi = new ByteArrayInputStream(bytes);
091    return parseAnyType(bi, typeName);
092  }
093
094  public String composeString(Resource resource) throws IOException {
095    return new String(composeBytes(resource), StandardCharsets.UTF_8);
096  }
097
098  public byte[] composeBytes(Resource resource) throws IOException {
099    ByteArrayOutputStream bytes = new ByteArrayOutputStream();
100    compose(bytes, resource);
101    bytes.close();
102    return bytes.toByteArray();
103  }
104
105  public String composeString(DataType type, String typeName) throws IOException {
106    return new String(composeBytes(type, typeName), StandardCharsets.UTF_8);
107  }
108
109  public byte[] composeBytes(DataType type, String typeName) throws IOException {
110    ByteArrayOutputStream bytes = new ByteArrayOutputStream();
111    compose(bytes, type, typeName);
112    bytes.close();
113    return bytes.toByteArray();
114  }
115
116
117  // -- Parser Configuration --------------------------------
118
119  protected String xhtmlMessage;
120  
121        @Override
122  public IParser setSuppressXhtml(String message) {
123    xhtmlMessage = message;
124    return this;
125  }
126  
127  protected boolean handleComments = false;
128  
129  public boolean getHandleComments() {
130    return handleComments;
131  }
132
133  public IParser setHandleComments(boolean value) {
134    this.handleComments = value;
135    return this;
136  }
137  
138  /**
139   * Whether to throw an exception if unknown content is found (or just skip it)
140   */
141  protected boolean allowUnknownContent;
142  
143  /**
144   * whether to allow comments in the json (special case for IG publisher source)
145   */
146  protected boolean allowComments;
147  
148  /**
149   * @return Whether to throw an exception if unknown content is found (or just skip it) 
150   */
151  public boolean isAllowUnknownContent() {
152    return true; // allowUnknownContent;
153  }
154  /**
155   * @param allowUnknownContent Whether to throw an exception if unknown content is found (or just skip it)
156   */
157  public IParser setAllowUnknownContent(boolean allowUnknownContent) {
158    this.allowUnknownContent = allowUnknownContent;
159    return this;
160  }
161    
162  public boolean isAllowComments() {
163    return allowComments;
164  }
165
166  public void setAllowComments(boolean allowComments) {
167    this.allowComments = allowComments;
168  }
169
170  protected OutputStyle style = OutputStyle.NORMAL;
171  
172  public OutputStyle getOutputStyle() {
173    return style;
174  }
175
176  public IParser setOutputStyle(OutputStyle style) {
177    this.style = style;
178    return this;
179  }
180  
181  // -- Parser Utilities --------------------------------
182        
183
184  protected Map<String, Object> idMap = new HashMap<String, Object>();
185
186
187  protected int parseIntegerPrimitive(String value) {
188    if (value.startsWith("+") && Utilities.isInteger(value.substring(1)))
189      value = value.substring(1);
190        return java.lang.Integer.parseInt(value);
191  }
192  protected int parseIntegerPrimitive(java.lang.Long value) {
193    if (value < java.lang.Integer.MIN_VALUE || value > java.lang.Integer.MAX_VALUE) {
194        throw new IllegalArgumentException
195            (value + " cannot be cast to int without changing its value.");
196    }
197    return value.intValue();
198  }
199
200
201  protected String parseCodePrimitive(String value) {
202    return value;
203  }
204
205  protected String parseTimePrimitive(String value) throws ParseException {
206    return value;
207  }
208
209  protected BigDecimal parseDecimalPrimitive(BigDecimal value) {
210    return value;
211  }
212
213  protected BigDecimal parseDecimalPrimitive(String value) {
214    return new BigDecimal(value);
215  }
216
217  protected String parseUriPrimitive(String value) {
218         return value;
219  }
220
221  protected byte[] parseBase64BinaryPrimitive(String value) {
222    return Base64.decodeBase64(value.getBytes());
223  }
224  
225  protected String parseOidPrimitive(String value) {
226    return value;
227  }
228
229  protected Boolean parseBooleanPrimitive(String value) {
230    return java.lang.Boolean.valueOf(value);
231  }
232  
233  protected Boolean parseBooleanPrimitive(Boolean value) {
234    return java.lang.Boolean.valueOf(value);
235  }
236  
237  protected String parseIdPrimitive(String value) {
238    return value;
239  }
240
241  protected String parseStringPrimitive(String value) {
242    return value;
243  }
244
245  protected String parseUuidPrimitive(String value) {
246    return value;
247  }
248
249  @Override
250  public Resource parseAndClose(InputStream input) throws IOException, FHIRFormatError {
251    try {
252      return parse(input);
253    } finally {
254      input.close();
255    }
256  }
257
258  public static Map<String, IParserFactory> getCustomResourceHandlers() {
259    return customResourceHandlers;
260  }
261
262}