001package org.hl7.fhir.convertors.misc; 002 003import java.io.BufferedOutputStream; 004import java.io.ByteArrayOutputStream; 005import java.io.File; 006import java.io.FileInputStream; 007import java.io.IOException; 008import java.io.InputStream; 009import java.nio.charset.StandardCharsets; 010import java.util.ArrayList; 011import java.util.HashMap; 012import java.util.List; 013import java.util.Map; 014import java.util.UUID; 015import java.util.Map.Entry; 016 017import javax.annotation.Nonnull; 018 019import org.apache.commons.compress.archivers.tar.TarArchiveEntry; 020import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; 021import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; 022import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream; 023import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream; 024import org.hl7.fhir.convertors.advisors.impl.BaseAdvisor_30_40; 025import org.hl7.fhir.convertors.advisors.impl.BaseAdvisor_30_50; 026import org.hl7.fhir.convertors.factory.VersionConvertorFactory_10_30; 027import org.hl7.fhir.convertors.factory.VersionConvertorFactory_10_40; 028import org.hl7.fhir.convertors.factory.VersionConvertorFactory_10_50; 029import org.hl7.fhir.convertors.factory.VersionConvertorFactory_14_30; 030import org.hl7.fhir.convertors.factory.VersionConvertorFactory_14_40; 031import org.hl7.fhir.convertors.factory.VersionConvertorFactory_14_50; 032import org.hl7.fhir.convertors.factory.VersionConvertorFactory_30_40; 033import org.hl7.fhir.convertors.factory.VersionConvertorFactory_30_50; 034import org.hl7.fhir.convertors.factory.VersionConvertorFactory_40_50; 035import org.hl7.fhir.r5.model.Enumeration; 036import org.hl7.fhir.r5.model.Enumerations.FHIRVersion; 037import org.hl7.fhir.r5.model.Enumerations.FHIRVersionEnumFactory; 038import org.hl7.fhir.r5.model.ImplementationGuide; 039import org.hl7.fhir.r5.model.Resource; 040import org.hl7.fhir.r5.model.StructureDefinition; 041import org.hl7.fhir.utilities.TextFile; 042import org.hl7.fhir.utilities.Utilities; 043import org.hl7.fhir.utilities.VersionUtilities; 044import org.hl7.fhir.utilities.filesystem.ManagedFileAccess; 045import org.hl7.fhir.utilities.json.model.JsonArray; 046import org.hl7.fhir.utilities.json.model.JsonObject; 047import org.hl7.fhir.utilities.json.parser.JsonParser; 048import org.hl7.fhir.utilities.npm.NpmPackageIndexBuilder; 049 050public class NpmPackageVersionConverter { 051 052 private static final int BUFFER_SIZE = 1024; 053 054 private final String source; 055 private final String dest; 056 private final String version; 057 private final String vCode; 058 private final List<String> errors = new ArrayList<>(); 059 private String currentVersion; 060 061 private String packageId; 062 063 public NpmPackageVersionConverter(String source, String dest, String version, String packageId) { 064 super(); 065 this.source = source; 066 this.dest = dest; 067 this.vCode = version; 068 this.packageId = packageId; 069 this.version = VersionUtilities.versionFromCode(version); 070 } 071 072 public static void main(String[] args) throws IOException { 073 NpmPackageVersionConverter self = new NpmPackageVersionConverter(args[0], args[1], args[2], args[3]); 074 self.execute(); 075 System.out.println("Finished"); 076 for (String s : self.errors) { 077 System.out.println(s); 078 } 079 } 080 081 public List<String> getErrors() { 082 return errors; 083 } 084 085 public void execute() throws IOException { 086 Map<String, byte[]> content = loadContentMap(ManagedFileAccess.inStream(source)); 087 088 Map<String, byte[]> output = new HashMap<>(); 089 output.put("package/package.json", convertPackage(content.get("package/package.json"))); 090 output.put("package/other/spec.internals", convertSpec(content.get("package/other/spec.internals"))); 091 092 for (Entry<String, byte[]> e : content.entrySet()) { 093 if (!e.getKey().equals("package/package.json") && !e.getKey().equals("package/other/spec.internals") && !e.getKey().endsWith("ig-r4.json") && !e.getKey().endsWith("ig-r4.jsonX")) { 094 byte[] cnv = e.getValue(); 095 try { 096 JsonObject json = JsonParser.parseObject(e.getValue()); 097 if (json.has("resourceType")) { 098 cnv = convertResource(e.getKey(), e.getValue()); 099 } 100 } catch (Exception ex) { 101 } 102 if (cnv != null && cnv.length > 0) { 103 output.put(e.getKey(), cnv); 104 } 105 } 106 } 107 108 TarArchiveOutputStream tar; 109 ByteArrayOutputStream OutputStream; 110 BufferedOutputStream bufferedOutputStream; 111 GzipCompressorOutputStream gzipOutputStream; 112 113 OutputStream = new ByteArrayOutputStream(); 114 bufferedOutputStream = new BufferedOutputStream(OutputStream); 115 gzipOutputStream = new GzipCompressorOutputStream(bufferedOutputStream); 116 tar = new TarArchiveOutputStream(gzipOutputStream); 117 118 119 Map<String, NpmPackageIndexBuilder> indexers = new HashMap<>(); 120 for (Entry<String, byte[]> e : output.entrySet()) { 121 String n = e.getKey().substring(0, e.getKey().lastIndexOf("/")); 122 String s = e.getKey().substring(n.length() + 1); 123 byte[] b = e.getValue(); 124 NpmPackageIndexBuilder indexer = indexers.get(n); 125 if (indexer == null) { 126 indexer = new NpmPackageIndexBuilder(); 127 indexer.start(Utilities.path("[tmp]", "tmp-"+UUID.randomUUID().toString()+".db")); 128 indexers.put(n, indexer); 129 } 130 indexer.seeFile(s, b); 131 if (!s.equals(".index.json") && !s.equals("package.json") && !s.equals(".index.db")) { 132 TarArchiveEntry entry = new TarArchiveEntry(e.getKey()); 133 entry.setSize(b.length); 134 tar.putArchiveEntry(entry); 135 tar.write(b); 136 tar.closeArchiveEntry(); 137 } 138 } 139 for (Entry<String, NpmPackageIndexBuilder> e : indexers.entrySet()) { 140 byte[] cnt = e.getValue().build().getBytes(StandardCharsets.UTF_8); 141 TarArchiveEntry entry = new TarArchiveEntry(e.getKey() + "/.index.json"); 142 entry.setSize(cnt.length); 143 tar.putArchiveEntry(entry); 144 tar.write(cnt); 145 tar.closeArchiveEntry(); 146 cnt = TextFile.fileToBytes(e.getValue().getDbFilename()); 147 ManagedFileAccess.file(e.getValue().getDbFilename()).delete(); 148 entry = new TarArchiveEntry(e.getKey() + "/.index.db"); 149 entry.setSize(cnt.length); 150 tar.putArchiveEntry(entry); 151 tar.write(cnt); 152 tar.closeArchiveEntry(); 153 } 154 155 byte[] cnt = output.get("package/package.json"); 156 TarArchiveEntry entry = new TarArchiveEntry("package/package.json"); 157 entry.setSize(cnt.length); 158 tar.putArchiveEntry(entry); 159 tar.write(cnt); 160 tar.closeArchiveEntry(); 161 162 tar.finish(); 163 tar.close(); 164 gzipOutputStream.close(); 165 bufferedOutputStream.close(); 166 OutputStream.close(); 167 byte[] b = OutputStream.toByteArray(); 168 TextFile.bytesToFile(b, dest); 169 } 170 171 @Nonnull 172 protected Map<String, byte[]> loadContentMap(InputStream inputStream) throws IOException { 173 GzipCompressorInputStream gzipIn; 174 try { 175 gzipIn = new GzipCompressorInputStream(inputStream); 176 } catch (Exception e) { 177 throw new IOException("Error reading " + source + ": " + e.getMessage(), e); 178 } 179 Map<String, byte[]> content = new HashMap<>(); 180 181 try (TarArchiveInputStream tarIn = new TarArchiveInputStream(gzipIn)) { 182 TarArchiveEntry entry; 183 184 while ((entry = (TarArchiveEntry) tarIn.getNextEntry()) != null) { 185 String n = entry.getName(); 186 if (n.contains("..")) { 187 throw new RuntimeException("Entry with an illegal name: " + n); 188 } 189 if (!entry.isDirectory()) { 190 int count; 191 byte[] data = new byte[BUFFER_SIZE]; 192 ByteArrayOutputStream fos = new ByteArrayOutputStream(); 193 try (BufferedOutputStream dest = new BufferedOutputStream(fos, BUFFER_SIZE)) { 194 while ((count = tarIn.read(data, 0, BUFFER_SIZE)) != -1) { 195 dest.write(data, 0, count); 196 } 197 } 198 fos.close(); 199 content.put(n, fos.toByteArray()); 200 } 201 } 202 } 203 return content; 204 } 205 206 private byte[] convertPackage(byte[] cnt) throws IOException { 207 JsonObject json = JsonParser.parseObject(cnt); 208 currentVersion = json.getJsonArray("fhirVersions").get(0).asString(); 209 String name = json.asString("name"); 210 assert(packageId.equals(name + "." + vCode)); 211 json.remove("name"); 212 json.add("name", name + "." + vCode); 213 json.remove("fhirVersions"); 214 json.remove("dependencies"); 215 JsonArray fv = new JsonArray(); 216 json.add("fhirVersions", fv); 217 fv.add(version); 218 JsonObject dep = new JsonObject(); 219 json.add("dependencies", dep); 220 dep.add(VersionUtilities.packageForVersion(version), version); 221 return JsonParser.composeBytes(json); 222 } 223 224 private byte[] convertSpec(byte[] cnt) throws IOException { 225 JsonObject json = JsonParser.parseObject(cnt); 226 json.set("ig-version", version); 227 json.set("npm-name", packageId); 228 return JsonParser.composeBytes(json, true); 229 } 230 231 private byte[] convertResource(String n, byte[] cnt) { 232 try { 233 if (VersionUtilities.isR2Ver(currentVersion)) { 234 org.hl7.fhir.dstu2.model.Resource res = new org.hl7.fhir.dstu2.formats.JsonParser().parse(cnt); 235 convertResourceR2(res); 236 if (VersionUtilities.isR2Ver(version)) { 237 return new org.hl7.fhir.dstu2.formats.JsonParser().composeBytes(res); 238 } else if (VersionUtilities.isR2BVer(version)) { 239 return new org.hl7.fhir.dstu2016may.formats.JsonParser().composeBytes(VersionConvertorFactory_14_30.convertResource(VersionConvertorFactory_10_30.convertResource(res))); 240 } else if (VersionUtilities.isR3Ver(version)) { 241 return new org.hl7.fhir.dstu3.formats.JsonParser().composeBytes(VersionConvertorFactory_10_30.convertResource(res)); 242 } else if (VersionUtilities.isR4Ver(version) || VersionUtilities.isR4BVer(version)) { 243 return new org.hl7.fhir.r4.formats.JsonParser().composeBytes(VersionConvertorFactory_10_40.convertResource(res)); 244 } else if (VersionUtilities.isR5Plus(version)) { 245 return new org.hl7.fhir.r5.formats.JsonParser().composeBytes(VersionConvertorFactory_10_50.convertResource(res)); 246 } 247 } else if (VersionUtilities.isR2BVer(currentVersion)) { 248 org.hl7.fhir.dstu2016may.model.Resource res = new org.hl7.fhir.dstu2016may.formats.JsonParser().parse(cnt); 249 convertResourceR2B(res); 250 if (VersionUtilities.isR2Ver(version)) { 251 return new org.hl7.fhir.dstu2.formats.JsonParser().composeBytes(VersionConvertorFactory_10_30.convertResource(VersionConvertorFactory_14_30.convertResource(res))); 252 } else if (VersionUtilities.isR2BVer(version)) { 253 return new org.hl7.fhir.dstu2016may.formats.JsonParser().composeBytes(res); 254 } else if (VersionUtilities.isR3Ver(version)) { 255 return new org.hl7.fhir.dstu3.formats.JsonParser().composeBytes(VersionConvertorFactory_14_30.convertResource(res)); 256 } else if (VersionUtilities.isR4Ver(version) || VersionUtilities.isR4BVer(version)) { 257 return new org.hl7.fhir.r4.formats.JsonParser().composeBytes(VersionConvertorFactory_14_40.convertResource(res)); 258 } else if (VersionUtilities.isR5Plus(version)) { 259 return new org.hl7.fhir.r5.formats.JsonParser().composeBytes(VersionConvertorFactory_14_50.convertResource(res)); 260 } 261 } else if (VersionUtilities.isR3Ver(currentVersion)) { 262 org.hl7.fhir.dstu3.model.Resource res = new org.hl7.fhir.dstu3.formats.JsonParser().parse(cnt); 263 convertResourceR3(res); 264 if (VersionUtilities.isR2Ver(version)) { 265 return new org.hl7.fhir.dstu2.formats.JsonParser().composeBytes(VersionConvertorFactory_10_30.convertResource(res)); 266 } else if (VersionUtilities.isR2BVer(version)) { 267 return new org.hl7.fhir.dstu2016may.formats.JsonParser().composeBytes(VersionConvertorFactory_14_30.convertResource(res)); 268 } else if (VersionUtilities.isR3Ver(version)) { 269 return new org.hl7.fhir.dstu3.formats.JsonParser().composeBytes(res); 270 } else if (VersionUtilities.isR4Ver(version) || VersionUtilities.isR4BVer(version)) { 271 return new org.hl7.fhir.r4.formats.JsonParser().composeBytes(VersionConvertorFactory_30_40.convertResource(res)); 272 } else if (VersionUtilities.isR5Plus(version)) { 273 return new org.hl7.fhir.r5.formats.JsonParser().composeBytes(VersionConvertorFactory_30_50.convertResource(res)); 274 } 275 } else if (VersionUtilities.isR4Ver(currentVersion)) { 276 org.hl7.fhir.r4.model.Resource res = new org.hl7.fhir.r4.formats.JsonParser().parse(cnt); 277 convertResourceR4(res); 278 if (VersionUtilities.isR2Ver(version)) { 279 return new org.hl7.fhir.dstu2.formats.JsonParser().composeBytes(VersionConvertorFactory_10_40.convertResource(res, new PR2Handler())); 280 } else if (VersionUtilities.isR2BVer(version)) { 281 return new org.hl7.fhir.dstu2016may.formats.JsonParser().composeBytes(VersionConvertorFactory_14_40.convertResource(res)); 282 } else if (VersionUtilities.isR3Ver(version)) { 283 return new org.hl7.fhir.dstu3.formats.JsonParser().composeBytes(VersionConvertorFactory_30_40.convertResource(res, new BaseAdvisor_30_40(false))); 284 } else if (VersionUtilities.isR4Ver(version) || VersionUtilities.isR4BVer(version)) { 285 return new org.hl7.fhir.r4.formats.JsonParser().composeBytes(res); 286 } else if (VersionUtilities.isR5Plus(version)) { 287 return new org.hl7.fhir.r5.formats.JsonParser().composeBytes(VersionConvertorFactory_40_50.convertResource(res)); 288 } 289 } else if (VersionUtilities.isR4BVer(currentVersion)) { 290 org.hl7.fhir.r4.model.Resource res = new org.hl7.fhir.r4.formats.JsonParser().parse(cnt); 291 convertResourceR4B(res); 292 if (VersionUtilities.isR2Ver(version)) { 293 return new org.hl7.fhir.dstu2.formats.JsonParser().composeBytes(VersionConvertorFactory_10_40.convertResource(res, new PR2Handler())); 294 } else if (VersionUtilities.isR2BVer(version)) { 295 return new org.hl7.fhir.dstu2016may.formats.JsonParser().composeBytes(VersionConvertorFactory_14_40.convertResource(res)); 296 } else if (VersionUtilities.isR3Ver(version)) { 297 return new org.hl7.fhir.dstu3.formats.JsonParser().composeBytes(VersionConvertorFactory_30_40.convertResource(res, new BaseAdvisor_30_40(false))); 298 } else if (VersionUtilities.isR4Ver(version) || VersionUtilities.isR4BVer(version)) { 299 return new org.hl7.fhir.r4.formats.JsonParser().composeBytes(res); 300 } else if (VersionUtilities.isR5Plus(version)) { 301 return new org.hl7.fhir.r5.formats.JsonParser().composeBytes(VersionConvertorFactory_40_50.convertResource(res)); 302 } 303 } else if (VersionUtilities.isR5Plus(currentVersion)) { 304 org.hl7.fhir.r5.model.Resource res = new org.hl7.fhir.r5.formats.JsonParser().parse(cnt); 305 convertResourceR5(res); 306 if (VersionUtilities.isR2Ver(version)) { 307 return new org.hl7.fhir.dstu2.formats.JsonParser().composeBytes(VersionConvertorFactory_10_50.convertResource(res)); 308 } else if (VersionUtilities.isR2BVer(version)) { 309 return new org.hl7.fhir.dstu2016may.formats.JsonParser().composeBytes(VersionConvertorFactory_14_50.convertResource(res)); 310 } else if (VersionUtilities.isR3Ver(version)) { 311 return new org.hl7.fhir.dstu3.formats.JsonParser().composeBytes(VersionConvertorFactory_30_50.convertResource(res, new BaseAdvisor_30_50(false))); 312 } else if (VersionUtilities.isR4Ver(version) || VersionUtilities.isR4BVer(version)) { 313 return new org.hl7.fhir.r4.formats.JsonParser().composeBytes(VersionConvertorFactory_40_50.convertResource(res)); 314 } else if (VersionUtilities.isR5Plus(version)) { 315 return new org.hl7.fhir.r5.formats.JsonParser().composeBytes(res); 316 } 317 } 318 throw new Error("Unknown version " + currentVersion + " -> " + version); 319 } catch (Exception ex) { 320 errors.add("Error converting " + n + ": " + ex.getMessage()); 321 return null; 322 } 323 } 324 325 private void convertResourceR2(org.hl7.fhir.dstu2.model.Resource res) { 326 if (res instanceof org.hl7.fhir.dstu2.model.ImplementationGuide) { 327 org.hl7.fhir.dstu2.model.ImplementationGuide ig = (org.hl7.fhir.dstu2.model.ImplementationGuide) res; 328 ig.setFhirVersion(version); 329 } 330 if (res instanceof org.hl7.fhir.dstu2.model.StructureDefinition) { 331 org.hl7.fhir.dstu2.model.StructureDefinition sd = (org.hl7.fhir.dstu2.model.StructureDefinition) res; 332 sd.setFhirVersion(version); 333 } 334 } 335 336 private void convertResourceR2B(org.hl7.fhir.dstu2016may.model.Resource res) { 337 if (res instanceof org.hl7.fhir.dstu2016may.model.ImplementationGuide) { 338 org.hl7.fhir.dstu2016may.model.ImplementationGuide ig = (org.hl7.fhir.dstu2016may.model.ImplementationGuide) res; 339 ig.setFhirVersion(version); 340 } 341 if (res instanceof org.hl7.fhir.dstu2016may.model.StructureDefinition) { 342 org.hl7.fhir.dstu2016may.model.StructureDefinition sd = (org.hl7.fhir.dstu2016may.model.StructureDefinition) res; 343 sd.setFhirVersion(version); 344 } 345 } 346 347 private void convertResourceR3(org.hl7.fhir.dstu3.model.Resource res) { 348 if (res instanceof org.hl7.fhir.dstu3.model.ImplementationGuide) { 349 org.hl7.fhir.dstu3.model.ImplementationGuide ig = (org.hl7.fhir.dstu3.model.ImplementationGuide) res; 350 ig.setFhirVersion(version); 351 } 352 if (res instanceof org.hl7.fhir.dstu3.model.StructureDefinition) { 353 org.hl7.fhir.dstu3.model.StructureDefinition sd = (org.hl7.fhir.dstu3.model.StructureDefinition) res; 354 sd.setFhirVersion(version); 355 } 356 } 357 358 private void convertResourceR4(org.hl7.fhir.r4.model.Resource res) { 359 if (res instanceof org.hl7.fhir.r4.model.ImplementationGuide) { 360 org.hl7.fhir.r4.model.ImplementationGuide ig = (org.hl7.fhir.r4.model.ImplementationGuide) res; 361 ig.getFhirVersion().clear(); 362 ig.getFhirVersion().add(new org.hl7.fhir.r4.model.Enumeration<>(new org.hl7.fhir.r4.model.Enumerations.FHIRVersionEnumFactory(), version)); 363 ig.setPackageId(packageId); 364 } 365 if (res instanceof org.hl7.fhir.r4.model.StructureDefinition) { 366 org.hl7.fhir.r4.model.StructureDefinition sd = (org.hl7.fhir.r4.model.StructureDefinition) res; 367 sd.setFhirVersion(org.hl7.fhir.r4.model.Enumerations.FHIRVersion.fromCode(version)); 368 } 369 } 370 371 private void convertResourceR4B(org.hl7.fhir.r4.model.Resource res) { 372 if (res instanceof org.hl7.fhir.r4.model.ImplementationGuide) { 373 org.hl7.fhir.r4.model.ImplementationGuide ig = (org.hl7.fhir.r4.model.ImplementationGuide) res; 374 ig.getFhirVersion().clear(); 375 ig.getFhirVersion().add(new org.hl7.fhir.r4.model.Enumeration<>(new org.hl7.fhir.r4.model.Enumerations.FHIRVersionEnumFactory(), version)); 376 ig.setPackageId(packageId); 377 } 378 if (res instanceof org.hl7.fhir.r4.model.StructureDefinition) { 379 org.hl7.fhir.r4.model.StructureDefinition sd = (org.hl7.fhir.r4.model.StructureDefinition) res; 380 sd.setFhirVersion(org.hl7.fhir.r4.model.Enumerations.FHIRVersion.fromCode(version)); 381 } 382 } 383 384 385 private void convertResourceR5(Resource res) { 386 if (res instanceof ImplementationGuide) { 387 ImplementationGuide ig = (ImplementationGuide) res; 388 ig.getFhirVersion().clear(); 389 ig.getFhirVersion().add(new Enumeration<>(new FHIRVersionEnumFactory(), version)); 390 ig.setPackageId(packageId); 391 } 392 if (res instanceof StructureDefinition) { 393 StructureDefinition sd = (StructureDefinition) res; 394 sd.setFhirVersion(FHIRVersion.fromCode(version)); 395 } 396 } 397 398}