001package org.hl7.fhir.r4.formats;
002
003import java.io.FileNotFoundException;
004import java.io.IOException;
005
006/*-
007 * #%L
008 * org.hl7.fhir.r4
009 * %%
010 * Copyright (C) 2014 - 2019 Health Level 7
011 * %%
012 * Licensed under the Apache License, Version 2.0 (the "License");
013 * you may not use this file except in compliance with the License.
014 * You may obtain a copy of the License at
015 * 
016 *      http://www.apache.org/licenses/LICENSE-2.0
017 * 
018 * Unless required by applicable law or agreed to in writing, software
019 * distributed under the License is distributed on an "AS IS" BASIS,
020 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
021 * See the License for the specific language governing permissions and
022 * limitations under the License.
023 * #L%
024 */
025
026
027/*
028Copyright (c) 2011+, HL7, Inc
029All rights reserved.
030
031Redistribution and use in source and binary forms, with or without modification, 
032are permitted provided that the following conditions are met:
033
034 * Redistributions of source code must retain the above copyright notice, this 
035   list of conditions and the following disclaimer.
036 * Redistributions in binary form must reproduce the above copyright notice, 
037   this list of conditions and the following disclaimer in the documentation 
038   and/or other materials provided with the distribution.
039 * Neither the name of HL7 nor the names of its contributors may be used to 
040   endorse or promote products derived from this software without specific 
041   prior written permission.
042
043THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
044ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
045WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
046IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
047INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
048NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
049PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
050WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
051ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
052POSSIBILITY OF SUCH DAMAGE.
053
054*/
055
056import java.math.BigDecimal;
057import java.net.URI;
058
059import org.apache.commons.codec.binary.Base64;
060import org.hl7.fhir.exceptions.FHIRException;
061import org.hl7.fhir.exceptions.FHIRFormatError;
062import org.hl7.fhir.r4.elementmodel.Manager.FhirFormat;
063import org.hl7.fhir.r4.model.Resource;
064import org.hl7.fhir.utilities.TextFile;
065
066public abstract class FormatUtilities {
067  public static final String ID_REGEX = "[A-Za-z0-9\\-\\.]{1,64}";
068  public static final String FHIR_NS = "http://hl7.org/fhir";
069  public static final String XHTML_NS = "http://www.w3.org/1999/xhtml";
070  public static final String NS_XSI = "http://www.w3.org/2001/XMLSchema-instance";
071  private static final int MAX_SCAN_LENGTH = 1000; // how many characters to scan into content when autodetermining format
072 
073  protected String toString(String value) {
074    return value;
075  }
076  
077  protected String toString(int value) {
078    return java.lang.Integer.toString(value);
079  }
080  
081  protected String toString(boolean value) {
082    return java.lang.Boolean.toString(value);
083  }
084  
085  protected String toString(BigDecimal value) {
086    return value.toString();
087  }
088  
089  protected String toString(URI value) {
090    return value.toString();
091  }
092
093  public static String toString(byte[] value) {
094    byte[] encodeBase64 = Base64.encodeBase64(value);
095    return new String(encodeBase64);
096  }
097  
098        public static boolean isValidId(String tail) {
099          return tail.matches(ID_REGEX);
100  }
101
102  public static String makeId(String candidate) {
103    StringBuilder b = new StringBuilder();
104    for (char c : candidate.toCharArray())
105      if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '.' || c == '-')
106        b.append(c);
107    return b.toString();
108  }
109
110  public static ParserBase makeParser(FhirFormat format) {
111    switch (format) {
112    case XML : return new XmlParser();
113    case JSON : return new JsonParser();
114    case TURTLE : throw new Error("unsupported Format "+format.toString()); // return new TurtleParser();
115    case VBAR : throw new Error("unsupported Format "+format.toString()); // 
116    case TEXT : throw new Error("unsupported Format "+format.toString()); // 
117    }
118    throw new Error("unsupported Format "+format.toString());
119  }
120  
121  public static ParserBase makeParser(String format) {
122    if ("XML".equalsIgnoreCase(format)) return new XmlParser();
123    if ("JSON".equalsIgnoreCase(format)) return new JsonParser();
124    if ("TURTLE".equalsIgnoreCase(format)) throw new Error("unsupported Format "+format.toString()); // return new TurtleParser();
125    if ("JSONLD".equalsIgnoreCase(format)) throw new Error("unsupported Format "+format.toString()); // return new JsonLdParser();
126    if ("VBAR".equalsIgnoreCase(format)) throw new Error("unsupported Format "+format.toString()); // 
127    if ("TEXT".equalsIgnoreCase(format)) throw new Error("unsupported Format "+format.toString()); // 
128    throw new Error("unsupported Format "+format);
129  }  
130
131  public static FhirFormat determineFormat(byte[] source) throws FHIRException {
132    return determineFormat(source, MAX_SCAN_LENGTH);
133  }
134  
135  public static FhirFormat determineFormat(byte[] source, int scanLength) throws FHIRException {
136    if (scanLength == -1)
137      scanLength = source.length;
138    int lt = firstIndexOf(source, '<', scanLength);
139    int ps = firstIndexOf(source, '{', scanLength);
140    int at = firstIndexOf(source, '@', scanLength);
141    if (at < ps && at < lt) return FhirFormat.TURTLE;
142    if (ps < lt) return FhirFormat.JSON;
143    if (lt < ps) return FhirFormat.XML;
144    throw new FHIRException("unable to determine format");
145  }
146
147  private static int firstIndexOf(byte[] source, char c, int scanLength) {
148    for (int i = 0; i < Math.min(source.length, scanLength); i++) {
149      if (source[i] == c)
150        return i;
151    }
152    return Integer.MAX_VALUE;
153  }
154
155  public static Resource loadFile(String path) throws FileNotFoundException, IOException, FHIRException {
156    byte[] src = TextFile.fileToBytes(path);
157    FhirFormat fmt = determineFormat(src);
158    ParserBase parser = makeParser(fmt);
159    return parser.parse(src);
160  }
161
162
163}