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}