001package org.hl7.fhir.utilities.npm; 002 003import java.io.File; 004import java.io.IOException; 005import java.text.ParseException; 006import java.time.Instant; 007import java.util.ArrayList; 008import java.util.List; 009 010import org.hl7.fhir.utilities.FhirPublication; 011import org.hl7.fhir.utilities.TextFile; 012import org.hl7.fhir.utilities.Utilities; 013import org.hl7.fhir.utilities.json.JsonException; 014import org.hl7.fhir.utilities.json.model.JsonArray; 015import org.hl7.fhir.utilities.json.model.JsonObject; 016import org.hl7.fhir.utilities.json.parser.JsonParser; 017import org.hl7.fhir.utilities.npm.PackageList.PackageListEntry; 018 019public class PackageList { 020 021 public static class PackageListEntry { 022 private JsonObject json; 023 024 private PackageListEntry(JsonObject json) { 025 super(); 026 this.json = json; 027 } 028 029 public String version() { 030 return json.asString("version"); 031 } 032 033 public String path() { 034 return json.asString("path"); 035 } 036 037 public boolean current() { 038 return json.has("current") && json.asBoolean("current"); 039 } 040 041 public boolean cibuild() { 042 return "ci-build".equals(json.asString("status")); 043 } 044 045 public String sequence() { 046 return json.asString("sequence"); 047 } 048 049 public String fhirVersion() { 050 if (json.has("fhir-version")) // legacy 051 return json.asString("fhir-version"); 052 return json.asString("fhirversion"); 053 } 054 055 public String status() { 056 return json.asString("status"); 057 } 058 059 public String desc() { 060 return json.asString("desc"); 061 } 062 063 public String date() { 064 return json.asString("date"); 065 } 066 067 public void setDate(String date) { 068 json.set("date", date); 069 } 070 071 public boolean isPartofMainSpec() { 072 return Utilities.startsWithInList(path(), "http://hl7.org/fhir/DSTU2", "http://hl7.org/fhir/2015Sep", "http://hl7.org/fhir/2015May"); 073 } 074 075 /** 076 * For a variety of reasons in the past, the path is not always under the canonical 077 * this method determines the path *if it exists* 078 * 079 * @param root 080 * @param v 081 * @throws IOException 082 */ 083 public String determineLocalPath(String url, String root) throws IOException { 084 if (!isPartofMainSpec() && path().startsWith(url+"/")) { 085 String tail = path().substring(url.length()+1); 086 return Utilities.path(root, tail); 087 } else { 088 return null; 089 } 090 } 091 092 public void setCurrent(boolean b) { 093 if (b) { 094 json.set("current", true); 095 } else { 096 if (json.has("current")) { 097 json.remove("current"); 098 } 099 } 100 } 101 102 public void init(String version, String path, String status, String sequence, FhirPublication fhirVersion) { 103 json.set("version", version); 104 json.set("path", path); 105 json.set("status", status); 106 json.set("sequence", sequence); 107 if (fhirVersion != null) { 108 json.set("fhirversion", fhirVersion.toCode()); 109 } 110 } 111 112 public void describe(String desc, String descMD, String changes) { 113 if (!Utilities.noString(desc)) { 114 json.set("desc", desc); 115 } 116 if (!Utilities.noString(descMD)) { 117 json.set("descmd", descMD); 118 } 119 if (!Utilities.noString(changes)) { 120 json.set("changes", changes); 121 } 122 } 123 124 public JsonObject json() { 125 return json; 126 } 127 128 public Instant instant() throws ParseException { 129 return json.asInstant("date"); 130 } 131 132 /** 133 * only used for a technical correction. tcPath is the name of archive file (web reference) containing the content before correction 134 * 135 * @param asString 136 * @param webpath 137 * @param asString2 138 * @param asString3 139 * @param fhirVersion 140 * @param tcName 141 */ 142 public void update(String version, String path, String status, String sequence, FhirPublication fhirVersion, String tcPath, String date) { 143 JsonObject tc = new JsonObject(); 144 json.forceArray("corrections").add(tc); 145 tc.set("version", json.asString("version")); 146 tc.set("path", tcPath); 147 tc.set("date", date); 148 149 json.set("version", version); 150 json.set("path", path); 151 json.set("status", status); 152 json.set("sequence", sequence); 153 if (fhirVersion != null) { 154 json.set("fhirversion", fhirVersion.toCode()); 155 } 156 setDate(date); 157 } 158 } 159 160 private String source; 161 private JsonObject json; 162 private List<PackageListEntry> list = new ArrayList<>(); 163 private List<PackageListEntry> versions = new ArrayList<>(); 164 private PackageListEntry cibuild; 165 166 public PackageList() { 167 super(); 168 json = new JsonObject(); 169 json.add("list", new JsonArray()); 170 } 171 172 public PackageList(JsonObject json) { 173 this.json = json; 174 for (JsonObject o : json.getJsonObjects("list")) { 175 PackageListEntry e = new PackageListEntry(o); 176 list.add(e); 177 if ("current".equals(o.asString("version"))) { 178 cibuild = e; 179 } else { 180 versions.add(e); 181 } 182 } 183 } 184 185 public static PackageList fromFile(File f) throws JsonException, IOException { 186 return new PackageList(JsonParser.parseObject(f)).setSource(f.getAbsolutePath()); 187 } 188 189 public PackageList setSource(String src) { 190 this.source = src; 191 return this; 192 } 193 194 public static PackageList fromFile(String f) throws JsonException, IOException { 195 return new PackageList(JsonParser.parseObjectFromFile(f)).setSource(f); 196 } 197 198 public static PackageList fromContent(byte[] cnt) throws JsonException, IOException { 199 return new PackageList(JsonParser.parseObject(cnt)).setSource("unknown"); 200 } 201 202 public static PackageList fromUrl(String url) throws JsonException, IOException { 203 return new PackageList(JsonParser.parseObjectFromUrl(url)).setSource(url); 204 } 205 206 public String source() { 207 return source; 208 } 209 210 public String canonical() { 211 return json.asString("canonical"); 212 } 213 214 public String pid() { 215 return json.asString("package-id"); 216 } 217 218 public boolean hasPid() { 219 return json.has("package-id"); 220 } 221 222 public String category() { 223 return json.asString("category"); 224 } 225 226 public List<PackageListEntry> list() { 227 return list; 228 } 229 230 public List<PackageListEntry> versions() { 231 return versions; 232 } 233 234 public PackageListEntry ciBuild() { 235 return cibuild; 236 } 237 238 public String toJson() { 239 return JsonParser.compose(json, true); 240 } 241 242 public PackageListEntry newVersion(String version, String path, String status, String sequence, FhirPublication fhirVersion) { 243 JsonObject o = new JsonObject(); 244 PackageListEntry e = new PackageListEntry(o); 245 versions.add(0, e); 246 if (cibuild != null) { 247 json.getJsonArray("list").add(1, o); 248 list.add(1, e); 249 } else { 250 json.getJsonArray("list").add(0, o); 251 list.add(0, e); 252 } 253 e.init(version, path, status, sequence, fhirVersion); 254 return e; 255 } 256 257 public void init(String name, String canonical, String title, String category, String introduction) { 258 json.add("package-id", name); 259 json.add("canonical", canonical); 260 json.add("title", title); 261 json.add("category", category); 262 json.add("introduction", introduction); 263 264 } 265 266 public void addCIBuild(String version, String path, String desc, String status) { 267 if (cibuild != null) { 268 json.getJsonArray("list").remove(cibuild.json); 269 } 270 cibuild = new PackageListEntry(new JsonObject()); 271 cibuild.init(version, path, status, status, null); 272 json.getJsonArray("list").add(0, cibuild.json); 273 } 274 275 public PackageListEntry findByVersion(String version) { 276 for (PackageListEntry p : versions) { 277 if (version.equals(p.version())) { 278 return p; 279 } 280 } 281 return null; 282 } 283 284 public void save(String filepath) throws IOException { 285 TextFile.stringToFile(toJson(), filepath); 286 } 287 288 public String determineLocalPath(String url, String root) throws IOException { 289 if (canonical().startsWith(url+"/")) { 290 String tail = canonical().substring(url.length()+1); 291 return Utilities.path(root, tail); 292 } else { 293 return null; 294 } 295 } 296 297 public String title() { 298 return json.asString("title"); 299 } 300 301 public PackageListEntry current() { 302 for (PackageListEntry e : list) { 303 if (e.current() && !"ci-build".equals(e.status())) { 304 return e; 305 } 306 } 307 return null; 308 } 309 310 public String intro() { 311 return json.asString("introduction"); 312 } 313}