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