
001package org.hl7.fhir.r5.elementmodel; 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 032import java.io.ByteArrayInputStream; 033import java.io.ByteArrayOutputStream; 034import java.io.IOException; 035import java.util.ArrayList; 036import java.util.List; 037 038import org.hl7.fhir.exceptions.FHIRException; 039import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; 040import org.hl7.fhir.r5.conformance.profile.ProfileUtilities.SourcedChildDefinitions; 041import org.hl7.fhir.r5.context.IWorkerContext; 042import org.hl7.fhir.r5.formats.IParser.OutputStyle; 043import org.hl7.fhir.r5.model.Base; 044import org.hl7.fhir.r5.model.CodeableConcept; 045import org.hl7.fhir.r5.model.Coding; 046import org.hl7.fhir.r5.model.DataType; 047import org.hl7.fhir.r5.model.ElementDefinition; 048import org.hl7.fhir.r5.model.Factory; 049import org.hl7.fhir.r5.model.Identifier; 050import org.hl7.fhir.r5.model.PrimitiveType; 051import org.hl7.fhir.r5.model.Quantity; 052import org.hl7.fhir.r5.model.Reference; 053import org.hl7.fhir.r5.model.Resource; 054import org.hl7.fhir.r5.model.StructureDefinition; 055import org.hl7.fhir.r5.model.Enumerations.QuantityComparator; 056import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind; 057import org.hl7.fhir.utilities.MarkedToMoveToAdjunctPackage; 058 059 060@MarkedToMoveToAdjunctPackage 061public class ObjectConverter { 062 063 private IWorkerContext context; 064 private ProfileUtilities profileUtilities; 065 066 public ObjectConverter(IWorkerContext context) { 067 this.context = context; 068 profileUtilities = new ProfileUtilities(context, null, null); 069 } 070 071 public Element convert(Resource ig) throws IOException, FHIRException { 072 if (ig == null) 073 return null; 074 ByteArrayOutputStream bs = new ByteArrayOutputStream(); 075 org.hl7.fhir.r5.formats.JsonParser jp = new org.hl7.fhir.r5.formats.JsonParser(); 076 jp.compose(bs, ig); 077 ByteArrayInputStream bi = new ByteArrayInputStream(bs.toByteArray()); 078 List<ValidatedFragment> list = new JsonParser(context).parse(bi); 079 if (list.size() != 1) { 080 throw new FHIRException("Unable to convert because the source contains multiple resources"); 081 } 082 return list.get(0).getElement(); 083 } 084 085 public Element convert(Property property, DataType type) throws FHIRException { 086 return convertElement(property, type); 087 } 088 089 private Element convertElement(Property property, Base base) throws FHIRException { 090 if (base == null) 091 return null; 092 String tn = base.fhirType(); 093 StructureDefinition sd = context.fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(tn, null)); 094 if (sd == null) 095 throw new FHIRException("Unable to find definition for type "+tn); 096 Element res = new Element(property.getName(), property); 097 if (sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE) 098 res.setValue(((PrimitiveType) base).asStringValue()); 099 100 SourcedChildDefinitions children = profileUtilities.getChildMap(sd, sd.getSnapshot().getElementFirstRep(), true); 101 for (ElementDefinition child : children.getList()) { 102 String n = tail(child.getPath()); 103 if (sd.getKind() != StructureDefinitionKind.PRIMITIVETYPE || !"value".equals(n)) { 104 Base[] values = base.getProperty(n.hashCode(), n, false); 105 if (values != null) 106 for (Base value : values) { 107 res.getChildren().add(convertElement(new Property(context, child, sd), value)); 108 } 109 } 110 } 111 return res; 112 } 113 114 private String tail(String path) { 115 if (path.contains(".")) 116 return path.substring(path.lastIndexOf('.')+1); 117 else 118 return path; 119 } 120 121 public DataType convertToType(Element element) throws FHIRException { 122 DataType b = new Factory().create(element.fhirType()); 123 if (b instanceof PrimitiveType) { 124 ((PrimitiveType) b).setValueAsString(element.primitiveValue()); 125 } else { 126 for (Element child : element.getChildren()) { 127 b.setProperty(child.getName(), convertToType(child)); 128 } 129 } 130 return b; 131 } 132 133 public Resource convert(Element element) throws FHIRException { 134 ByteArrayOutputStream bo = new ByteArrayOutputStream(); 135 try { 136 new JsonParser(context).compose(element, bo, OutputStyle.NORMAL, null); 137 return new org.hl7.fhir.r5.formats.JsonParser().parse(bo.toByteArray()); 138 } catch (IOException e) { 139 // won't happen 140 throw new FHIRException(e); 141 } 142 143 } 144 145 public static CodeableConcept readAsCodeableConcept(Element element) { 146 if (element == null) { 147 return null; 148 } 149 CodeableConcept cc = new CodeableConcept(); 150 List<Element> list = new ArrayList<Element>(); 151 element.getNamedChildren("coding", list); 152 for (Element item : list) 153 cc.addCoding(readAsCoding(item)); 154 cc.setText(element.getNamedChildValue("text")); 155 return cc; 156 } 157 158 public static Coding readAsCoding(Element item) { 159 Coding c = new Coding(); 160 c.setSystem(item.getNamedChildValue("system")); 161 c.setVersion(item.getNamedChildValue("version")); 162 c.setCode(item.getNamedChildValue("code")); 163 c.setDisplay(item.getNamedChildValue("display")); 164 return c; 165 } 166 167 public static Quantity readAsQuantity(Element item) { 168 // Check the type of the item before trying to read it as a Quantity 169 if (item == null || !item.fhirType().equals("Quantity")) { 170 return null; 171 } 172 Quantity q = new Quantity(); 173 174 var value = item.getNamedChildValue("value"); 175 if (value != null) { 176 q.setValue(new java.math.BigDecimal(value)); 177 } 178 var comparator = item.getNamedChildValue("comparator"); 179 if (comparator != null) { 180 if (QuantityComparator.isValidCode(comparator)) 181 { 182 q.setComparator(QuantityComparator.fromCode(comparator)); 183 } else { 184 // should we throw an exception here? 185 // throw new FHIRException("Invalid comparator value: " + comparator); 186 } 187 } 188 189 q.setSystem(item.getNamedChildValue("system")); 190 q.setCode(item.getNamedChildValue("code")); 191 q.setUnit(item.getNamedChildValue("unit")); 192 return q; 193 } 194 195 public static Identifier readAsIdentifier(Element item) { 196 Identifier r = new Identifier(); 197 r.setSystem(item.getNamedChildValue("system")); 198 r.setValue(item.getNamedChildValue("value")); 199 return r; 200 } 201 202 public static Reference readAsReference(Element item) { 203 Reference r = new Reference(); 204 r.setDisplay(item.getNamedChildValue("display")); 205 r.setReference(item.getNamedChildValue("reference")); 206 r.setType(item.getNamedChildValue("type")); 207 if (!r.hasType()) { 208 Element ext = item.getExtension("http://hl7.org/fhir/4.0/StructureDefinition/extension-Reference.type"); 209 if (ext != null) { 210 r.setType(ext.getChildValue("valueUri")); 211 } 212 } 213 List<Element> identifier = item.getChildrenByName("identifier"); 214 if (identifier.isEmpty() == false) { 215 r.setIdentifier(readAsIdentifier(identifier.get(0))); 216 } 217 return r; 218 } 219 220}