001package org.hl7.fhir.convertors.misc;
002
003import java.io.FileInputStream;
004import java.io.FileOutputStream;
005
006import org.hl7.fhir.r4.formats.IParser.OutputStyle;
007import org.hl7.fhir.r4.model.BooleanType;
008import org.hl7.fhir.r4.model.CodeSystem;
009import org.hl7.fhir.r4.model.CodeSystem.ConceptDefinitionComponent;
010import org.hl7.fhir.r4.model.CodeSystem.PropertyType;
011import org.hl7.fhir.r4.model.StringType;
012import org.hl7.fhir.r4.terminologies.CodeSystemUtilities;
013import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
014import org.hl7.fhir.utilities.TextFile;
015import org.hl7.fhir.utilities.Utilities;
016import org.hl7.fhir.utilities.filesystem.ManagedFileAccess;
017import org.hl7.fhir.utilities.json.model.JsonObject;
018import org.hl7.fhir.utilities.json.parser.JsonParser;
019
020public class SPDXImporter {
021
022  private StringBuilder b;
023
024
025  public static void main(String[] args) throws Exception {
026    new SPDXImporter().generate(args);
027  }
028  
029  public void generate(String[] args) throws Exception {
030    JsonObject json = JsonParser.parseObjectFromUrl("https://raw.githubusercontent.com/spdx/license-list-data/main/json/licenses.json");
031    CodeSystem cs = (CodeSystem) new org.hl7.fhir.r4.formats.JsonParser().parse(ManagedFileAccess.inStream(args[0]));
032    cs.getConcept().clear();
033    cs.getProperty().clear();
034    cs.addProperty().setCode("reference").setType(PropertyType.STRING);
035    cs.addProperty().setCode("isOsiApproved").setType(PropertyType.BOOLEAN);
036    cs.addProperty().setCode("status").setType(PropertyType.CODE).setUri("http://hl7.org/fhir/concept-properties#status");
037    cs.addProperty().setCode("seeAlso").setType(PropertyType.STRING);
038    cs.setVersion(json.asString("licenseListVersion"));
039    ConceptDefinitionComponent cc = cs.addConcept();
040    cc.setCode("not-open-source");
041    cc.setDisplay("Not open source");
042    cc.setDefinition("Not an open source license.");
043    for (JsonObject l : json.getJsonObjects("licenses")) {
044      cc = cs.addConcept();
045      cc.setCode(l.asString("licenseId"));
046      cc.setDisplay(l.asString("name"));
047      cc.setDefinition(l.asString("name"));
048      if (l.has("reference")) {
049        cc.addProperty().setCode("reference").setValue(new StringType(l.asString("reference")));
050      }
051      if (l.has("isOsiApproved")) {
052        cc.addProperty().setCode("isOsiApproved").setValue(new BooleanType(l.asBoolean("isOsiApproved")));
053      }
054      if (l.asBoolean("isDeprecatedLicenseId")) {
055        cc.addProperty().setCode("status").setValue(new BooleanType(l.asBoolean("deprecated")));
056      }
057      for (String s : l.getStrings("seeAlso")) {        
058        cc.addProperty().setCode("seeAlso").setValue(new StringType(s));
059      }
060    }
061    CodeSystemUtilities.sortAllCodes(cs);
062    new org.hl7.fhir.r4.formats.JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(ManagedFileAccess.outStream(args[1]), cs);
063    b = new StringBuilder();
064    generateEnum("SPDXLicense", cs);
065    TextFile.stringToFile(b.toString(), Utilities.changeFileExt(args[1], ".java"));
066  }
067
068  private void write(String s) {
069    b.append(s);
070  }
071  
072  private boolean allPlusMinus(String cc) {
073    for (char c : cc.toCharArray())
074      if (!(c == '-' || c == '+'))
075        return false;
076    return true;
077  }
078  
079  protected String makeConst(String cc) {
080    if (cc.equals("*"))
081      cc = "ASTERISK";
082    if (Utilities.isOid(cc) && Utilities.charCount(cc, '.') > 2)
083      cc = "OID_"+cc;
084    if (cc.equals("%"))
085      cc = "pct";
086    else if (cc.equals("<"))
087      cc = "less_Than";
088    else if (cc.equals("<="))
089      cc = "less_Or_Equal";
090    else if (cc.equals(">"))
091      cc = "greater_Than";
092    else if (cc.equals(">="))
093      cc = "greater_Or_Equal";
094    else if (cc.equals("="))
095      cc = "equal";
096    else if (cc.equals("!="))
097      cc = "not_equal";
098    else if (allPlusMinus(cc))
099      cc = cc.replace("-", "Minus").replace("+", "Plus");
100    else
101      cc = cc.replace("-", "_").replace("+", "PLUS");
102    cc = cc.replace("(", "_").replace(")", "_");
103    cc = cc.replace("{", "_").replace("}", "_");
104    cc = cc.replace("<", "_").replace(">", "_");
105    cc = cc.replace(".", "_").replace("/", "_");
106    cc = cc.replace(":", "_");
107    cc = cc.replace("%", "pct");
108    if (Utilities.isInteger(cc.substring(0, 1)))
109      cc = "_"+cc;
110    cc = cc.toUpperCase();
111    return cc;
112  }
113
114  
115  private void generateEnum(String name, CodeSystem cs) throws Exception {
116    String url = cs.getUrl();
117    CommaSeparatedStringBuilder el = new CommaSeparatedStringBuilder();
118
119    write("    public enum "+name+" {\r\n");
120    int l = cs.getConcept().size();
121    int i = 0;
122    for (ConceptDefinitionComponent c : cs.getConcept()) {
123        i++;
124        String cc = Utilities.camelCase(c.getCode());
125        cc = makeConst(cc);
126        el.append(cc);
127
128        write("        /**\r\n");
129        write("         * "+c.getDefinition()+"\r\n");
130        write("         */\r\n");      
131        write("        "+cc.toUpperCase()+", \r\n");
132      }
133    write("        /**\r\n");
134    write("         * added to help the parsers\r\n");
135    write("         */\r\n");      
136    write("        NULL;\r\n");
137    el.append("NULL");
138
139
140    write("        public static "+name+" fromCode(String codeString) throws FHIRException {\r\n");
141    write("            if (codeString == null || \"\".equals(codeString))\r\n");
142    write("                return null;\r\n");
143    for (ConceptDefinitionComponent c : cs.getConcept()) {
144        String cc = Utilities.camelCase(c.getCode());
145        cc = makeConst(cc);
146        write("        if (\""+c.getCode()+"\".equals(codeString))\r\n");
147        write("          return "+cc+";\r\n");
148      }
149    write("        throw new FHIRException(\"Unknown "+name+" code '\"+codeString+\"'\");\r\n");
150    write("        }\r\n"); 
151
152    write("        public static boolean isValidCode(String codeString) {\r\n");
153    write("            if (codeString == null || \"\".equals(codeString))\r\n");
154    write("                return false;\r\n");
155    write("          return Utilities.existsInList(codeString");
156    for (ConceptDefinitionComponent c : cs.getConcept()) {
157        write(", \""+c.getCode()+"\"");
158    }
159    write(");\r\n");
160    write("        }\r\n"); 
161
162    write("        public String toCode() {\r\n");
163    write("          switch (this) {\r\n");
164    for (ConceptDefinitionComponent c : cs.getConcept()) {
165        String cc = Utilities.camelCase(c.getCode());
166        cc = makeConst(cc);
167        write("            case "+cc+": return \""+c.getCode()+"\";\r\n");
168      }
169    write("            case NULL: return null;\r\n");
170    write("            default: return \"?\";\r\n");
171    write("          }\r\n"); 
172    write("        }\r\n"); 
173
174    write("        public String getSystem() {\r\n");
175    write("          switch (this) {\r\n");
176    for (ConceptDefinitionComponent c : cs.getConcept()) {
177      String cc = Utilities.camelCase(c.getCode());
178      cc = makeConst(cc);
179      write("            case "+cc+": return \""+cs.getUrl()+"\";\r\n");
180    }
181    write("            case NULL: return null;\r\n");
182    write("            default: return \"?\";\r\n");
183    write("          }\r\n"); 
184    write("        }\r\n"); 
185
186    write("        public String getDefinition() {\r\n");
187    write("          switch (this) {\r\n");
188    for (ConceptDefinitionComponent c : cs.getConcept()) {
189        String cc = Utilities.camelCase(c.getCode());
190        cc = makeConst(cc);
191        write("            case "+cc+": return \""+Utilities.escapeJava(c.getDefinition())+"\";\r\n");
192      }
193    write("            case NULL: return null;\r\n");
194    write("            default: return \"?\";\r\n");
195    write("          }\r\n"); 
196    write("        }\r\n"); 
197
198    write("        public String getDisplay() {\r\n");
199    write("          switch (this) {\r\n");
200    for (ConceptDefinitionComponent c : cs.getConcept()) {
201        String cc = Utilities.camelCase(c.getCode());
202        cc = makeConst(cc);
203        write("            case "+cc+": return \""+Utilities.escapeJava(Utilities.noString(c.getDisplay()) ? c.getCode() : c.getDisplay())+"\";\r\n");
204      }
205    write("            case NULL: return null;\r\n");
206    write("            default: return \"?\";\r\n");
207    write("          }\r\n"); 
208    write("        }\r\n"); 
209
210    write("    }\r\n");
211    write("\r\n");
212
213    
214    write("  public static class "+name+"EnumFactory implements EnumFactory<"+name+"> {\r\n");
215    write("    public "+name+" fromCode(String codeString) throws IllegalArgumentException {\r\n");
216    
217    write("      if (codeString == null || \"\".equals(codeString))\r\n");
218    write("            if (codeString == null || \"\".equals(codeString))\r\n");
219    write("                return null;\r\n");
220    for (ConceptDefinitionComponent c : cs.getConcept()) {
221        String cc = Utilities.camelCase(c.getCode());
222        cc = makeConst(cc);
223        write("        if (\""+c.getCode()+"\".equals(codeString))\r\n");
224        write("          return "+name+"."+cc+";\r\n");
225      }
226    write("        throw new IllegalArgumentException(\"Unknown "+name+" code '\"+codeString+\"'\");\r\n");
227    write("        }\r\n"); 
228    write("\r\n");
229    write("        public Enumeration<"+name+"> fromType(PrimitiveType<?> code) throws FHIRException {\r\n");
230    write("          if (code == null)\r\n");
231    write("            return null;\r\n");
232    write("          if (code.isEmpty())\r\n");
233    write("            return new Enumeration<"+name+">(this, "+name+".NULL, code);\r\n");
234    write("          String codeString = ((PrimitiveType) code).asStringValue();\r\n");
235    write("          if (codeString == null || \"\".equals(codeString))\r\n");
236    write("            return new Enumeration<"+name+">(this, "+name+".NULL, code);\r\n");
237    for (ConceptDefinitionComponent c : cs.getConcept()) {
238      String cc = Utilities.camelCase(c.getCode());
239      cc = makeConst(cc);
240      write("        if (\""+c.getCode()+"\".equals(codeString))\r\n");
241      write("          return new Enumeration<"+name+">(this, "+name+"."+cc+", code);\r\n");
242    }   
243    write("        throw new FHIRException(\"Unknown "+name+" code '\"+codeString+\"'\");\r\n");
244    write("        }\r\n"); 
245    write("    public String toCode("+name+" code) {\r\n");
246    for (ConceptDefinitionComponent c : cs.getConcept()) {
247        String cc = Utilities.camelCase(c.getCode());
248        cc = makeConst(cc);
249        write("      if (code == "+name+"."+cc+")\r\n        return \""+c.getCode()+"\";\r\n");
250    }
251    write("      return \"?\";\r\n"); 
252    write("      }\r\n");
253    
254    write("    public String toSystem("+name+" code) {\r\n");
255    write("      return code.getSystem();\r\n");
256    write("      }\r\n"); 
257
258    write("    }\r\n"); 
259    write("\r\n");
260  }
261
262}
263