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