001package org.hl7.fhir.r4.utils; 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.OutputStreamWriter; 033import java.util.ArrayList; 034import java.util.List; 035 036import org.hl7.fhir.exceptions.FHIRException; 037import org.hl7.fhir.r4.context.IWorkerContext; 038import org.hl7.fhir.r4.model.ElementDefinition; 039import org.hl7.fhir.r4.model.StructureDefinition; 040import org.hl7.fhir.r4.model.StructureDefinition.StructureDefinitionKind; 041import org.hl7.fhir.r4.model.StructureDefinition.TypeDerivationRule; 042import org.hl7.fhir.utilities.Utilities; 043 044public class ProtoBufGenerator { 045 046 private IWorkerContext context; 047 private StructureDefinition definition; 048 private OutputStreamWriter destination; 049 private int cursor; 050 private Message message; 051 052 private class Field { 053 private String name; 054 private boolean required; 055 private boolean repeating; 056 private String type; 057 } 058 059 private class Message { 060 private String name; 061 private List<Field> fields = new ArrayList<Field>(); 062 private List<Message> messages = new ArrayList<Message>(); 063 064 public Message(String name) { 065 super(); 066 this.name = name; 067 } 068 069 } 070 071 public ProtoBufGenerator(IWorkerContext context) { 072 super(); 073 this.context = context; 074 } 075 076 public ProtoBufGenerator(IWorkerContext context, StructureDefinition definition, OutputStreamWriter destination) { 077 super(); 078 this.context = context; 079 this.definition = definition; 080 this.destination = destination; 081 } 082 083 public IWorkerContext getContext() { 084 return context; 085 } 086 087 public StructureDefinition getDefinition() { 088 return definition; 089 } 090 091 public void setDefinition(StructureDefinition definition) { 092 this.definition = definition; 093 } 094 095 public OutputStreamWriter getDestination() { 096 return destination; 097 } 098 099 public void setDestination(OutputStreamWriter destination) { 100 this.destination = destination; 101 } 102 103 public void build() throws FHIRException { 104 if (definition == null) 105 throw new FHIRException("A definition must be provided"); 106 if (destination == null) 107 throw new FHIRException("A destination must be provided"); 108 109 if (definition.getDerivation() == TypeDerivationRule.CONSTRAINT) 110 throw new FHIRException("derivation = constraint is not supported yet"); 111 112 message = new Message(definition.getSnapshot().getElement().get(0).getPath()); 113 cursor = 1; 114 while (cursor < definition.getSnapshot().getElement().size()) { 115 ElementDefinition ed = definition.getSnapshot().getElement().get(0); 116 Field fld = new Field(); 117 fld.name = tail(ed.getPath()); 118 fld.required = (ed.getMin() == 1); 119 fld.repeating = (!ed.getMax().equals("1")); 120 message.fields.add(fld); 121 if (ed.getType().size() != 1) 122 fld.type = "Unknown"; 123 else { 124 StructureDefinition td = context.fetchTypeDefinition(ed.getTypeFirstRep().getWorkingCode()); 125 if (td == null) 126 fld.type = "Unresolved"; 127 else if (td.getKind() == StructureDefinitionKind.PRIMITIVETYPE) { 128 fld.type = protoTypeForFhirType(ed.getTypeFirstRep().getWorkingCode()); 129 fld = new Field(); 130 fld.name = tail(ed.getPath()) + "Extra"; 131 fld.repeating = (!ed.getMax().equals("1")); 132 fld.type = "Primitive"; 133 message.fields.add(fld); 134 } else 135 fld.type = ed.getTypeFirstRep().getWorkingCode(); 136 } 137 } 138 } 139 140 private String protoTypeForFhirType(String code) { 141 if (Utilities.existsInList(code, "integer", "unsignedInt", "positiveInt")) 142 return "int23"; 143 else if (code.equals("boolean")) 144 return "bool"; 145 else 146 return "string"; 147 } 148 149 private String tail(String path) { 150 return path.substring(path.lastIndexOf(".") + 1); 151 } 152 153}