001package org.hl7.fhir.dstu2016may.formats; 002 003/* 004 Copyright (c) 2011+, HL7, Inc. 005 All rights reserved. 006 007 Redistribution and use in source and binary forms, with or without modification, 008 are permitted provided that the following conditions are met: 009 010 * Redistributions of source code must retain the above copyright notice, this 011 list of conditions and the following disclaimer. 012 * Redistributions in binary form must reproduce the above copyright notice, 013 this list of conditions and the following disclaimer in the documentation 014 and/or other materials provided with the distribution. 015 * Neither the name of HL7 nor the names of its contributors may be used to 016 endorse or promote products derived from this software without specific 017 prior written permission. 018 019 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 020 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 021 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 022 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 023 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 024 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 025 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 026 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 027 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 028 POSSIBILITY OF SUCH DAMAGE. 029 030 */ 031 032 033/* 034Copyright (c) 2011+, HL7, Inc 035All rights reserved. 036 037Redistribution and use in source and binary forms, with or without modification, 038are permitted provided that the following conditions are met: 039 040 * Redistributions of source code must retain the above copyright notice, this 041 list of conditions and the following disclaimer. 042 * Redistributions in binary form must reproduce the above copyright notice, 043 this list of conditions and the following disclaimer in the documentation 044 and/or other materials provided with the distribution. 045 * Neither the name of HL7 nor the names of its contributors may be used to 046 endorse or promote products derived from this software without specific 047 prior written permission. 048 049THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 050ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 051WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 052IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 053INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 054NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 055PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 056WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 057ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 058POSSIBILITY OF SUCH DAMAGE. 059 060*/ 061 062import java.io.IOException; 063import java.io.InputStream; 064import java.io.OutputStream; 065import java.io.OutputStreamWriter; 066import java.math.BigDecimal; 067import java.util.List; 068 069import org.hl7.fhir.dstu2016may.model.DomainResource; 070import org.hl7.fhir.dstu2016may.model.Element; 071import org.hl7.fhir.dstu2016may.model.IdType; 072import org.hl7.fhir.dstu2016may.model.Resource; 073import org.hl7.fhir.dstu2016may.model.StringType; 074import org.hl7.fhir.dstu2016may.model.Type; 075import org.hl7.fhir.exceptions.FHIRFormatError; 076import org.hl7.fhir.instance.model.api.IIdType; 077import org.hl7.fhir.utilities.TextFile; 078import org.hl7.fhir.utilities.Utilities; 079import org.hl7.fhir.utilities.xhtml.XhtmlComposer; 080import org.hl7.fhir.utilities.xhtml.XhtmlNode; 081import org.hl7.fhir.utilities.xhtml.XhtmlParser; 082 083import com.google.gson.JsonArray; 084import com.google.gson.JsonObject; 085import com.google.gson.JsonSyntaxException; 086/** 087 * General parser for JSON content. You instantiate an JsonParser of these, but you 088 * actually use parse or parseGeneral defined on this class 089 * 090 * The two classes are separated to keep generated and manually maintained code apart. 091 */ 092public abstract class JsonParserBase extends ParserBase implements IParser { 093 094 @Override 095 public ParserType getType() { 096 return ParserType.JSON; 097 } 098 099 private static com.google.gson.JsonParser parser = new com.google.gson.JsonParser(); 100 101 // -- in descendent generated code -------------------------------------- 102 103 abstract protected Resource parseResource(JsonObject json) throws IOException, FHIRFormatError; 104 abstract protected Type parseType(JsonObject json, String type) throws IOException, FHIRFormatError; 105 abstract protected Type parseType(String prefix, JsonObject json) throws IOException, FHIRFormatError; 106 abstract protected boolean hasTypeName(JsonObject json, String prefix); 107 abstract protected void composeResource(Resource resource) throws IOException; 108 abstract protected void composeTypeInner(Type type) throws IOException; 109 110 /* -- entry points --------------------------------------------------- */ 111 112 /** 113 * @throws FHIRFormatError 114 * Parse content that is known to be a resource 115 * @throws IOException 116 * @throws 117 */ 118 @Override 119 public Resource parse(InputStream input) throws IOException, FHIRFormatError { 120 JsonObject json = loadJson(input); 121 return parseResource(json); 122 } 123 124 /** 125 * parse xml that is known to be a resource, and that has already been read into a JSON object 126 * @throws IOException 127 * @throws FHIRFormatError 128 */ 129 public Resource parse(JsonObject json) throws FHIRFormatError, IOException { 130 return parseResource(json); 131 } 132 133 @Override 134 public Type parseType(InputStream input, String type) throws IOException, FHIRFormatError { 135 JsonObject json = loadJson(input); 136 return parseType(json, type); 137 } 138 139 /** 140 * Compose a resource to a stream, possibly using pretty presentation for a human reader (used in the spec, for example, but not normally in production) 141 * @throws IOException 142 */ 143 @Override 144 public void compose(OutputStream stream, Resource resource) throws IOException { 145 OutputStreamWriter osw = new OutputStreamWriter(stream, "UTF-8"); 146 if (style == OutputStyle.CANONICAL) 147 json = new JsonCreatorCanonical(osw); 148 else 149 json = new JsonCreatorGson(osw); 150 json.setIndent(style == OutputStyle.PRETTY ? " " : ""); 151 json.beginObject(); 152 composeResource(resource); 153 json.endObject(); 154 json.finish(); 155 osw.flush(); 156 } 157 158 /** 159 * Compose a resource using a pre-existing JsonWriter 160 * @throws IOException 161 */ 162 public void compose(JsonCreator writer, Resource resource) throws IOException { 163 json = writer; 164 composeResource(resource); 165 } 166 167 @Override 168 public void compose(OutputStream stream, Type type, String rootName) throws IOException { 169 OutputStreamWriter osw = new OutputStreamWriter(stream, "UTF-8"); 170 if (style == OutputStyle.CANONICAL) 171 json = new JsonCreatorCanonical(osw); 172 else 173 json = new JsonCreatorGson(osw); 174 json.setIndent(style == OutputStyle.PRETTY ? " " : ""); 175 json.beginObject(); 176 composeTypeInner(type); 177 json.endObject(); 178 json.finish(); 179 osw.flush(); 180 } 181 182 183 184 /* -- json routines --------------------------------------------------- */ 185 186 protected JsonCreator json; 187 private boolean htmlPretty; 188 189 private JsonObject loadJson(InputStream input) throws JsonSyntaxException, IOException { 190 return parser.parse(TextFile.streamToString(input)).getAsJsonObject(); 191 } 192 193// private JsonObject loadJson(String input) { 194// return parser.parse(input).getAsJsonObject(); 195// } 196// 197 protected void parseElementProperties(JsonObject json, Element e) throws IOException, FHIRFormatError { 198 if (json != null && json.has("id")) 199 e.setId(json.get("id").getAsString()); 200 if (!Utilities.noString(e.getId())) 201 idMap.put(e.getId(), e); 202 if (json.has("fhir_comments") && handleComments) { 203 JsonArray array = json.getAsJsonArray("fhir_comments"); 204 for (int i = 0; i < array.size(); i++) { 205 e.getFormatCommentsPre().add(array.get(i).getAsString()); 206 } 207 } 208 } 209 210 protected XhtmlNode parseXhtml(String value) throws IOException, FHIRFormatError { 211 XhtmlParser prsr = new XhtmlParser(); 212 try { 213 return prsr.parse(value, "div").getChildNodes().get(0); 214 } catch (org.hl7.fhir.exceptions.FHIRFormatError e) { 215 throw new FHIRFormatError(e.getMessage(), e); 216 } 217 } 218 219 protected DomainResource parseDomainResource(JsonObject json) throws FHIRFormatError, IOException { 220 return (DomainResource) parseResource(json); 221 } 222 223 protected void writeNull(String name) throws IOException { 224 json.nullValue(); 225 } 226 protected void prop(String name, String value) throws IOException { 227 if (name != null) 228 json.name(name); 229 json.value(value); 230 } 231 232 protected void prop(String name, java.lang.Boolean value) throws IOException { 233 if (name != null) 234 json.name(name); 235 json.value(value); 236 } 237 238 protected void prop(String name, BigDecimal value) throws IOException { 239 if (name != null) 240 json.name(name); 241 json.value(value); 242 } 243 244 protected void prop(String name, java.lang.Integer value) throws IOException { 245 if (name != null) 246 json.name(name); 247 json.value(value); 248 } 249 250 protected void composeXhtml(String name, XhtmlNode html) throws IOException { 251 if (!Utilities.noString(xhtmlMessage)) { 252 prop(name, "<div>!-- "+xhtmlMessage+" --></div>"); 253 } else { 254 XhtmlComposer comp = new XhtmlComposer(true, htmlPretty); 255 prop(name, comp.compose(html)); 256 } 257 } 258 259 protected void open(String name) throws IOException { 260 if (name != null) 261 json.name(name); 262 json.beginObject(); 263 } 264 265 protected void close() throws IOException { 266 json.endObject(); 267 } 268 269 protected void openArray(String name) throws IOException { 270 if (name != null) 271 json.name(name); 272 json.beginArray(); 273 } 274 275 protected void closeArray() throws IOException { 276 json.endArray(); 277 } 278 279 protected void openObject(String name) throws IOException { 280 if (name != null) 281 json.name(name); 282 json.beginObject(); 283 } 284 285 protected void closeObject() throws IOException { 286 json.endObject(); 287 } 288 289// protected void composeBinary(String name, Binary element) { 290// if (element != null) { 291// prop("resourceType", "Binary"); 292// if (element.getXmlId() != null) 293// prop("id", element.getXmlId()); 294// prop("contentType", element.getContentType()); 295// prop("content", toString(element.getContent())); 296// } 297// 298// } 299 300 protected boolean anyHasExtras(List<? extends Element> list) { 301 for (Element e : list) { 302 if (e.hasExtension() || !Utilities.noString(e.getId())) 303 return true; 304 } 305 return false; 306 } 307 308 protected boolean makeComments(Element element) { 309 return handleComments && (style != OutputStyle.CANONICAL) && !(element.getFormatCommentsPre().isEmpty() && element.getFormatCommentsPost().isEmpty()); 310 } 311 312 protected void composeDomainResource(String name, DomainResource e) throws IOException { 313 openObject(name); 314 composeResource(e); 315 close(); 316 317 } 318 319 protected abstract void composeType(String prefix, Type type) throws IOException; 320 321 322 abstract void composeStringCore(String name, StringType value, boolean inArray) throws IOException; 323 324 protected void composeStringCore(String name, IIdType value, boolean inArray) throws IOException { 325 composeStringCore(name, new StringType(value.getValue()), inArray); 326 } 327 328 abstract void composeStringExtras(String name, StringType value, boolean inArray) throws IOException; 329 330 protected void composeStringExtras(String name, IIdType value, boolean inArray) throws IOException { 331 composeStringExtras(name, new StringType(value.getValue()), inArray); 332 } 333 334 protected void parseElementProperties(JsonObject theAsJsonObject, IIdType theReferenceElement) throws FHIRFormatError, IOException { 335 parseElementProperties(theAsJsonObject, (Element)theReferenceElement); 336 } 337 338 protected void parseElementProperties(JsonObject theAsJsonObject, IdType theReferenceElement) throws FHIRFormatError, IOException { 339 parseElementProperties(theAsJsonObject, (Element)theReferenceElement); 340 } 341 342}