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