001package org.hl7.fhir.r4.utils; 002 003import java.io.OutputStreamWriter; 004import java.util.ArrayList; 005import java.util.List; 006 007import org.hl7.fhir.exceptions.FHIRException; 008import org.hl7.fhir.r4.context.IWorkerContext; 009import org.hl7.fhir.r4.model.ElementDefinition; 010import org.hl7.fhir.r4.model.StructureDefinition; 011import org.hl7.fhir.r4.model.StructureDefinition.StructureDefinitionKind; 012import org.hl7.fhir.r4.model.StructureDefinition.TypeDerivationRule; 013import org.hl7.fhir.utilities.Utilities; 014 015public class ProtoBufGenerator { 016 017 private IWorkerContext context; 018 private StructureDefinition definition; 019 private OutputStreamWriter destination; 020 private int cursor; 021 private Message message; 022 023 private class Field { 024 private String name; 025 private boolean required; 026 private boolean repeating; 027 private String type; 028 } 029 030 private class Message { 031 private String name; 032 private List<Field> fields = new ArrayList<Field>(); 033 private List<Message> messages = new ArrayList<Message>(); 034 public Message(String name) { 035 super(); 036 this.name = name; 037 } 038 039 040 } 041 042 public ProtoBufGenerator(IWorkerContext context) { 043 super(); 044 this.context = context; 045 } 046 047 public ProtoBufGenerator(IWorkerContext context, StructureDefinition definition, OutputStreamWriter destination) { 048 super(); 049 this.context = context; 050 this.definition = definition; 051 this.destination = destination; 052 } 053 054 public IWorkerContext getContext() { 055 return context; 056 } 057 058 public StructureDefinition getDefinition() { 059 return definition; 060 } 061 062 public void setDefinition(StructureDefinition definition) { 063 this.definition = definition; 064 } 065 066 public OutputStreamWriter getDestination() { 067 return destination; 068 } 069 070 public void setDestination(OutputStreamWriter destination) { 071 this.destination = destination; 072 } 073 074 075 public void build() throws FHIRException { 076 if (definition == null) 077 throw new FHIRException("A definition must be provided"); 078 if (destination == null) 079 throw new FHIRException("A destination must be provided"); 080 081 if (definition.getDerivation() == TypeDerivationRule.CONSTRAINT) 082 throw new FHIRException("derivation = constraint is not supported yet"); 083 084 message = new Message(definition.getSnapshot().getElement().get(0).getPath()); 085 cursor = 1; 086 while (cursor < definition.getSnapshot().getElement().size()) { 087 ElementDefinition ed = definition.getSnapshot().getElement().get(0); 088 Field fld = new Field(); 089 fld.name = tail(ed.getPath()); 090 fld.required = (ed.getMin() == 1); 091 fld.repeating = (!ed.getMax().equals("1")); 092 message.fields.add(fld); 093 if (ed.getType().size() != 1) 094 fld.type = "Unknown"; 095 else { 096 StructureDefinition td = context.fetchTypeDefinition(ed.getTypeFirstRep().getCode()); 097 if (td == null) 098 fld.type = "Unresolved"; 099 else if (td.getKind() == StructureDefinitionKind.PRIMITIVETYPE) { 100 fld.type = protoTypeForFhirType(ed.getTypeFirstRep().getCode()); 101 fld = new Field(); 102 fld.name = tail(ed.getPath())+"Extra"; 103 fld.repeating = (!ed.getMax().equals("1")); 104 fld.type = "Primitive"; 105 message.fields.add(fld); 106 } else 107 fld.type = ed.getTypeFirstRep().getCode(); 108 } 109 } 110 } 111 112 private String protoTypeForFhirType(String code) { 113 if (Utilities.existsInList(code, "integer", "unsignedInt", "positiveInt")) 114 return "int23"; 115 else if (code.equals("boolean")) 116 return "bool"; 117 else 118 return "string"; 119 } 120 121 private String tail(String path) { 122 return path.substring(path.lastIndexOf(".")+1); 123 } 124 125 126}