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}