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