001package org.hl7.fhir.r4.formats; 002 003import java.io.FileNotFoundException; 004import java.io.IOException; 005import java.io.InputStream; 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/* 037Copyright (c) 2011+, HL7, Inc 038All rights reserved. 039 040Redistribution and use in source and binary forms, with or without modification, 041are permitted provided that the following conditions are met: 042 043 * Redistributions of source code must retain the above copyright notice, this 044 list of conditions and the following disclaimer. 045 * Redistributions in binary form must reproduce the above copyright notice, 046 this list of conditions and the following disclaimer in the documentation 047 and/or other materials provided with the distribution. 048 * Neither the name of HL7 nor the names of its contributors may be used to 049 endorse or promote products derived from this software without specific 050 prior written permission. 051 052THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 053ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 054WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 055IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 056INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 057NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 058PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 059WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 060ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 061POSSIBILITY OF SUCH DAMAGE. 062 063*/ 064 065import java.math.BigDecimal; 066import java.net.URI; 067 068import org.apache.commons.codec.binary.Base64; 069import org.hl7.fhir.exceptions.FHIRException; 070import org.hl7.fhir.r4.elementmodel.Manager.FhirFormat; 071import org.hl7.fhir.r4.model.Resource; 072import org.hl7.fhir.utilities.TextFile; 073 074public abstract class FormatUtilities { 075 public static final String ID_REGEX = "[A-Za-z0-9\\-\\.]{1,64}"; 076 public static final String FHIR_NS = "http://hl7.org/fhir"; 077 public static final String XHTML_NS = "http://www.w3.org/1999/xhtml"; 078 public static final String NS_XSI = "http://www.w3.org/2001/XMLSchema-instance"; 079 private static final int MAX_SCAN_LENGTH = 1000; // how many characters to scan into content when autodetermining 080 // format 081 082 protected String toString(String value) { 083 return value; 084 } 085 086 protected String toString(int value) { 087 return java.lang.Integer.toString(value); 088 } 089 090 protected String toString(boolean value) { 091 return java.lang.Boolean.toString(value); 092 } 093 094 protected String toString(BigDecimal value) { 095 return value.toString(); 096 } 097 098 protected String toString(URI value) { 099 return value.toString(); 100 } 101 102 public static String toString(byte[] value) { 103 byte[] encodeBase64 = Base64.encodeBase64(value); 104 return new String(encodeBase64); 105 } 106 107 public static boolean isValidId(String tail) { 108 return tail.matches(ID_REGEX); 109 } 110 111 public static String makeId(String candidate) { 112 StringBuilder b = new StringBuilder(); 113 for (char c : candidate.toCharArray()) 114 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '.' || c == '-') 115 b.append(c); 116 return b.toString(); 117 } 118 119 public static ParserBase makeParser(FhirFormat format) { 120 switch (format) { 121 case XML: 122 return new XmlParser(); 123 case JSON: 124 return new JsonParser(); 125 case TURTLE: 126 throw new Error("unsupported Format " + format.toString()); // return new TurtleParser(); 127 case VBAR: 128 throw new Error("unsupported Format " + format.toString()); // 129 case TEXT: 130 throw new Error("unsupported Format " + format.toString()); // 131 } 132 throw new Error("unsupported Format " + format.toString()); 133 } 134 135 public static ParserBase makeParser(String format) { 136 if ("XML".equalsIgnoreCase(format)) 137 return new XmlParser(); 138 if ("JSON".equalsIgnoreCase(format)) 139 return new JsonParser(); 140 if ("TURTLE".equalsIgnoreCase(format)) 141 throw new Error("unsupported Format " + format.toString()); // return new TurtleParser(); 142 if ("JSONLD".equalsIgnoreCase(format)) 143 throw new Error("unsupported Format " + format.toString()); // return new JsonLdParser(); 144 if ("VBAR".equalsIgnoreCase(format)) 145 throw new Error("unsupported Format " + format.toString()); // 146 if ("TEXT".equalsIgnoreCase(format)) 147 throw new Error("unsupported Format " + format.toString()); // 148 throw new Error("unsupported Format " + format); 149 } 150 151 public static FhirFormat determineFormat(byte[] source) throws FHIRException { 152 return determineFormat(source, MAX_SCAN_LENGTH); 153 } 154 155 public static FhirFormat determineFormat(byte[] source, int scanLength) throws FHIRException { 156 if (scanLength == -1) 157 scanLength = source.length; 158 int lt = firstIndexOf(source, '<', scanLength); 159 int ps = firstIndexOf(source, '{', scanLength); 160 int at = firstIndexOf(source, '@', scanLength); 161 if (at < ps && at < lt) 162 return FhirFormat.TURTLE; 163 if (ps < lt) 164 return FhirFormat.JSON; 165 if (lt < ps) 166 return FhirFormat.XML; 167 throw new FHIRException("unable to determine format"); 168 } 169 170 private static int firstIndexOf(byte[] source, char c, int scanLength) { 171 for (int i = 0; i < Math.min(source.length, scanLength); i++) { 172 if (source[i] == c) 173 return i; 174 } 175 return Integer.MAX_VALUE; 176 } 177 178 public static Resource loadFile(String path) throws FileNotFoundException, IOException, FHIRException { 179 byte[] src = TextFile.fileToBytes(path); 180 FhirFormat fmt = determineFormat(src); 181 ParserBase parser = makeParser(fmt); 182 return parser.parse(src); 183 } 184 185 public static Resource loadFile(InputStream source) throws FileNotFoundException, IOException, FHIRException { 186 byte[] src = TextFile.streamToBytes(source); 187 FhirFormat fmt = determineFormat(src); 188 ParserBase parser = makeParser(fmt); 189 return parser.parse(src); 190 } 191 192 public static Resource loadFileTight(String path) throws FileNotFoundException, IOException, FHIRException { 193 byte[] src = TextFile.fileToBytes(path); 194 FhirFormat fmt = determineFormat(src); 195 ParserBase parser = makeParser(fmt); 196 parser.setAllowUnknownContent(false); 197 return parser.parse(src); 198 } 199 200 public static Resource loadFileTight(InputStream source) throws FileNotFoundException, IOException, FHIRException { 201 byte[] src = TextFile.streamToBytes(source); 202 FhirFormat fmt = determineFormat(src); 203 ParserBase parser = makeParser(fmt); 204 parser.setAllowUnknownContent(false); 205 return parser.parse(src); 206 } 207 208}